@rbxts/uiblox 0.2.0-alpha.23 → 0.2.0-alpha.25

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,4 +1,5 @@
1
1
  export { breakpointName, orientationName, resolveResponsive } from "./breakpoints";
2
2
  export { BreakpointName, OrientationName, Responsive } from "./breakpoints";
3
3
  export { useBreakpoints } from "./useBreakpoints";
4
+ export { clearViewportObservers, observeViewport } from "./viewportObserver";
4
5
  export { useReducedMotion } from "./useReducedMotion";
@@ -6,5 +6,8 @@ exports.breakpointName = _breakpoints.breakpointName
6
6
  exports.orientationName = _breakpoints.orientationName
7
7
  exports.resolveResponsive = _breakpoints.resolveResponsive
8
8
  exports.useBreakpoints = TS.import(script, script, "useBreakpoints").useBreakpoints
9
+ local _viewportObserver = TS.import(script, script, "viewportObserver")
10
+ exports.clearViewportObservers = _viewportObserver.clearViewportObservers
11
+ exports.observeViewport = _viewportObserver.observeViewport
9
12
  exports.useReducedMotion = TS.import(script, script, "useReducedMotion").useReducedMotion
10
13
  return exports
@@ -6,6 +6,7 @@ local useState = _react.useState
6
6
  local _breakpoints = TS.import(script, script.Parent, "breakpoints")
7
7
  local breakpointName = _breakpoints.breakpointName
8
8
  local orientationName = _breakpoints.orientationName
9
+ local observeViewport = TS.import(script, script.Parent, "viewportObserver").observeViewport
9
10
  local function useBreakpoints(host)
10
11
  local size, setSize = useState({
11
12
  width = 0,
@@ -15,17 +16,7 @@ local function useBreakpoints(host)
15
16
  if host == nil then
16
17
  return nil
17
18
  end
18
- local read = function()
19
- return setSize({
20
- width = host.AbsoluteSize.X,
21
- height = host.AbsoluteSize.Y,
22
- })
23
- end
24
- read()
25
- local connection = host:GetPropertyChangedSignal("AbsoluteSize"):Connect(read)
26
- return function()
27
- return connection:Disconnect()
28
- end
19
+ return observeViewport(host, setSize)
29
20
  end, { host })
30
21
  return {
31
22
  width = size.width,
@@ -0,0 +1,10 @@
1
+ type Size = {
2
+ width: number;
3
+ height: number;
4
+ };
5
+ type Listener = (size: Size) => void;
6
+ /** One AbsoluteSize connection per host; shared by all subscribers. */
7
+ export declare function observeViewport(host: GuiObject, listener: Listener): () => void;
8
+ /** Test helper — drop all host observers. */
9
+ export declare function clearViewportObservers(): void;
10
+ export {};
@@ -0,0 +1,75 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local hosts = {}
3
+ --* One AbsoluteSize connection per host; shared by all subscribers.
4
+ local function observeViewport(host, listener)
5
+ local _host = host
6
+ local entry = hosts[_host]
7
+ if entry == nil then
8
+ entry = {
9
+ listeners = {},
10
+ size = {
11
+ width = host.AbsoluteSize.X,
12
+ height = host.AbsoluteSize.Y,
13
+ },
14
+ }
15
+ local _host_1 = host
16
+ local _entry = entry
17
+ hosts[_host_1] = _entry
18
+ local read = function()
19
+ local _host_2 = host
20
+ local current = hosts[_host_2]
21
+ if current == nil then
22
+ return nil
23
+ end
24
+ current.size = {
25
+ width = host.AbsoluteSize.X,
26
+ height = host.AbsoluteSize.Y,
27
+ }
28
+ for _, cb in current.listeners do
29
+ cb(current.size)
30
+ end
31
+ end
32
+ read()
33
+ entry.connection = host:GetPropertyChangedSignal("AbsoluteSize"):Connect(read)
34
+ end
35
+ local _listeners = entry.listeners
36
+ local _listener = listener
37
+ table.insert(_listeners, _listener)
38
+ listener(entry.size)
39
+ return function()
40
+ local _host_1 = host
41
+ local current = hosts[_host_1]
42
+ if current == nil then
43
+ return nil
44
+ end
45
+ local _listeners_1 = current.listeners
46
+ local _listener_1 = listener
47
+ local index = (table.find(_listeners_1, _listener_1) or 0) - 1
48
+ if index >= 0 then
49
+ table.remove(current.listeners, index + 1)
50
+ end
51
+ if #current.listeners == 0 then
52
+ local _result = current.connection
53
+ if _result ~= nil then
54
+ _result:Disconnect()
55
+ end
56
+ local _host_2 = host
57
+ hosts[_host_2] = nil
58
+ end
59
+ end
60
+ end
61
+ --* Test helper — drop all host observers.
62
+ local function clearViewportObservers()
63
+ for _, entry in hosts do
64
+ local _result = entry.connection
65
+ if _result ~= nil then
66
+ _result:Disconnect()
67
+ end
68
+ table.clear(entry.listeners)
69
+ end
70
+ table.clear(hosts)
71
+ end
72
+ return {
73
+ observeViewport = observeViewport,
74
+ clearViewportObservers = clearViewportObservers,
75
+ }
@@ -21,6 +21,21 @@ interface Theme {
21
21
  styleOverrides?: {
22
22
  [slot: string]: object;
23
23
  };
24
+ variants?: {
25
+ [prop: string]: {
26
+ [value: string]: {
27
+ [slot: string]: object;
28
+ };
29
+ };
30
+ };
31
+ compoundVariants?: Array<{
32
+ when: {
33
+ [prop: string]: unknown;
34
+ };
35
+ styles: {
36
+ [slot: string]: object;
37
+ };
38
+ }>;
24
39
  };
25
40
  };
26
41
  }
