@snailycfx/stylesheet 1.0.11 → 1.0.13

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.
@@ -1,14 +1,8 @@
1
1
  import type { LayoutNode } from "./node";
2
2
  export { createNode, updateNodeStyle, removeNode, markLayoutDirty, getRoot, findContainingBlockForAbsolute } from "./node";
3
3
  export type { LayoutNode } from "./node";
4
- /**
5
- * Marca el nodo como dirty y agenda un layout pass en el próximo frame.
6
- * Llama a esto cuando cambia un estilo o el tamaño de un contenedor.
7
- */
4
+ export declare function setEngineRoot(node: LayoutNode): void;
5
+ export declare function getEngineRoot(): LayoutNode | undefined;
8
6
  export declare function runLayout(node: LayoutNode): void;
9
- /**
10
- * Ejecuta el layout inmediatamente sin esperar al próximo frame.
11
- * Usar solo cuando necesitas los valores computados de forma síncrona.
12
- */
13
7
  export declare function runLayoutImmediate(node: LayoutNode): void;
14
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/engine/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAOxC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,EAAE,OAAO,EAAE,8BAA8B,EAAE,MAAM,QAAQ,CAAA;AAC1H,YAAY,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AA0BxC;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAGhD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAIzD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/engine/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAOxC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,EAAE,OAAO,EAAE,8BAA8B,EAAE,MAAM,QAAQ,CAAA;AAC1H,YAAY,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAMxC,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAEpD;AAED,wBAAgB,aAAa,IAAI,UAAU,GAAG,SAAS,CAEtD;AAmBD,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAGhD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAIzD"}
@@ -1,69 +1,46 @@
1
1
  -- Compiled with roblox-ts v3.0.0
2
2
  local TS = _G[script]
3
3
  local exports = {}
4
- local _node = TS.import(script, script, "node")
5
- local getRoot = _node.getRoot
6
- local markLayoutDirty = _node.markLayoutDirty
4
+ local markLayoutDirty = TS.import(script, script, "node").markLayoutDirty
7
5
  local computeFlexLayout = TS.import(script, script, "flex").computeFlexLayout
8
6
  local computeGridLayout = TS.import(script, script, "grid").computeGridLayout
9
7
  local computeAbsoluteLayout = TS.import(script, script, "absolute").computeAbsoluteLayout
10
8
  local resolvePixels = TS.import(script, script.Parent, "parse").resolvePixels
11
- local _node_1 = TS.import(script, script, "node")
12
- exports.createNode = _node_1.createNode
13
- exports.updateNodeStyle = _node_1.updateNodeStyle
14
- exports.removeNode = _node_1.removeNode
15
- exports.markLayoutDirty = _node_1.markLayoutDirty
16
- exports.getRoot = _node_1.getRoot
17
- exports.findContainingBlockForAbsolute = _node_1.findContainingBlockForAbsolute
9
+ local _node = TS.import(script, script, "node")
10
+ exports.createNode = _node.createNode
11
+ exports.updateNodeStyle = _node.updateNodeStyle
12
+ exports.removeNode = _node.removeNode
13
+ exports.markLayoutDirty = _node.markLayoutDirty
14
+ exports.getRoot = _node.getRoot
15
+ exports.findContainingBlockForAbsolute = _node.findContainingBlockForAbsolute
16
+ -- ── Raíz global del engine ────────────────────────────────────────────────────
17
+ local engineRoot
18
+ local function setEngineRoot(node)
19
+ engineRoot = node
20
+ end
21
+ local function getEngineRoot()
22
+ return engineRoot
23
+ end
18
24
  -- ── Batching ──────────────────────────────────────────────────────────────────
19
- -- Acumulamos nodos sucios y ejecutamos un único layout pass por frame
20
25
  local scheduled = false
21
- local pendingRoots = {}
22
26
  local runLayoutImmediate
23
- local function scheduleLayout(root)
24
- local _root = root
25
- pendingRoots[_root] = true
26
- if scheduled then
27
+ local function scheduleLayout()
28
+ if scheduled or not engineRoot then
27
29
  return nil
28
30
  end
29
31
  scheduled = true
