@rbxts/uiblox 0.2.0-alpha.34 → 0.2.0-alpha.36

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.
@@ -11,6 +11,7 @@ export * from "./layout/index";
11
11
  export * from "./preloader/index";
12
12
  export * from "./progressBar/index";
13
13
  export * from "./scroll/index";
14
+ export * from "./reorder/index";
14
15
  export * from "./shadow/index";
15
16
  export * from "./sidebar/index";
16
17
  export * from "./toast/index";
@@ -40,6 +40,9 @@ end
40
40
  for _k, _v in TS.import(script, script, "scroll") or {} do
41
41
  exports[_k] = _v
42
42
  end
43
+ for _k, _v in TS.import(script, script, "reorder") or {} do
44
+ exports[_k] = _v
45
+ end
43
46
  for _k, _v in TS.import(script, script, "shadow") or {} do
44
47
  exports[_k] = _v
45
48
  end
@@ -0,0 +1,2 @@
1
+ export { DragRect, hitRect, isReorderMove, isReorderPress, isReorderRelease, passedDragThreshold, placeItem, REORDER_THRESHOLD, transferId } from "./reorder";
2
+ export { ReorderDragHandle, ReorderDragState, useReorderDrag } from "./useReorderDrag";
@@ -0,0 +1,14 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local exports = {}
4
+ local _reorder = TS.import(script, script, "reorder")
5
+ exports.hitRect = _reorder.hitRect
6
+ exports.isReorderMove = _reorder.isReorderMove
7
+ exports.isReorderPress = _reorder.isReorderPress
8
+ exports.isReorderRelease = _reorder.isReorderRelease
9
+ exports.passedDragThreshold = _reorder.passedDragThreshold
10
+ exports.placeItem = _reorder.placeItem
11
+ exports.REORDER_THRESHOLD = _reorder.REORDER_THRESHOLD
12
+ exports.transferId = _reorder.transferId
13
+ exports.useReorderDrag = TS.import(script, script, "useReorderDrag").useReorderDrag
14
+ return exports
@@ -0,0 +1,24 @@
1
+ export declare const REORDER_THRESHOLD = 6;
2
+ export interface DragRect {
3
+ id: string;
4
+ x: number;
5
+ y: number;
6
+ width: number;
7
+ height: number;
8
+ }
9
+ export declare function isReorderPress(kind: Enum.UserInputType): boolean;
10
+ export declare function isReorderMove(kind: Enum.UserInputType): boolean;
11
+ export declare function isReorderRelease(kind: Enum.UserInputType): boolean;
12
+ export declare function passedDragThreshold(startX: number, startY: number, x: number, y: number, threshold?: number): boolean;
13
+ /** Smallest rect containing the point wins, so a card beats the column behind it. */
14
+ export declare function hitRect(rects: readonly DragRect[], x: number, y: number): string | undefined;
15
+ /** Final index after the move. Out-of-range or a no-op returns a copy. */
16
+ export declare function placeItem<T extends defined>(items: readonly T[], from: number, to: number): T[];
17
+ /**
18
+ * Insert `id` at `index` in `dest` and remove it from `source`.
19
+ * The same list uses placeItem, where index is the final index.
20
+ */
21
+ export declare function transferId(source: readonly string[], dest: readonly string[], id: string, index: number): {
22
+ source: string[];
23
+ dest: string[];
24
+ };
@@ -0,0 +1,178 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local REORDER_THRESHOLD = 6
3
+ local function isReorderPress(kind)
4
+ return kind == Enum.UserInputType.MouseButton1 or kind == Enum.UserInputType.Touch
5
+ end
6
+ local function isReorderMove(kind)
7
+ return kind == Enum.UserInputType.MouseMovement or kind == Enum.UserInputType.Touch
8
+ end
9
+ local function isReorderRelease(kind)
10
+ return kind == Enum.UserInputType.MouseButton1 or kind == Enum.UserInputType.Touch
11
+ end
12
+ local function passedDragThreshold(startX, startY, x, y, threshold)
13
+ if threshold == nil then
14
+ threshold = REORDER_THRESHOLD
15
+ end
16
+ local dx = x - startX
17
+ local dy = y - startY
18
+ return dx * dx + dy * dy >= threshold * threshold
19
+ end
20
+ --* Smallest rect containing the point wins, so a card beats the column behind it.
21
+ local function hitRect(rects, x, y)
22
+ local best
23
+ local bestArea = math.huge
24
+ for _, rect in rects do
25
+ if x < rect.x or y < rect.y or x > rect.x + rect.width or y > rect.y + rect.height then
26
+ continue
27
+ end
28
+ local area = rect.width * rect.height
29
+ if area < bestArea then
30
+ best = rect
31
+ bestArea = area
32
+ end
33
+ end
34
+ local _result = best
35
+ if _result ~= nil then
36
+ _result = _result.id
37
+ end
38
+ return _result
39
+ end
40
+ --* Final index after the move. Out-of-range or a no-op returns a copy.
41
+ local function placeItem(items, from, to)
42
+ local listed = {}
43
+ for _, item in items do
44
+ table.insert(listed, item)
45
+ end
46
+ local count = #listed
47
+ if from < 0 or to < 0 or from >= count or to >= count or from == to then
48
+ return listed
49
+ end
50
+ local moved = listed[from + 1]
51
+ if from < to then
52
+ do
53
+ local index = from
54
+ local _shouldIncrement = false
55
+ while true do
56
+ if _shouldIncrement then
57
+ index += 1
58
+ else
59
+ _shouldIncrement = true
60
+ end
61
+ if not (index < to) then
62
+ break
63
+ end
64
+ listed[index + 1] = listed[index + 2]
65
+ end
66
+ end
67
+ else
68
+ do
69
+ local index = from
70
+ local _shouldIncrement = false
71
+ while true do
72
+ if _shouldIncrement then
73
+ index -= 1
74
+ else
75
+ _shouldIncrement = true
76
+ end
77
+ if not (index > to) then
78
+ break
79
+ end
80
+ listed[index + 1] = listed[index]
81
+ end
82
+ end
83
+ end
84
+ listed[to + 1] = moved
85
+ return listed
86
+ end
87
+ local function indexOfId(ids, id)
88
+ for index = 0, #ids - 1 do
89
+ if ids[index + 1] == id then
90
+ return index
91
+ end
92
+ end
93
+ return -1
94
+ end
95
+ --[[
96
+ *
97
+ * Insert `id` at `index` in `dest` and remove it from `source`.
98
+ * The same list uses placeItem, where index is the final index.
99
+
100
+ ]]
101
+ local function transferId(source, dest, id, index)
102
+ if source == dest then
103
+ local placed = placeItem(source, indexOfId(source, id), math.clamp(index, 0, math.max(0, #source - 1)))
104
+ return {
105
+ source = placed,
106
+ dest = placed,
107
+ }
108
+ end
109
+ local nextSource = {}
110
+ local found = false
111
+ for _, item in source do
112
+ if item == id then
113
+ found = true
114
+ else
115
+ table.insert(nextSource, item)
116
+ end
117
+ end
118
+ local nextDest = {}
119
+ for _, item in dest do
120
+ table.insert(nextDest, item)
121
+ end
122
+ if not found then
123
+ return {
124
+ source = nextSource,
125
+ dest = nextDest,
126
+ }
127
+ end
128
+ local at = math.clamp(math.floor(index), 0, #nextDest)
129
+ local inserted = {}
130
+ do
131
+ local cursor = 0
132
+ local _shouldIncrement = false
133
+ while true do
134
+ if _shouldIncrement then
135
+ cursor += 1
136
+ else
137
+ _shouldIncrement = true
138
+ end
139
+ if not (cursor < at) then
140
+ break
141
+ end
142
+ local _arg0 = nextDest[cursor + 1]
143
+ table.insert(inserted, _arg0)
144
+ end
145
+ end
146
+ local _id = id
147
+ table.insert(inserted, _id)
148
+ do
149
+ local cursor = at
150
+ local _shouldIncrement = false
151
+ while true do
152
+ if _shouldIncrement then
153
+ cursor += 1
154
+ else
155
+ _shouldIncrement = true
156
+ end
157
+ if not (cursor < #nextDest) then
158
+ break
159
+ end
160
+ local _arg0 = nextDest[cursor + 1]
161
+ table.insert(inserted, _arg0)
162
+ end
163
+ end
164
+ return {
165
+ source = nextSource,
166
+ dest = inserted,
167
+ }
168
+ end
169
+ return {
170
+ isReorderPress = isReorderPress,
171
+ isReorderMove = isReorderMove,
172
+ isReorderRelease = isReorderRelease,
173
+ passedDragThreshold = passedDragThreshold,
174
+ hitRect = hitRect,
175
+ placeItem = placeItem,
176
+ transferId = transferId,
177
+ REORDER_THRESHOLD = REORDER_THRESHOLD,
178
+ }
@@ -0,0 +1,15 @@
1
+ import { DragRect } from "./reorder";
2
+ export interface ReorderDragState {
3
+ active: boolean;
4
+ id?: string;
5
+ overId?: string;
6
+ x: number;
7
+ y: number;
8
+ }
9
+ export interface ReorderDragHandle {
10
+ drag: ReorderDragState;
11
+ begin: (id: string, input: InputObject) => boolean;
12
+ cancel: () => void;
13
+ suppressClick: () => boolean;
14
+ }
15
+ export declare function useReorderDrag(onDrop: (fromId: string, overId?: string) => void, getRects: () => readonly DragRect[]): ReorderDragHandle;
@@ -0,0 +1,129 @@
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 useEffect = _react.useEffect
5
+ local useRef = _react.useRef
6
+ local useState = _react.useState
7
+ local UserInputService = TS.import(script, TS.getModule(script, "@rbxts", "services")).UserInputService
8
+ local _reorder = TS.import(script, script.Parent, "reorder")
9
+ local hitRect = _reorder.hitRect
10
+ local isReorderMove = _reorder.isReorderMove
11
+ local isReorderPress = _reorder.isReorderPress
12
+ local isReorderRelease = _reorder.isReorderRelease
13
+ local passedDragThreshold = _reorder.passedDragThreshold
14
+ local rest = function()
15
+ return {
16
+ active = false,
17
+ x = 0,
18
+ y = 0,
19
+ }
20
+ end
21
+ local function useReorderDrag(onDrop, getRects)
22
+ local drag, setDrag = useState(rest())
23
+ local tracking = useRef({
24
+ down = false,
25
+ active = false,
26
+ x = 0,
27
+ y = 0,
28
+ startX = 0,
29
+ startY = 0,
30
+ })
31
+ local onDropRef = useRef(onDrop)
32
+ local rectsRef = useRef(getRects)
33
+ local took = useRef(false)
34
+ onDropRef.current = onDrop
35
+ rectsRef.current = getRects
36
+ local clear = function(drop)
37
+ local current = tracking.current
38
+ tracking.current = {
39
+ down = false,
40
+ active = false,
41
+ x = 0,
42
+ y = 0,
43
+ startX = 0,
44
+ startY = 0,
45
+ }
46
+ setDrag(rest())
47
+ if drop and current.active and current.id ~= nil then
48
+ took.current = true
49
+ onDropRef.current(current.id, current.overId)
50
+ end
51
+ end
52
+ useEffect(function()
53
+ local changed = UserInputService.InputChanged:Connect(function(input)
54
+ local current = tracking.current
55
+ if not current.down or not isReorderMove(input.UserInputType) then
56
+ return nil
57
+ end
58
+ local x = input.Position.X
59
+ local y = input.Position.Y
60
+ local active = current.active or passedDragThreshold(current.startX, current.startY, x, y)
61
+ local overId = if active then hitRect(rectsRef.current(), x, y) else nil
62
+ local _object = table.clone(current)
63
+ setmetatable(_object, nil)
64
+ _object.active = active
65
+ _object.x = x
66
+ _object.y = y
67
+ _object.overId = overId
68
+ tracking.current = _object
69
+ if active then
70
+ setDrag({
71
+ active = true,
72
+ id = current.id,
73
+ overId = overId,
74
+ x = x,
75
+ y = y,
76
+ })
77
+ end
78
+ end)
79
+ local ended = UserInputService.InputEnded:Connect(function(input)
80
+ if not tracking.current.down or not isReorderRelease(input.UserInputType) then
81
+ return nil
82
+ end
83
+ clear(true)
84
+ end)
85
+ local began = UserInputService.InputBegan:Connect(function(input)
86
+ if input.KeyCode == Enum.KeyCode.Escape then
87
+ clear(false)
88
+ end
89
+ end)
90
+ return function()
91
+ changed:Disconnect()
92
+ ended:Disconnect()
93
+ began:Disconnect()
94
+ end
95
+ end, {})
96
+ return {
97
+ drag = drag,
98
+ begin = function(id, input)
99
+ if not isReorderPress(input.UserInputType) then
100
+ return false
101
+ end
102
+ local x = input.Position.X
103
+ local y = input.Position.Y
104
+ tracking.current = {
105
+ down = true,
106
+ active = false,
107
+ id = id,
108
+ x = x,
109
+ y = y,
110
+ startX = x,
111
+ startY = y,
112
+ }
113
+ return true
114
+ end,
115
+ cancel = function()
116
+ return clear(false)
117
+ end,
118
+ suppressClick = function()
119
+ if not took.current then
120
+ return false
121
+ end
122
+ took.current = false
123
+ return true
124
+ end,
125
+ }
126
+ end
127
+ return {
128
+ useReorderDrag = useReorderDrag,
129
+ }
@@ -1,9 +1,22 @@
1
+ import React from "@rbxts/react";
1
2
  import { CustomizedProps } from "../../../../theme/index";
3
+ import { TableAlign, TableSortDirection } from "./tableColumns";
4
+ export interface TableColumn {
5
+ header: string | React.ReactNode;
6
+ width?: number | UDim;
7
+ flex?: number;
8
+ align?: TableAlign;
9
+ sortable?: boolean;
10
+ }
11
+ export type TableCell = string | React.ReactNode;
2
12
  export interface TableProps {
3
- columns: string[];
4
- rows: string[][];
13
+ columns: Array<string | TableColumn>;
14
+ rows: Array<Array<TableCell>>;
5
15
  selected?: number;
6
16
  dense?: boolean;
17
+ sortColumn?: number;
18
+ sortDirection?: TableSortDirection;
19
+ onSort?: (column: number) => void;
7
20
  onRowActivated?: (index: number) => void;
8
21
  }
9
22
  declare function Table(props: CustomizedProps<Frame, TableProps>): JSX.Element;
@@ -2,15 +2,33 @@
2
2
  local TS = _G[script]
3
3
  local React = TS.import(script, TS.getModule(script, "@rbxts", "react"))
4
4
  local cx = TS.import(script, script.Parent.Parent.Parent.Parent.Parent, "theme").cx
5
- local rowSelected = TS.import(script, script.Parent, "rowSelected").rowSelected
6
5
  local SxHost = TS.import(script, script.Parent.Parent.Parent, "host").SxHost
6
+ local rowSelected = TS.import(script, script.Parent, "rowSelected").rowSelected
7
+ local _tableColumns = TS.import(script, script.Parent, "tableColumns")
8
+ local canSort = _tableColumns.canSort
9
+ local columnSizes = _tableColumns.columnSizes
10
+ local headerText = _tableColumns.headerText
11
+ local isTextCell = _tableColumns.isTextCell
12
+ local resolveColumn = _tableColumns.resolveColumn
7
13
  local useTableStyles = TS.import(script, script.Parent, "Table.styles").default
14
+ local function textAlign(align)
15
+ if align == "center" then
16
+ return Enum.TextXAlignment.Center
17
+ end
18
+ if align == "right" then
19
+ return Enum.TextXAlignment.Right
20
+ end
21
+ return Enum.TextXAlignment.Left
22
+ end
8
23
  local function Table(props)
9
24
  local _binding = props
10
25
  local columns = _binding.columns
11
26
  local rows = _binding.rows
12
27
  local selected = _binding.selected
13
28
  local dense = _binding.dense
29
+ local sortColumn = _binding.sortColumn
30
+ local sortDirection = _binding.sortDirection
31
+ local onSort = _binding.onSort
14
32
  local onRowActivated = _binding.onRowActivated
15
33
  local className = _binding.className
16
34
  local sx = _binding.sx
@@ -19,7 +37,17 @@ local function Table(props)
19
37
  local styles = useTableStyles({
20
38
  dense = dense,
21
39
  })
22
- local width = if #columns > 0 then 1 / #columns else 1
40
+ -- ▼ ReadonlyArray.map ▼
41
+ local _newValue = table.create(#columns)
42
+ local _callback = function(column)
43
+ return resolveColumn(column)
44
+ end
45
+ for _k, _v in columns do
46
+ _newValue[_k] = _callback(_v, _k - 1, columns)
47
+ end
48
+ -- ▲ ReadonlyArray.map ▲
49
+ local resolved = _newValue
50
+ local sizes = columnSizes(resolved)
23
51
  local _attributes = {
24
52
  tag = "frame",
25
53
  }
@@ -52,27 +80,72 @@ local function Table(props)
52
80
  setmetatable(_attributes_5, nil)
53
81
  local _exp_3 = React.createElement("uilistlayout", _attributes_5)
54
82
  -- ▼ ReadonlyArray.map ▼
55
- local _newValue = table.create(#columns)
56
- local _callback = function(label, index)
57
- local _attributes_6 = {
58
- key = `h-{label}-{index}`,
59
- }
60
- for _k, _v in cx(styles.cell, styles.headerCell) do
61
- _attributes_6[_k] = _v
83
+ local _newValue_1 = table.create(#resolved)
84
+ local _callback_1 = function(column, index)
85
+ local size = sizes[index + 1]
86
+ local box = UDim2.new(size.scale, size.offset, 0, 0)
87
+ local align = textAlign(column.align)
88
+ local active = sortColumn == index and column.sortable
89
+ local _header = column.header
90
+ local label = if type(_header) == "string" then headerText(column.header, active, sortDirection) else nil
91
+ local clickable = canSort(column.sortable, onSort ~= nil)
92
+ if clickable then
93
+ local _attributes_6 = {
94
+ key = `h-{index}`,
95
+ }
96
+ for _k, _v in (cx(styles.cell, styles.headerCell)) do
97
+ _attributes_6[_k] = _v
98
+ end
99
+ local _condition_1 = label
100
+ if _condition_1 == nil then
101
+ _condition_1 = ""
102
+ end
103
+ _attributes_6.Text = _condition_1
104
+ _attributes_6.Size = box
105
+ _attributes_6.TextXAlignment = align
106
+ _attributes_6.AutoButtonColor = false
107
+ _attributes_6.LayoutOrder = index
108
+ _attributes_6.Event = {
109
+ Activated = function()
110
+ local _result = onSort
111
+ if _result ~= nil then
112
+ _result = _result(index)
113
+ end
114
+ return _result
115
+ end,
116
+ }
117
+ return React.createElement("textbutton", _attributes_6, label == nil and (column.header))
62
118
  end
63
- _attributes_6.Text = label
64
- _attributes_6.Size = UDim2.new(width, 0, 0, 0)
65
- _attributes_6.LayoutOrder = index
66
- return React.createElement("textlabel", _attributes_6)
119
+ if label ~= nil then
120
+ local _attributes_6 = {
121
+ key = `h-{index}`,
122
+ }
123
+ for _k, _v in cx(styles.cell, styles.headerCell) do
124
+ _attributes_6[_k] = _v
125
+ end
126
+ _attributes_6.Text = label
127
+ _attributes_6.Size = box
128
+ _attributes_6.TextXAlignment = align
129
+ _attributes_6.LayoutOrder = index
130
+ return React.createElement("textlabel", _attributes_6)
131
+ end
132
+ return React.createElement("frame", {
133
+ key = `h-{index}`,
134
+ Size = box,
135
+ AutomaticSize = Enum.AutomaticSize.Y,
136
+ BackgroundTransparency = 1,
137
+ BorderSizePixel = 0,
138
+ LayoutOrder = index,
139
+ }, column.header)
67
140
  end
68
- for _k, _v in columns do
69
- _newValue[_k] = _callback(_v, _k - 1, columns)
141
+ for _k, _v in resolved do
142
+ _newValue_1[_k] = _callback_1(_v, _k - 1, resolved)
70
143
  end
71
144
  -- ▲ ReadonlyArray.map ▲
72
- local _exp_4 = React.createElement("frame", _attributes_3, _exp_2, _exp_3, React.createElement(React.Fragment, nil, _newValue))
145
+ local _exp_4 = React.createElement("frame", _attributes_3, _exp_2, _exp_3, React.createElement(React.Fragment, nil, _newValue_1))
73
146
  -- ▼ ReadonlyArray.map ▼
74
- local _newValue_1 = table.create(#rows)
75
- local _callback_1 = function(cells, rowIndex)
147
+ local _newValue_2 = table.create(#rows)
148
+ local _callback_2 = function(cells, rowIndex)
76
149
  local _attributes_6 = {
77
150
  key = `r-{rowIndex}`,
78
151
  }
@@ -96,34 +169,48 @@ local function Table(props)
96
169
  setmetatable(_attributes_8, nil)
97
170
  local _exp_6 = React.createElement("uilistlayout", _attributes_8)
98
171
  -- ▼ ReadonlyArray.map ▼
99
- local _newValue_2 = table.create(#columns)
100
- local _callback_2 = function(_, colIndex)
101
- local _attributes_9 = {
102
- key = `c-{rowIndex}-{colIndex}`,
103
- }
104
- for _k, _v in styles.cell do
105
- _attributes_9[_k] = _v
106
- end
107
- local _condition_1 = cells[colIndex + 1]
108
- if _condition_1 == nil then
109
- _condition_1 = ""
172
+ local _newValue_3 = table.create(#resolved)
173
+ local _callback_3 = function(column, colIndex)
174
+ local size = sizes[colIndex + 1]
175
+ local box = UDim2.new(size.scale, size.offset, 0, 0)
176
+ local value = cells[colIndex + 1]
177
+ if isTextCell(value) then
178
+ local _attributes_9 = {
179
+ key = `c-{rowIndex}-{colIndex}`,
180
+ }
181
+ for _k, _v in styles.cell do
182
+ _attributes_9[_k] = _v
183
+ end
184
+ local _condition_1 = value
185
+ if _condition_1 == nil then
186
+ _condition_1 = ""
187
+ end
188
+ _attributes_9.Text = _condition_1
189
+ _attributes_9.Size = box
190
+ _attributes_9.TextXAlignment = textAlign(column.align)
191
+ _attributes_9.LayoutOrder = colIndex
192
+ return React.createElement("textlabel", _attributes_9)
110
193
  end
111
- _attributes_9.Text = _condition_1
112
- _attributes_9.Size = UDim2.new(width, 0, 0, 0)
113
- _attributes_9.LayoutOrder = colIndex
114
- return React.createElement("textlabel", _attributes_9)
194
+ return React.createElement("frame", {
195
+ key = `c-{rowIndex}-{colIndex}`,
196
+ Size = box,
197
+ AutomaticSize = Enum.AutomaticSize.Y,
198
+ BackgroundTransparency = 1,
199
+ BorderSizePixel = 0,
200
+ LayoutOrder = colIndex,
201
+ }, value)
115
202
  end
116
- for _k, _v in columns do
117
- _newValue_2[_k] = _callback_2(_v, _k - 1, columns)
203
+ for _k, _v in resolved do
204
+ _newValue_3[_k] = _callback_3(_v, _k - 1, resolved)
118
205
  end
119
206
  -- ▲ ReadonlyArray.map ▲
120
- return React.createElement("textbutton", _attributes_6, _exp_5, _exp_6, React.createElement(React.Fragment, nil, _newValue_2))
207
+ return React.createElement("textbutton", _attributes_6, _exp_5, _exp_6, React.createElement(React.Fragment, nil, _newValue_3))
121
208
  end
122
209
  for _k, _v in rows do
123
- _newValue_1[_k] = _callback_1(_v, _k - 1, rows)
210
+ _newValue_2[_k] = _callback_2(_v, _k - 1, rows)
124
211
  end
125
212
  -- ▲ ReadonlyArray.map ▲
126
- return React.createElement(SxHost, _attributes, _exp, _exp_1, _exp_4, React.createElement(React.Fragment, nil, _newValue_1))
213
+ return React.createElement(SxHost, _attributes, _exp, _exp_1, _exp_4, React.createElement(React.Fragment, nil, _newValue_2))
127
214
  end
128
215
  local default = Table
129
216
  return {
@@ -0,0 +1,26 @@
1
+ export type TableAlign = "left" | "center" | "right";
2
+ export type TableSortDirection = "asc" | "desc";
3
+ export interface TableColumnSpec {
4
+ header: unknown;
5
+ width?: number | UDim;
6
+ flex?: number;
7
+ align?: TableAlign;
8
+ sortable?: boolean;
9
+ }
10
+ export interface ResolvedColumn {
11
+ header: unknown;
12
+ width?: number | UDim;
13
+ flex?: number;
14
+ align: TableAlign;
15
+ sortable: boolean;
16
+ }
17
+ export interface ColumnSize {
18
+ scale: number;
19
+ offset: number;
20
+ }
21
+ export declare function resolveColumn(column: string | TableColumnSpec): ResolvedColumn;
22
+ /** Scale/offset for each column. Number widths are scales. Flex shares whatever scale is left. */
23
+ export declare function columnSizes(columns: ReadonlyArray<Pick<ResolvedColumn, "width" | "flex">>): ColumnSize[];
24
+ export declare function isTextCell(value: unknown): value is string | undefined;
25
+ export declare function canSort(sortable: boolean | undefined, hasHandler: boolean): boolean;
26
+ export declare function headerText(label: string, active: boolean, direction?: TableSortDirection): string;
@@ -0,0 +1,92 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local function resolveColumn(column)
3
+ local _column = column
4
+ if type(_column) == "string" then
5
+ return {
6
+ header = column,
7
+ align = "left",
8
+ sortable = false,
9
+ }
10
+ end
11
+ return {
12
+ header = column.header,
13
+ width = column.width,
14
+ flex = column.flex,
15
+ align = column.align or "left",
16
+ sortable = column.sortable == true,
17
+ }
18
+ end
19
+ --* Scale/offset for each column. Number widths are scales. Flex shares whatever scale is left.
20
+ local function columnSizes(columns)
21
+ local fixed = 0
22
+ local flexTotal = 0
23
+ for _, column in columns do
24
+ local width = column.width
25
+ if type(width) == "number" then
26
+ fixed += width
27
+ elseif width ~= nil then
28
+ fixed += width.Scale
29
+ else
30
+ local _condition = column.flex
31
+ if _condition == nil then
32
+ _condition = 1
33
+ end
34
+ flexTotal += _condition
35
+ end
36
+ end
37
+ local remain = math.max(0, 1 - fixed)
38
+ local sizes = {}
39
+ for _, column in columns do
40
+ local width = column.width
41
+ if type(width) == "number" then
42
+ local _arg0 = {
43
+ scale = width,
44
+ offset = 0,
45
+ }
46
+ table.insert(sizes, _arg0)
47
+ elseif width ~= nil then
48
+ local _arg0 = {
49
+ scale = width.Scale,
50
+ offset = width.Offset,
51
+ }
52
+ table.insert(sizes, _arg0)
53
+ else
54
+ local _condition = column.flex
55
+ if _condition == nil then
56
+ _condition = 1
57
+ end
58
+ local flex = _condition
59
+ local share = if flexTotal > 0 then (flex / flexTotal) * remain else 0
60
+ local _arg0 = {
61
+ scale = share,
62
+ offset = 0,
63
+ }
64
+ table.insert(sizes, _arg0)
65
+ end
66
+ end
67
+ return sizes
68
+ end
69
+ local function isTextCell(value)
70
+ local _value = value
71
+ local _condition = type(_value) == "string"
72
+ if not _condition then
73
+ _condition = value == nil
74
+ end
75
+ return _condition
76
+ end
77
+ local function canSort(sortable, hasHandler)
78
+ return sortable == true and hasHandler
79
+ end
80
+ local function headerText(label, active, direction)
81
+ if not active then
82
+ return label
83
+ end
84
+ return if direction == "desc" then `{label} ↓` else `{label} ↑`
85
+ end
86
+ return {
87
+ resolveColumn = resolveColumn,
88
+ columnSizes = columnSizes,
89
+ isTextCell = isTextCell,
90
+ canSort = canSort,
91
+ headerText = headerText,
92
+ }
@@ -1,2 +1,3 @@
1
1
  export { default as Table } from "./components/Table";
2
- export { TableProps } from "./components/Table";
2
+ export { TableProps, TableColumn, TableCell } from "./components/Table";
3
+ export { TableAlign, TableSortDirection } from "./components/tableColumns";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rbxts/uiblox",
3
- "version": "0.2.0-alpha.34",
3
+ "version": "0.2.0-alpha.36",
4
4
  "description": "UI Library and theming for roblox-ts projects",
5
5
  "main": "out/init.luau",
6
6
  "packageManager": "pnpm@11.3.0",
@@ -8,7 +8,7 @@
8
8
  "build": "rbxtsc",
9
9
  "watch": "rbxtsc -w",
10
10
  "pack:check": "node scripts/pack-check.mjs",
11
- "test": "node scripts/no-internal-refs.check.mjs && node scripts/import-case.check.mjs && node --experimental-strip-types scripts/theme-scope.check.mjs && node --experimental-strip-types scripts/style-types.check.mjs && node --experimental-strip-types scripts/style-cache.check.mjs && node --experimental-strip-types scripts/style-variants.check.mjs && node --experimental-strip-types scripts/component-styles.check.mjs && node --experimental-strip-types scripts/interaction-styles.check.mjs && node --experimental-strip-types scripts/resolve-style.check.mjs && node --experimental-strip-types scripts/resolve-sx.check.mjs && node --experimental-strip-types scripts/sx-prop.check.mjs && node --experimental-strip-types scripts/style-system.check.mjs && node --experimental-strip-types scripts/host-sx.check.mjs && node --experimental-strip-types scripts/density.check.mjs && node --experimental-strip-types scripts/styles.check.mjs && node --experimental-strip-types scripts/contrast.check.mjs && node --experimental-strip-types scripts/primitives.check.mjs && node scripts/state-matrix-registers.check.mjs && node --experimental-strip-types scripts/paper.check.mjs && node --experimental-strip-types scripts/list-item.check.mjs && node --experimental-strip-types scripts/slider.check.mjs && node --experimental-strip-types scripts/input.check.mjs && node --experimental-strip-types scripts/menu.check.mjs && node --experimental-strip-types scripts/guard.check.mjs && node --experimental-strip-types scripts/breakpoints.check.mjs && node --experimental-strip-types scripts/viewport-observer.check.mjs && node --experimental-strip-types scripts/focus-trap.check.mjs && node --experimental-strip-types scripts/select-typeahead.check.mjs && node --experimental-strip-types scripts/select-groups.check.mjs && node --experimental-strip-types scripts/select-multi.check.mjs && node --experimental-strip-types scripts/select-polish.check.mjs && node --experimental-strip-types scripts/reduced-motion.check.mjs && node --experimental-strip-types scripts/card.check.mjs && node --experimental-strip-types scripts/chip.check.mjs && node --experimental-strip-types scripts/badge.check.mjs && node --experimental-strip-types scripts/avatar.check.mjs && node --experimental-strip-types scripts/imageList.check.mjs && node --experimental-strip-types scripts/drawer.check.mjs && node --experimental-strip-types scripts/breadcrumbs.check.mjs && node --experimental-strip-types scripts/pagination.check.mjs && node --experimental-strip-types scripts/stepper.check.mjs && node --experimental-strip-types scripts/accordion.check.mjs && node --experimental-strip-types scripts/snackbar.check.mjs && node --experimental-strip-types scripts/table.check.mjs && node --experimental-strip-types scripts/autocomplete.check.mjs && node --experimental-strip-types scripts/field-loading.check.mjs && node --experimental-strip-types scripts/fab.check.mjs && node --experimental-strip-types scripts/appbar.check.mjs && node --experimental-strip-types scripts/bottom-navigation.check.mjs && node --experimental-strip-types scripts/alert.check.mjs && node --experimental-strip-types scripts/toggle-button.check.mjs && node --experimental-strip-types scripts/link.check.mjs && node --experimental-strip-types scripts/rating.check.mjs && node --experimental-strip-types scripts/stack.check.mjs && node --experimental-strip-types scripts/flex-item.check.mjs && node --experimental-strip-types scripts/grid.check.mjs && node --experimental-strip-types scripts/speed-dial.check.mjs && node --experimental-strip-types scripts/form-text.check.mjs && node --experimental-strip-types scripts/box.check.mjs && node --experimental-strip-types scripts/scroll-view.check.mjs && node --experimental-strip-types scripts/image-list.check.mjs && node --experimental-strip-types scripts/radio-group.check.mjs && node --experimental-strip-types scripts/container.check.mjs && node --experimental-strip-types scripts/divider.check.mjs && node --experimental-strip-types scripts/markdown.check.mjs && node --experimental-strip-types scripts/switch.check.mjs && node --experimental-strip-types scripts/tabs.check.mjs && node --experimental-strip-types scripts/dialog.check.mjs && node --experimental-strip-types scripts/backdrop.check.mjs && node --experimental-strip-types scripts/cframe-editor.check.mjs && node --experimental-strip-types scripts/enum-picker.check.mjs && node --experimental-strip-types scripts/number-range.check.mjs && node --experimental-strip-types scripts/date-range.check.mjs && node --experimental-strip-types scripts/sparkline.check.mjs && node --experimental-strip-types scripts/rect-editor.check.mjs && node --experimental-strip-types scripts/asset-field.check.mjs && node --experimental-strip-types scripts/gradient-editor.check.mjs && node --experimental-strip-types scripts/ray-editor.check.mjs && node --experimental-strip-types scripts/physical-properties.check.mjs && node --experimental-strip-types scripts/brickcolor-picker.check.mjs",
11
+ "test": "node scripts/no-internal-refs.check.mjs && node scripts/import-case.check.mjs && node --experimental-strip-types scripts/theme-scope.check.mjs && node --experimental-strip-types scripts/style-types.check.mjs && node --experimental-strip-types scripts/style-cache.check.mjs && node --experimental-strip-types scripts/style-variants.check.mjs && node --experimental-strip-types scripts/component-styles.check.mjs && node --experimental-strip-types scripts/interaction-styles.check.mjs && node --experimental-strip-types scripts/resolve-style.check.mjs && node --experimental-strip-types scripts/resolve-sx.check.mjs && node --experimental-strip-types scripts/sx-prop.check.mjs && node --experimental-strip-types scripts/style-system.check.mjs && node --experimental-strip-types scripts/host-sx.check.mjs && node --experimental-strip-types scripts/density.check.mjs && node --experimental-strip-types scripts/styles.check.mjs && node --experimental-strip-types scripts/contrast.check.mjs && node --experimental-strip-types scripts/primitives.check.mjs && node scripts/state-matrix-registers.check.mjs && node --experimental-strip-types scripts/paper.check.mjs && node --experimental-strip-types scripts/list-item.check.mjs && node --experimental-strip-types scripts/slider.check.mjs && node --experimental-strip-types scripts/input.check.mjs && node --experimental-strip-types scripts/menu.check.mjs && node --experimental-strip-types scripts/guard.check.mjs && node --experimental-strip-types scripts/breakpoints.check.mjs && node --experimental-strip-types scripts/viewport-observer.check.mjs && node --experimental-strip-types scripts/focus-trap.check.mjs && node --experimental-strip-types scripts/select-typeahead.check.mjs && node --experimental-strip-types scripts/select-groups.check.mjs && node --experimental-strip-types scripts/select-multi.check.mjs && node --experimental-strip-types scripts/select-polish.check.mjs && node --experimental-strip-types scripts/reduced-motion.check.mjs && node --experimental-strip-types scripts/card.check.mjs && node --experimental-strip-types scripts/chip.check.mjs && node --experimental-strip-types scripts/badge.check.mjs && node --experimental-strip-types scripts/avatar.check.mjs && node --experimental-strip-types scripts/imageList.check.mjs && node --experimental-strip-types scripts/drawer.check.mjs && node --experimental-strip-types scripts/breadcrumbs.check.mjs && node --experimental-strip-types scripts/pagination.check.mjs && node --experimental-strip-types scripts/stepper.check.mjs && node --experimental-strip-types scripts/accordion.check.mjs && node --experimental-strip-types scripts/snackbar.check.mjs && node --experimental-strip-types scripts/table.check.mjs && node --experimental-strip-types scripts/table-columns.check.mjs && node --experimental-strip-types scripts/reorder.check.mjs && node --experimental-strip-types scripts/autocomplete.check.mjs && node --experimental-strip-types scripts/field-loading.check.mjs && node --experimental-strip-types scripts/fab.check.mjs && node --experimental-strip-types scripts/appbar.check.mjs && node --experimental-strip-types scripts/bottom-navigation.check.mjs && node --experimental-strip-types scripts/alert.check.mjs && node --experimental-strip-types scripts/toggle-button.check.mjs && node --experimental-strip-types scripts/link.check.mjs && node --experimental-strip-types scripts/rating.check.mjs && node --experimental-strip-types scripts/stack.check.mjs && node --experimental-strip-types scripts/flex-item.check.mjs && node --experimental-strip-types scripts/grid.check.mjs && node --experimental-strip-types scripts/speed-dial.check.mjs && node --experimental-strip-types scripts/form-text.check.mjs && node --experimental-strip-types scripts/box.check.mjs && node --experimental-strip-types scripts/scroll-view.check.mjs && node --experimental-strip-types scripts/image-list.check.mjs && node --experimental-strip-types scripts/radio-group.check.mjs && node --experimental-strip-types scripts/container.check.mjs && node --experimental-strip-types scripts/divider.check.mjs && node --experimental-strip-types scripts/markdown.check.mjs && node --experimental-strip-types scripts/switch.check.mjs && node --experimental-strip-types scripts/tabs.check.mjs && node --experimental-strip-types scripts/dialog.check.mjs && node --experimental-strip-types scripts/backdrop.check.mjs && node --experimental-strip-types scripts/cframe-editor.check.mjs && node --experimental-strip-types scripts/enum-picker.check.mjs && node --experimental-strip-types scripts/number-range.check.mjs && node --experimental-strip-types scripts/date-range.check.mjs && node --experimental-strip-types scripts/sparkline.check.mjs && node --experimental-strip-types scripts/rect-editor.check.mjs && node --experimental-strip-types scripts/asset-field.check.mjs && node --experimental-strip-types scripts/gradient-editor.check.mjs && node --experimental-strip-types scripts/ray-editor.check.mjs && node --experimental-strip-types scripts/physical-properties.check.mjs && node --experimental-strip-types scripts/brickcolor-picker.check.mjs",
12
12
  "prepublishOnly": "pnpm build"
13
13
  },
14
14
  "keywords": [