@@ -4,6 +4,7 @@ local _componentTheme = TS.import(script, script.Parent, "componentTheme")
4
4
  local propsWithDefaults = _componentTheme.propsWithDefaults
5
5
  local slotsWithOverrides = _componentTheme.slotsWithOverrides
6
6
  local makeStyles = TS.import(script, script.Parent, "makeStyles").default
7
+ local applyVariants = TS.import(script, script.Parent, "variants").applyVariants
7
8
  local componentStyles = function(name, factory)
8
9
  return makeStyles((function(theme, props)
9
10
  local _spec = theme.components
@@ -17,12 +18,53 @@ local componentStyles = function(name, factory)
17
18
  end
18
19
  local merged = propsWithDefaults(_result, props)
19
20
  local paint = factory
20
- local _exp = paint(theme, merged)
21
+ local slots = paint(theme, merged)
21
22
  local _result_1 = spec
22
23
  if _result_1 ~= nil then
23
- _result_1 = _result_1.styleOverrides
24
+ _result_1 = _result_1.variants
24
25
  end
25
- return slotsWithOverrides(_exp, _result_1)
26
+ local _condition = _result_1 ~= nil
27
+ if not _condition then
28
+ local _result_2 = spec
29
+ if _result_2 ~= nil then
30
+ _result_2 = _result_2.compoundVariants
31
+ if _result_2 ~= nil then
32
+ _result_2 = #_result_2
33
+ end
34
+ end
35
+ local _condition_1 = _result_2
36
+ if _condition_1 == nil then
37
+ _condition_1 = 0
38
+ end
39
+ _condition = _condition_1 > 0
40
+ end
41
+ if _condition then
42
+ local _exp = slots
43
+ local _exp_1 = merged
44
+ local _result_2 = spec
45
+ if _result_2 ~= nil then
46
+ _result_2 = _result_2.variants
47
+ end
48
+ local _condition_1 = _result_2
49
+ if _condition_1 == nil then
50
+ _condition_1 = {}
51
+ end
52
+ local _result_3 = spec
53
+ if _result_3 ~= nil then
54
+ _result_3 = _result_3.compoundVariants
55
+ end
56
+ local _condition_2 = _result_3
57
+ if _condition_2 == nil then
58
+ _condition_2 = {}
59
+ end
60
+ slots = applyVariants(_exp, _exp_1, _condition_1, _condition_2)
61
+ end
62
+ local _exp = slots
63
+ local _result_2 = spec
64
+ if _result_2 ~= nil then
65
+ _result_2 = _result_2.styleOverrides
66
+ end
67
+ return slotsWithOverrides(_exp, _result_2)
26
68
  end))