30
- -- Diferir al siguiente Heartbeat para batching automático
31
32
  local RunService = game:GetService("RunService")
32
- local conn = RunService.Heartbeat:Once(function()
33
+ RunService.Heartbeat:Once(function()
33
34
  scheduled = false
34
- local _array = {}
35
- local _length = #_array
36
- for _v in pendingRoots do
37
- _length += 1
38
- _array[_length] = _v
39
- end
40
- local roots = _array
41
- table.clear(pendingRoots)
42
- for _, r in roots do
43
- if r.layoutDirty then
44
- runLayoutImmediate(r)
45
- end
35
+ if engineRoot and engineRoot.layoutDirty then
36
+ runLayoutImmediate(engineRoot)
46
37
  end
47
38
  end)
48
- local _ = conn
49
- local _1 = nil
50
39
  end
51
- --[[
52
- *
53
- * Marca el nodo como dirty y agenda un layout pass en el próximo frame.
54
- * Llama a esto cuando cambia un estilo o el tamaño de un contenedor.
55
-
56
- ]]
57
40
  local function runLayout(node)
58
41
  markLayoutDirty(node)
59
- scheduleLayout(getRoot(node))
42
+ scheduleLayout()
60
43
  end
61
- --[[
62
- *
63
- * Ejecuta el layout inmediatamente sin esperar al próximo frame.
64
- * Usar solo cuando necesitas los valores computados de forma síncrona.
65
-
66
- ]]
67
44
  local layoutNode
68
45
  function runLayoutImmediate(node)
69
46
  if not node.layoutDirty then
@@ -79,7 +56,6 @@ function layoutNode(node, containerWidth, containerHeight)
79
56
  return nil
80
57
  end
81
58
  local style = node.style
82
- -- Tamaño propio
83
59
  node.computedWidth = if style.width ~= nil then resolvePixels(style.width, containerWidth) else containerWidth
84
60
  node.computedHeight = if style.height ~= nil then resolvePixels(style.height, containerHeight) else containerHeight
85
61
  if #node.children == 0 then
@@ -87,7 +63,6 @@ function layoutNode(node, containerWidth, containerHeight)
87
63
  return nil
88
64
  end
89
65
  local display = style.display
90
- -- ── Layout de hijos en flujo ───────────────────────────────────────────────
91
66
  local childLayouts
92
67
  if display == "flex" then
93
68
  childLayouts = computeFlexLayout(node, node.computedWidth, node.computedHeight)
@@ -96,7 +71,7 @@ function layoutNode(node, containerWidth, containerHeight)
96
71
  else
97
72
  childLayouts = computeBlockLayout(node, node.computedWidth, node.computedHeight)
98
73
  end
99
- -- ── Escribir y recursión: in-flow ─────────────────────────────────────────
74
+ -- In-flow children
100
75
  for i = 0, #node.children - 1 do
101
76
  local child = node.children[i + 1]
102
77
  if child.style.position == "absolute" then
@@ -112,13 +87,12 @@ function layoutNode(node, containerWidth, containerHeight)
112
87
  child.computedWidth = layout.width
113
88
  child.computedHeight = layout.height
114
89
  writeLayout(child.instance, layout.x, layout.y, layout.width, layout.height)
115
- -- Solo recalcular hijos si el tamaño cambió
116
90
  if sizeChanged then
117
91
  child.layoutDirty = true
118
92
  end
119
93
  layoutNode(child, layout.width, layout.height)
120
94
  end
121
- -- ── Escribir y recursión: absolute ────────────────────────────────────────
95
+ -- Absolute children
122
96
  for _, child in node.children do
123
97
  if child.style.position ~= "absolute" then
124
98
  continue
@@ -138,7 +112,6 @@ function layoutNode(node, containerWidth, containerHeight)
138
112
  end
139
113
  node.layoutDirty = false
140
114
  end
141
- -- ── Block layout ──────────────────────────────────────────────────────────────
142
115
  function computeBlockLayout(node, containerWidth, containerHeight)
143
116
  local yOffset = 0
144
117
  local results = {}
@@ -164,7 +137,6 @@ function computeBlockLayout(node, containerWidth, containerHeight)
164
137
  end
165
138
  return results
166
139
  end
167
- -- ── Helpers ───────────────────────────────────────────────────────────────────
168
140
  function writeLayout(instance, x, y, w, h)
169
141
  instance.Position = UDim2.new(0, x, 0, y)
170
142
  instance.Size = UDim2.new(0, w, 0, h)
@@ -174,6 +146,8 @@ function reparentIfNeeded(node, containingBlock)
174
146
  node.instance.Parent = containingBlock.instance
175
147
  end
176
148
  end
149
+ exports.setEngineRoot = setEngineRoot
150
+ exports.getEngineRoot = getEngineRoot
177
151
  exports.runLayout = runLayout
178
152
  exports.runLayoutImmediate = runLayoutImmediate
179
153
  return exports
@@ -10,7 +10,7 @@ export type { MiscStyle } from "./types/style/misc";
10
10
  export { parseColor } from "./parse/color";
11
11
  export { parseUDim, parseUDim2, resolvePixels } from "./parse/udim";
12
12
  export { parseGridTemplate, resolveTrackSizes } from "./parse/grid";
13
- export { createNode, updateNodeStyle, removeNode, runLayout, runLayoutImmediate, markLayoutDirty, getRoot } from "./engine";
13
+ export { createNode, updateNodeStyle, removeNode, runLayout, runLayoutImmediate, markLayoutDirty, getRoot, setEngineRoot, getEngineRoot, findContainingBlockForAbsolute } from "./engine";
14
14
  export type { LayoutNode } from "./engine";
15
15
  export { writeVisual } from "./writer";
16
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC1F,YAAY,EAAE,YAAY,EAAE,MAAS,uBAAuB,CAAA;AAC5D,YAAY,EAAE,SAAS,EAAE,MAAY,oBAAoB,CAAA;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC/D,YAAY,EAAE,WAAW,EAAE,MAAU,sBAAsB,CAAA;AAC3D,YAAY,EAAE,SAAS,EAAE,MAAY,oBAAoB,CAAA;AACzD,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACnI,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACzE,YAAY,EAAE,SAAS,EAAE,MAAY,oBAAoB,CAAA;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAoC,eAAe,CAAA;AACxE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAU,cAAc,CAAA;AACvE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAU,cAAc,CAAA;AAEvE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,kBAAkB,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAC3H,YAAY,EAAE,UAAU,EAAE,MAA+B,UAAU,CAAA;AAEnE,OAAO,EAAE,WAAW,EAAE,MAAmC,UAAU,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC1F,YAAY,EAAE,YAAY,EAAE,MAAS,uBAAuB,CAAA;AAC5D,YAAY,EAAE,SAAS,EAAE,MAAY,oBAAoB,CAAA;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC/D,YAAY,EAAE,WAAW,EAAE,MAAU,sBAAsB,CAAA;AAC3D,YAAY,EAAE,SAAS,EAAE,MAAY,oBAAoB,CAAA;AACzD,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACnI,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACzE,YAAY,EAAE,SAAS,EAAE,MAAY,oBAAoB,CAAA;AAEzD,OAAO,EAAE,UAAU,EAAE,MAA4C,eAAe,CAAA;AAChF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAkB,cAAc,CAAA;AAC/E,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAkB,cAAc,CAAA;AAE/E,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,kBAAkB,EAAE,eAAe,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,8BAA8B,EAAE,MAAM,UAAU,CAAA;AACzL,YAAY,EAAE,UAAU,EAAE,MAAuC,UAAU,CAAA;AAE3E,OAAO,EAAE,WAAW,EAAE,MAA2C,UAAU,CAAA"}
@@ -17,5 +17,8 @@ exports.runLayout = _engine.runLayout
17
17
  exports.runLayoutImmediate = _engine.runLayoutImmediate
18
18
  exports.markLayoutDirty = _engine.markLayoutDirty
19
19
  exports.getRoot = _engine.getRoot
20
+ exports.setEngineRoot = _engine.setEngineRoot
21
+ exports.getEngineRoot = _engine.getEngineRoot
22
+ exports.findContainingBlockForAbsolute = _engine.findContainingBlockForAbsolute
20
23
  exports.writeVisual = TS.import(script, script, "writer").writeVisual
21
24
  return exports
@@ -1 +1 @@
1
- {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../../src/core/parse/color.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE1C,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAgBpD"}
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../../src/core/parse/color.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE1C,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAoBpD"}
@@ -14,7 +14,8 @@ local function parseColor(value)
14
14
  end
15
15
  local str = value
16
16
  local hex = (string.gsub(str, "#", ""))
17
- local expanded = if #hex == 3 then string.rep(string.sub(hex, 1, 1), 2) .. string.rep(string.sub(hex, 2, 2), 2) .. string.rep(string.sub(hex, 3, 3), 2) else hex
17
+ -- Expandir shorthand #rgb #rrggbb
18
+ local expanded = if #hex == 3 then string.rep(string.sub(hex, 1, 1), 2) .. string.rep(string.sub(hex, 2, 2), 2) .. string.rep(string.sub(hex, 3, 3), 2) elseif #hex == 8 then string.sub(hex, 1, 6) else hex
18
19
  return Color3.fromHex(expanded)
19
20
  end
20
21
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"udim.d.ts","sourceRoot":"","sources":["../../../src/core/parse/udim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzC,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAgBhD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,KAAK,CAI5D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAkB7E"}
1
+ {"version":3,"file":"udim.d.ts","sourceRoot":"","sources":["../../../src/core/parse/udim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAuBzC,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAYhD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,KAAK,CAI5D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAY7E"}
@@ -1,17 +1,47 @@
1
1
  -- Compiled with roblox-ts v3.0.0
2
+ --[[
3
+ *
4
+ * Extrae scale y offset de strings tipo "50%+16" o "50%-16"
5
+ * usando dos match separados para evitar problemas con LuaTuple.
6
+
7
+ ]]
8
+ local function parseMixed(str)
9
+ local scaleStr = (string.match(str, "^(%d+%.?%d*)%%[%+%-]"))
10
+ if scaleStr == nil then
11
+ return nil
12
+ end
13
+ local offsetStr = (string.match(str, "[%+%-](%d+%.?%d*)$"))
14
+ if offsetStr == nil then
15
+ return nil
16
+ end
17
+ local sign = (string.match(str, "%%(%+?%-?)%d"))
18
+ local scale = tonumber(scaleStr) / 100
19
+ local offset = tonumber(offsetStr) * (if sign == "-" then -1 else 1)
20
+ return {
21
+ scale = scale,
22
+ offset = offset,
23
+ }
24
+ end
25
+ local function parseScaleOnly(str)
26
+ local scaleStr = (string.match(str, "^(%d+%.?%d*)%%$"))
27
+ if scaleStr == nil then
28
+ return nil
29
+ end
30
+ return tonumber(scaleStr) / 100
31
+ end
2
32
  local function parseUDim(value)
3
33
  local _value = value
4
34
  if typeof(_value) == "number" then
5
35
  return UDim.new(0, value)
6
36
  end
7
37
  local str = value
8
- local mixed = { string.match(str, "^(%d+%.?%d*)%%([%+%-]%d+%.?%d*)$") }
38
+ local mixed = parseMixed(str)
9
39
  if mixed ~= nil then
10
- return UDim.new(tonumber(mixed[1]) / 100, tonumber(mixed[2]))
40
+ return UDim.new(mixed.scale, mixed.offset)
11
41
  end
12
- local scaleOnly = { string.match(str, "^(%d+%.?%d*)%%$") }
13
- if scaleOnly ~= nil then
14
- return UDim.new(tonumber(scaleOnly[1]) / 100, 0)
42
+ local scale = parseScaleOnly(str)
43
+ if scale ~= nil then
44
+ return UDim.new(scale, 0)
15
45
  end
16
46
  local _condition = tonumber(str)
17
47
  if _condition == nil then
@@ -30,15 +60,13 @@ local function resolvePixels(value, containerSize)
30
60
  return value
31
61
  end
32
62
  local str = value
33
- local mixed = { string.match(str, "^(%d+%.?%d*)%%([%+%-]%d+%.?%d*)$") }
63
+ local mixed = parseMixed(str)
34
64
  if mixed ~= nil then
35
- local scale = tonumber(mixed[1]) / 100
36
- local offset = tonumber(mixed[2])
37
- return containerSize * scale + offset
65
+ return containerSize * mixed.scale + mixed.offset
38
66
  end
39
- local scaleOnly = { string.match(str, "^(%d+%.?%d*)%%$") }
40
- if scaleOnly ~= nil then
41
- return containerSize * (tonumber(scaleOnly[1]) / 100)
67
+ local scale = parseScaleOnly(str)
68
+ if scale ~= nil then
69
+ return containerSize * scale
42
70
  end
43
71
  local _condition = tonumber(str)
44
72
  if _condition == nil then
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/elements/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwC,MAAM,cAAc,CAAA;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,SAAS,CAAA;AAUnD,UAAU,SAAS;IAClB,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,SAAS,CAAC,EAAE,QAAQ,CAAA;IACpB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,UAAU,gBAAiB,SAAQ,SAAS;IAC3C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB;AAwGD,wBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,CAAC,YAAY,CAgBxD;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,YAAY,CAmBjG;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,KAAK,CAAC,YAAY,CAwBtF;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAA;CAAE,GAAG,KAAK,CAAC,YAAY,CAwB3H;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,SAAS,GAAG;IACxC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,YAAY,CAAC,EAAE,OAAO,CAAA;CACtB,GAAG,KAAK,CAAC,YAAY,CAoBrB;AAED,wBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG;IACrC,eAAe,CAAC,EAAE,UAAU,GAAG,YAAY,CAAA;IAC3C,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC3B,GAAG,KAAK,CAAC,YAAY,CA4BrB;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,CAAC,YAAY,CAU3D;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,SAAS,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,YAAY,CAmBjH;AAGD,eAAO,MAAM,GAAG,YAAM,CAAA;AACtB,eAAO,MAAM,IAAI,aAAO,CAAA;AACxB,eAAO,MAAM,MAAM,eAAS,CAAA;AAC5B,eAAO,MAAM,GAAG,YAAM,CAAA;AACtB,eAAO,MAAM,KAAK,cAAQ,CAAA;AAC1B,eAAO,MAAM,EAAE,WAAK,CAAA;AACpB,eAAO,MAAM,MAAM,eAAS,CAAA;AAC5B,eAAO,MAAM,KAAK,cAAQ,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/elements/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwC,MAAM,cAAc,CAAA;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,SAAS,CAAA;AAOnD,UAAU,SAAS;IAClB,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,SAAS,CAAC,EAAE,QAAQ,CAAA;IACpB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,UAAU,gBAAiB,SAAQ,SAAS;IAC3C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB;AAkFD,wBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,CAAC,YAAY,CAgBxD;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,YAAY,CAmBjG;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,KAAK,CAAC,YAAY,CAwBtF;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAA;CAAE,GAAG,KAAK,CAAC,YAAY,CAwB3H;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,SAAS,GAAG;IACxC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,YAAY,CAAC,EAAE,OAAO,CAAA;CACtB,GAAG,KAAK,CAAC,YAAY,CAoBrB;AAED,wBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG;IACrC,eAAe,CAAC,EAAE,UAAU,GAAG,YAAY,CAAA;IAC3C,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC3B,GAAG,KAAK,CAAC,YAAY,CA4BrB;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,CAAC,YAAY,CAgB3D;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,SAAS,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,YAAY,CAmBjH;AAGD,eAAO,MAAM,GAAG,YAAM,CAAA;AACtB,eAAO,MAAM,IAAI,aAAO,CAAA;AACxB,eAAO,MAAM,MAAM,eAAS,CAAA;AAC5B,eAAO,MAAM,GAAG,YAAM,CAAA;AACtB,eAAO,MAAM,KAAK,cAAQ,CAAA;AAC1B,eAAO,MAAM,EAAE,WAAK,CAAA;AACpB,eAAO,MAAM,MAAM,eAAS,CAAA;AAC5B,eAAO,MAAM,KAAK,cAAQ,CAAA"}
@@ -11,17 +11,14 @@ local updateNodeStyle = _core.updateNodeStyle
11
11
  local removeNode = _core.removeNode
12
12
  local runLayout = _core.runLayout
13
13
  local writeVisual = _core.writeVisual
14
- local getRoot = _core.getRoot
15
14
  local StyleSheet = TS.import(script, script.Parent, "stylesheet").StyleSheet
16
- -- ── Context ───────────────────────────────────────────────────────────────────
17
- local NodeContext = React.createContext(nil)
15
+ local NodeContext = TS.import(script, script.Parent, "provider").NodeContext
18
16
  -- ── Tipos ─────────────────────────────────────────────────────────────────────
19
17
  -- ── Hook central ──────────────────────────────────────────────────────────────
20
18
  local function useLayoutNode(ref, style, className, disabled)
21
19
  local parentNode = useContext(NodeContext)
22
20
  local nodeRef = useRef()
23
21
  local prevStyleRef = useRef()
24
- -- Fusión de estilos — solo recalcular si alguno de los dos cambió
25
22
  local base = StyleSheet:compose(className, style)
26
23
  local activeStyle = if disabled and base[":disabled"] then StyleSheet:withPseudo(base, ":disabled") else base
27
24
  useEffect(function()
@@ -29,25 +26,12 @@ local function useLayoutNode(ref, style, className, disabled)
29
26
  if not instance then
30
27
  return nil
31
28
  end
32
- -- Primer montaje — esperar a que la instancia tenga AbsoluteSize real
33
29
  local node = createNode(instance, activeStyle, parentNode)
34
30
  nodeRef.current = node
35
31
  prevStyleRef.current = activeStyle
36
32
  writeVisual(instance, activeStyle)
37
- -- Si ya tiene tamaño, layout inmediato. Si no, esperar al primer resize
38
- local doFirstLayout = function()
39
- local size = instance.AbsoluteSize
40
- if size.X > 0 or size.Y > 0 then
41
- runLayout(getRoot(node))
42
- end
43
- end
44
- doFirstLayout()
45
- local sizeConn = instance:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
46
- doFirstLayout()
47
- runLayout(getRoot(node))
48
- end)
49
- -- Pseudo-estado :hover
50
- local connections = { sizeConn }
33
+ runLayout(node)
34
+ local connections = {}
51
35
  if base[":hover"] then
52
36
  local hoverStyle = StyleSheet:withPseudo(base, ":hover")
53
37
  local _arg0 = instance.MouseEnter:Connect(function()
@@ -64,7 +48,6 @@ local function useLayoutNode(ref, style, className, disabled)
64
48
  table.insert(connections, _arg1)
65
49
  -- ▲ Array.push ▲
66
50
  end
67
- -- Pseudo-estado :active
68
51
  if base[":active"] then
69
52
  local activeStateStyle = StyleSheet:withPseudo(base, ":active")
70
53
  local btn = instance
@@ -93,11 +76,10 @@ local function useLayoutNode(ref, style, className, disabled)
93
76
  -- ▲ ReadonlyArray.forEach ▲
94
77
  removeNode(node)
95
78
  if parentNode then
96
- runLayout(getRoot(parentNode))
79
+ runLayout(parentNode)
97
80
  end
98
81
  end
99
82
  end, {})
100
- -- Actualizar estilo cuando cambia
101
83
  useEffect(function()
102
84
  local node = nodeRef.current
103
85
  if not node then
@@ -110,7 +92,7 @@ local function useLayoutNode(ref, style, className, disabled)
110
92
  updateNodeStyle(node, activeStyle)
111
93
  writeVisual(node.instance, activeStyle, prev)
112
94
  prevStyleRef.current = activeStyle
113
- runLayout(getRoot(node))
95
+ runLayout(node)
114
96
  end, { activeStyle })
115
97
  return nodeRef.current
116
98
  end
@@ -317,7 +299,7 @@ local function video(props)
317
299
  value = node,
318
300
  }, React.createElement("videoframe", _attributes, props.children))
319
301
  end
320
- -- Aliases PascalCase para uso como JSX components
302
+ -- PascalCase aliases para uso como JSX components
321
303
  local Div = div
322
304
  local Span = span
323
305
  local Button = button
package/out/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { StyleSheet } from "./stylesheet";
2
+ export { StyleSheetProvider } from "./provider";
2
3
  export * as elements from "./elements";
3
4
  export type { RbxStyle, RbxStyleBase } from "./core";
4
5
  export type { UDimValue, ColorValue, GradientStop } from "./core";
@@ -6,6 +7,6 @@ export type { SpacingStyle, SizeStyle, BackgroundStyle } from "./core";
6
7
  export type { BorderStyle, TextStyle } from "./core";
7
8
  export type { LayoutStyle, Display, FlexDirection, JustifyContent, AlignItems, AlignContent, FlexWrap } from "./core";
8
9
  export type { PositionStyle, PositionType, MiscStyle } from "./core";
9
- export { writeVisual, runLayout, runLayoutImmediate, markLayoutDirty, getRoot, createNode, updateNodeStyle, removeNode, parseColor, parseUDim, parseUDim2 } from "./core";
10
+ export { writeVisual, runLayout, runLayoutImmediate, markLayoutDirty, getRoot, setEngineRoot, createNode, updateNodeStyle, removeNode, parseColor, parseUDim, parseUDim2 } from "./core";
10
11
  export type { LayoutNode } from "./core";
11
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAS,cAAc,CAAA;AAC5C,OAAO,KAAK,QAAQ,MAAU,YAAY,CAAA;AAE1C,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAA+B,QAAQ,CAAA;AAC7E,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAkB,QAAQ,CAAA;AAC7E,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAa,QAAQ,CAAA;AAC7E,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAA+B,QAAQ,CAAA;AAC7E,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACrH,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAe,QAAQ,CAAA;AAG7E,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,kBAAkB,EAAE,eAAe,EAAE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACzK,YAAY,EAAE,UAAU,EAAE,MAA4C,QAAQ,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAiB,cAAc,CAAA;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAS,YAAY,CAAA;AAClD,OAAO,KAAK,QAAQ,MAAkB,YAAY,CAAA;AAElD,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAA+B,QAAQ,CAAA;AAC7E,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAkB,QAAQ,CAAA;AAC7E,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAa,QAAQ,CAAA;AAC7E,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAA+B,QAAQ,CAAA;AAC7E,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACrH,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAe,QAAQ,CAAA;AAG7E,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,kBAAkB,EAAE,eAAe,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACxL,YAAY,EAAE,UAAU,EAAE,MAA4C,QAAQ,CAAA"}
package/out/init.luau CHANGED
@@ -2,14 +2,16 @@
2
2
  local TS = _G[script]
3
3
  local exports = {}
4
4
  exports.StyleSheet = TS.import(script, script, "stylesheet").StyleSheet
5
+ exports.StyleSheetProvider = TS.import(script, script, "provider").StyleSheetProvider
5
6
  exports.elements = TS.import(script, script, "elements")
6
- -- API avanzada para extensión del paquete
7
+ -- API avanzada
7
8
  local _core = TS.import(script, script, "core")
8
9
  exports.writeVisual = _core.writeVisual
9
10
  exports.runLayout = _core.runLayout
10
11
  exports.runLayoutImmediate = _core.runLayoutImmediate
11
12
  exports.markLayoutDirty = _core.markLayoutDirty
12
13
  exports.getRoot = _core.getRoot
14
+ exports.setEngineRoot = _core.setEngineRoot
13
15
  exports.createNode = _core.createNode
14
16
  exports.updateNodeStyle = _core.updateNodeStyle
15
17
  exports.removeNode = _core.removeNode
@@ -0,0 +1,22 @@
1
+ import React from "@rbxts/react";
2
+ import type { LayoutNode } from "../core";
3
+ export declare const NodeContext: React.Context<LayoutNode | undefined>;
4
+ interface StyleSheetProviderProps {
5
+ target: Frame;
6
+ children?: React.ReactNode;
7
+ }
8
+ /**
9
+ * Raíz del engine de layout. Debe envolver toda la UI.
10
+ * Crea un Frame invisible que ocupa el 100% del target
11
+ * y actúa como el "body" del que cuelgan todos los elementos.
12
+ *
13
+ * @example
14
+ * export = (target: Frame) => {
15
+ * const root = createRoot(target)
16
+ * root.render(<StyleSheetProvider target={target}><App /></StyleSheetProvider>)
17
+ * return () => root.unmount()
18
+ * }
19
+ */
20
+ export declare function StyleSheetProvider(props: StyleSheetProviderProps): React.ReactElement;
21
+ export {};
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/provider/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,cAAc,CAAA;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAKzC,eAAO,MAAM,WAAW,uCAAyD,CAAA;AAIjF,UAAU,uBAAuB;IAChC,MAAM,EAAE,KAAK,CAAA;IACb,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,KAAK,CAAC,YAAY,CAsDrF"}
@@ -0,0 +1,74 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
4
+ local React = _react
5
+ local useEffect = _react.useEffect
6
+ local useRef = _react.useRef
7
+ local _core = TS.import(script, script.Parent, "core")
8
+ local createNode = _core.createNode
9
+ local setEngineRoot = _core.setEngineRoot
10
+ local runLayoutImmediate = _core.runLayoutImmediate
11
+ -- ── Context ───────────────────────────────────────────────────────────────────
12
+ local NodeContext = React.createContext(nil)
13
+ -- ── StyleSheetProvider ────────────────────────────────────────────────────────
14
+ --[[
15
+ *
16
+ * Raíz del engine de layout. Debe envolver toda la UI.
17
+ * Crea un Frame invisible que ocupa el 100% del target
18
+ * y actúa como el "body" del que cuelgan todos los elementos.
19
+ *
20
+ * @example
21
+ * export = (target: Frame) => {
22
+ * const root = createRoot(target)
23
+ * root.render(<StyleSheetProvider target={target}><App /></StyleSheetProvider>)
24
+ * return () => root.unmount()
25
+ * }
26
+
27
+ ]]
28
+ local function StyleSheetProvider(props)
29
+ local bodyRef = useRef()
30
+ local rootNodeRef = useRef()
31
+ useEffect(function()
32
+ local body = bodyRef.current
33
+ if not body then
34
+ return nil
35
+ end
36
+ -- Crear el nodo raíz — sin padre, es la raíz del árbol
37
+ local rootNode = createNode(body, {
38
+ width = "100%",
39
+ height = "100%",
40
+ display = "flex",
41
+ flexDirection = "column",
42
+ })
43
+ rootNodeRef.current = rootNode
44
+ setEngineRoot(rootNode)
45
+ -- Ejecutar layout inmediato con el tamaño real del target
46
+ local doLayout = function()
47
+ local size = props.target.AbsoluteSize
48
+ body.Size = UDim2.fromOffset(size.X, size.Y)
49
+ rootNode.computedWidth = size.X
50
+ rootNode.computedHeight = size.Y
51
+ rootNode.layoutDirty = true
52
+ runLayoutImmediate(rootNode)
53
+ end
54
+ doLayout()
55
+ -- Escuchar resize del target — un solo listener para todo el árbol
56
+ local conn = (props.target):GetPropertyChangedSignal("AbsoluteSize"):Connect(doLayout)
57
+ return function()
58
+ conn:Disconnect()
59
+ setEngineRoot(nil)
60
+ end
61
+ end, {})
62
+ return React.createElement(NodeContext.Provider, {
63
+ value = rootNodeRef.current,
64
+ }, React.createElement("frame", {
65
+ ref = bodyRef,
66
+ Size = UDim2.fromScale(1, 1),
67
+ BackgroundTransparency = 1,
68
+ BorderSizePixel = 0,
69
+ }, props.children))
70
+ end
71
+ return {
72
+ StyleSheetProvider = StyleSheetProvider,
73
+ NodeContext = NodeContext,
74
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snailycfx/stylesheet",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "CSS-inspired StyleSheet system for roblox-ts and @rbxts/react",
5
5
  "main": "out/init.lua",
6
6
  "types": "out/index.d.ts",