27
69
  end
28
70
  local default = componentStyles
@@ -5,6 +5,21 @@ export interface ComponentSpec {
5
5
  styleOverrides?: {
6
6
  [slot: string]: object;
7
7
  };
8
+ variants?: {
9
+ [prop: string]: {
10
+ [value: string]: {
11
+ [slot: string]: object;
12
+ };
13
+ };
14
+ };
15
+ compoundVariants?: Array<{
16
+ when: {
17
+ [prop: string]: unknown;
18
+ };
19
+ styles: {
20
+ [slot: string]: object;
21
+ };
22
+ }>;
8
23
  }
9
24
  export declare function propsWithDefaults(defaults: {
10
25
  [key: string]: unknown;
@@ -4,4 +4,6 @@ export { default as classNames, cx } from "./classNames";
4
4
  export { applyVariants, CompoundVariant } from "./variants";
5
5
  export { default as componentStyles } from "./componentStyles";
6
6
  export { resolveResponsive, Responsive } from "../../../hooks/breakpoints";
7
+ export { clearStyleCaches, createStyleCache, styleDepsKey } from "./styleCache";
8
+ export { resolveSx, resolvePaletteToken, PaletteToken, ResolvedSx, SxColor, SxInput } from "./resolveSx";
7
9
  export { interactionStyle, InteractionSlots, InteractionState, resolveStyle, StyleSelectorKey, StyleState, StyleWithSelectors, } from "./resolveStyle";
@@ -9,6 +9,13 @@ exports.cx = _classNames.cx
9
9
  exports.applyVariants = TS.import(script, script, "variants").applyVariants
10
10
  exports.componentStyles = TS.import(script, script, "componentStyles").default
11
11
  exports.resolveResponsive = TS.import(script, script.Parent.Parent.Parent, "hooks", "breakpoints").resolveResponsive
12
+ local _styleCache = TS.import(script, script, "styleCache")
13
+ exports.clearStyleCaches = _styleCache.clearStyleCaches
14
+ exports.createStyleCache = _styleCache.createStyleCache
15
+ exports.styleDepsKey = _styleCache.styleDepsKey
16
+ local _resolveSx = TS.import(script, script, "resolveSx")
17
+ exports.resolveSx = _resolveSx.resolveSx
18
+ exports.resolvePaletteToken = _resolveSx.resolvePaletteToken
12
19
  local _resolveStyle = TS.import(script, script, "resolveStyle")
13
20
  exports.interactionStyle = _resolveStyle.interactionStyle
14
21
  exports.resolveStyle = _resolveStyle.resolveStyle
@@ -1,23 +1,31 @@
1
- export type StyleSelectorKey = "_hover" | "_pressed" | "_focus" | "_disabled" | "_selected" | "_checked" | "_first" | "_last";
1
+ export type StyleSelectorKey = "_hover" | "_pressed" | "_focus" | "_focusVisible" | "_disabled" | "_selected" | "_checked" | "_loading" | "_first" | "_last" | "_odd" | "_even";
2
2
  export interface StyleState {
3
3
  hover?: boolean;
4
4
  pressed?: boolean;
5
5
  focused?: boolean;
6
+ focusVisible?: boolean;
6
7
  disabled?: boolean;
7
8
  selected?: boolean;
8
9
  checked?: boolean;
10
+ loading?: boolean;
9
11
  first?: boolean;
10
12
  last?: boolean;
13
+ odd?: boolean;
14
+ even?: boolean;
11
15
  }
12
16
  export type StyleWithSelectors<T extends object = object> = T & {
13
17
  _hover?: Partial<T>;
14
18
  _pressed?: Partial<T>;
15
19
  _focus?: Partial<T>;
20
+ _focusVisible?: Partial<T>;
16
21
  _disabled?: Partial<T>;
17
22
  _selected?: Partial<T>;
18
23
  _checked?: Partial<T>;
24
+ _loading?: Partial<T>;
19
25
  _first?: Partial<T>;
20
26
  _last?: Partial<T>;
27
+ _odd?: Partial<T>;
28
+ _even?: Partial<T>;
21
29
  };
22
30
  export interface InteractionSlots<T extends object = object> {
23
31
  hover?: T;
@@ -26,7 +34,7 @@ export interface InteractionSlots<T extends object = object> {
26
34
  disabled?: T;
27
35
  }
28
36
  export type InteractionState = Pick<StyleState, "hover" | "pressed" | "focused" | "disabled">;
29
- /** Peels `_hover` / `_pressed` / `_focus` / … and merges active ones onto the Instance props. */
37
+ /** Peels selector keys and merges active ones onto the Instance props. */
30
38
  export declare function resolveStyle<T extends object>(style: StyleWithSelectors<T>, state?: StyleState): T;
31
39
  /** Prefer `resolveStyle` with `_hover` keys. Kept for existing call sites. */
32
40
  export declare function interactionStyle<T extends object>(base: T, slots: InteractionSlots<T>, state: InteractionState): T;
@@ -1,17 +1,21 @@
1
1
  -- Compiled with roblox-ts v3.0.0
2
- --* Order matters: later keys win. Structural first, then interaction; `_disabled` last.
3
- local SELECTORS = { { "_first", "first" }, { "_last", "last" }, { "_selected", "selected" }, { "_checked", "checked" }, { "_hover", "hover" }, { "_pressed", "pressed" }, { "_focus", "focused" }, { "_disabled", "disabled" } }
2
+ --* Order matters: later keys win. Structural → selection → interaction; `_disabled` last.
3
+ local SELECTORS = { { "_first", "first" }, { "_last", "last" }, { "_odd", "odd" }, { "_even", "even" }, { "_selected", "selected" }, { "_checked", "checked" }, { "_loading", "loading" }, { "_hover", "hover" }, { "_pressed", "pressed" }, { "_focus", "focused" }, { "_focusVisible", "focusVisible" }, { "_disabled", "disabled" } }
4
4
  local SELECTOR_FLAGS = {
5
5
  _hover = true,
6
6
  _pressed = true,
7
7
  _focus = true,
8
+ _focusVisible = true,
8
9
  _selected = true,
9
10
  _checked = true,
11
+ _loading = true,
10
12
  _first = true,
11
13
  _last = true,
14
+ _odd = true,
15
+ _even = true,
12
16
  _disabled = true,
13
17
  }
14
- --* Peels `_hover` / `_pressed` / `_focus` / … and merges active ones onto the Instance props.
18
+ --* Peels selector keys and merges active ones onto the Instance props.
15
19
  local function resolveStyle(style, state)
16
20
  if state == nil then
17
21
  state = {}
@@ -0,0 +1,110 @@
1
+ /** Dot-path into `theme.palette` (typed for common roles). */
2
+ export type PaletteToken = "surface.canvas" | "surface.paper" | "surface.elevated" | "surface.overlay" | "surface.input" | "primary.main" | "primary.on" | "primary.hover" | "primary.pressed" | "accent.main" | "accent.on" | "accent.hover" | "accent.pressed" | "text.primary" | "text.secondary" | "text.disabled" | "text.inverse" | "text.link" | "border" | "divider" | "focus" | "action.hover" | "action.pressed" | "action.selected" | "action.disabled" | "status.success.main" | "status.success.on" | "status.success.surface" | "status.success.border" | "status.warning.main" | "status.warning.on" | "status.warning.surface" | "status.warning.border" | "status.error.main" | "status.error.on" | "status.error.surface" | "status.error.border" | "status.info.main" | "status.info.on" | "status.info.surface" | "status.info.border" | "backdrop" | "shadow";
3
+ export declare function resolvePaletteToken(palette: object, token: PaletteToken | Color3): Color3;
4
+ /** Matches `hooks/breakpoints` thresholds. Kept local so Node style checks need no path aliases. */
5
+ type Responsive<T> = T | {
6
+ phone?: T;
7
+ tablet?: T;
8
+ desktop?: T;
9
+ };
10
+ type PadInput = number | {
11
+ x?: number;
12
+ y?: number;
13
+ top?: number;
14
+ right?: number;
15
+ bottom?: number;
16
+ left?: number;
17
+ };
18
+ interface SxTheme {
19
+ spacing: {
20
+ calc: (multiple: number) => number;
21
+ };
22
+ palette: object;
23
+ typography: {
24
+ fontFamilies: {
25
+ [family: string]: Enum.Font;
26
+ };
27
+ variants: {
28
+ [name: string]: {
29
+ size: number;
30
+ family: string;
31
+ };
32
+ };
33
+ };
34
+ }
35
+ export type SxColor = PaletteToken | Color3;
36
+ /** CSS-like shorthands + pass-through Instance props. No CSS string parser. */
37
+ export type SxInput = {
38
+ width?: Responsive<number | UDim | UDim2>;
39
+ height?: Responsive<number | UDim | UDim2>;
40
+ w?: Responsive<number | UDim | UDim2>;
41
+ h?: Responsive<number | UDim | UDim2>;
42
+ size?: Responsive<UDim2 | {
43
+ width?: number | UDim;
44
+ height?: number | UDim;
45
+ }>;
46
+ x?: Responsive<number | UDim>;
47
+ y?: Responsive<number | UDim>;
48
+ position?: Responsive<UDim2>;
49
+ pos?: Responsive<UDim2>;
50
+ anchor?: Responsive<Vector2 | number | [number, number]>;
51
+ p?: Responsive<number>;
52
+ px?: Responsive<number>;
53
+ py?: Responsive<number>;
54
+ pt?: Responsive<number>;
55
+ pr?: Responsive<number>;
56
+ pb?: Responsive<number>;
57
+ pl?: Responsive<number>;
58
+ padding?: Responsive<PadInput>;
59
+ gap?: Responsive<number>;
60
+ bgcolor?: Responsive<SxColor>;
61
+ bg?: Responsive<SxColor>;
62
+ backgroundColor?: Responsive<SxColor>;
63
+ color?: Responsive<SxColor>;
64
+ borderColor?: Responsive<SxColor>;
65
+ opacity?: Responsive<number>;
66
+ transparency?: Responsive<number>;
67
+ border?: Responsive<number>;
68
+ borderWidth?: Responsive<number>;
69
+ radius?: Responsive<number>;
70
+ typography?: Responsive<string>;
71
+ fontSize?: Responsive<number>;
72
+ font?: Responsive<Enum.Font | string>;
73
+ visible?: Responsive<boolean>;
74
+ zIndex?: Responsive<number>;
75
+ z?: Responsive<number>;
76
+ _hover?: SxInput;
77
+ _pressed?: SxInput;
78
+ _focus?: SxInput;
79
+ _focusVisible?: SxInput;
80
+ _disabled?: SxInput;
81
+ _selected?: SxInput;
82
+ _checked?: SxInput;
83
+ _loading?: SxInput;
84
+ _first?: SxInput;
85
+ _last?: SxInput;
86
+ _odd?: SxInput;
87
+ _even?: SxInput;
88
+ [key: string]: unknown;
89
+ };
90
+ export interface ResolvedSx {
91
+ root: {
92
+ [key: string]: unknown;
93
+ };
94
+ padding?: {
95
+ PaddingTop: UDim;
96
+ PaddingRight: UDim;
97
+ PaddingBottom: UDim;
98
+ PaddingLeft: UDim;
99
+ };
100
+ corner?: {
101
+ CornerRadius: UDim;
102
+ };
103
+ gap?: number;
104
+ }
105
+ /**
106
+ * Maps sx shorthands / tokens → Instance props (+ UIPadding / UICorner / gap helpers).
107
+ * Pass-through keys (BackgroundColor3, _hover, …) stay on `root` for `resolveStyle`.
108
+ */
109
+ export declare function resolveSx(theme: SxTheme, sx?: SxInput, width?: number): ResolvedSx;
110
+ export {};