diff --git a/src/Storybook/StorybookTreeView.luau b/src/Storybook/StorybookTreeView.luau index f500bc40..858a2fa8 100644 --- a/src/Storybook/StorybookTreeView.luau +++ b/src/Storybook/StorybookTreeView.luau @@ -1,11 +1,11 @@ local React = require("@pkg/React") +local Storyteller = require("@pkg/Storyteller") -local TreeView = require("@root/TreeView/Treeview") -local storybookTypes = require("@root/Storybook/types") +local TreeView = require("@root/TreeView/TreeView") local treeViewTypes = require("@root/TreeView/types") type TreeNode = treeViewTypes.TreeNode -type Storybook = storybookTypes.Storybook +type Storybook = Storyteller.Storybook local useMemo = React.useMemo @@ -21,7 +21,7 @@ local function StorybookTreeView(props: Props) local leafNodes = useMemo(function() local nodes: { TreeNode } = {} for _, storyModule in storyModules do - table.insert(nodes, {}) + -- table.insert(nodes, {}) end return nodes end, { storyModules }) diff --git a/src/TreeView/TreeNode.luau b/src/TreeView/TreeNode.luau index f9406de8..4fc378d8 100644 --- a/src/TreeView/TreeNode.luau +++ b/src/TreeView/TreeNode.luau @@ -1,58 +1,117 @@ local React = require("@pkg/React") +local Sprite = require("@root/Common/Sprite") local treeViewTypes = require("@root/TreeView/types") local useTheme = require("@root/Common/useTheme") +local assets = require("@root/assets") +local useCallback = React.useCallback local useMemo = React.useMemo type TreeNode = treeViewTypes.TreeNode export type Props = { node: TreeNode, + onActivated: (() -> ())?, + layoutOrder: number?, } local function TreeNode(props: Props) local theme = useTheme() local children = useMemo(function() + local elements: { [string]: React.Node } = {} if props.node.children then - local elements = {} - for _, child in props.node.children do + for index, child in props.node.children do elements[child.id] = React.createElement(TreeNode, { + layoutOrder = index, node = child, }) end - return elements end + return elements end, { props.node.children }) + local onActivated = useCallback(function() + if props.onActivated then + props.onActivated() + end + end, { props.onActivated }) + return React.createElement("ImageButton", { + LayoutOrder = props.layoutOrder, AutoButtonColor = false, - [React.Event.Activated] = function() - props.onActivated(props.node) - end, + AutomaticSize = Enum.AutomaticSize.XY, + BackgroundTransparency = 1, + [React.Event.Activated] = onActivated, }, { Layout = React.createElement("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, + Padding = theme.paddingSmall, }), Node = React.createElement("Frame", { LayoutOrder = 1, + AutomaticSize = Enum.AutomaticSize.XY, + BackgroundTransparency = 1, }, { - Icon = React.createElement("ImageLabel", {}), + Layout = React.createElement("UIListLayout", { + SortOrder = Enum.SortOrder.LayoutOrder, + FillDirection = Enum.FillDirection.Horizontal, + Padding = theme.paddingSmall, + HorizontalFlex = Enum.UIFlexAlignment.Fill, + }), + + Icon = React.createElement(Sprite, { + image = assets.Component, + color = theme.story, + layoutOrder = 1, + size = UDim2.fromOffset(16, 16), + }), Text = React.createElement("TextLabel", { + LayoutOrder = 2, Text = props.node.label, + AutomaticSize = Enum.AutomaticSize.Y, + BackgroundTransparency = 1, + Font = theme.font, + Size = UDim2.fromScale(1, 0), + TextXAlignment = Enum.TextXAlignment.Left, + TextColor3 = theme.text, + TextSize = theme.textSize, + }, { + Flex = React.createElement("UIFlexItem", { + FlexMode = Enum.UIFlexMode.Shrink, + }), }), - Toggle = React.createElement("ImageLabel", {}), + Toggle = if props.node.children + then React.createElement("ImageButton", { + LayoutOrder = 3, + BackgroundTransparency = 1, + Size = UDim2.fromOffset(16, 16), + }, { + Icon = React.createElement(Sprite, { + image = assets.ChevronRight, + color = theme.text, + size = UDim2.fromScale(1, 1), + }), + }) + else nil, }), Children = React.createElement("Frame", { LayoutOrder = 2, + AutomaticSize = Enum.AutomaticSize.XY, + BackgroundTransparency = 1, }, { + Padding = React.createElement("UIPadding", { + PaddingLeft = theme.padding, + }), + Layout = React.createElement("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, + Padding = theme.paddingSmall, }), }, children), }) diff --git a/src/TreeView/TreeView.luau b/src/TreeView/TreeView.luau index a590a930..9b9d4cbc 100644 --- a/src/TreeView/TreeView.luau +++ b/src/TreeView/TreeView.luau @@ -1,7 +1,10 @@ local React = require("@pkg/React") +local useTheme = require("@root/Common/useTheme") local treeViewTypes = require("@root/TreeView/types") +local TreeNode = require("@root/TreeView/TreeNode") +local useCallback = React.useCallback local useMemo = React.useMemo type TreeNode = treeViewTypes.TreeNode @@ -15,33 +18,36 @@ export type Props = { } local function TreeView(props: Props) - local nodesById = useMemo(function() end, { props.tree }) + local theme = useTheme() - local leafNodes = useMemo(function() end, { props.tree }) + local nodesById = useMemo(function() end, { props.roots }) - local children = {} - for _, node in props.roots do - children[node.label] = React.createElement("ImageButton", { - AutoButtonColor = false, - [React.Event.Activated] = function() - props.onActivated(node) - end, - }, { - Label = React.createElement("Frame", {}, { - Icon = React.createElement("ImageLabel", {}), + local leafNodes = useMemo(function() end, { props.roots }) - Text = React.createElement("TextLabel", { - Text = node.label, - }), - }), + local onNodeActivated = useCallback(function(node: TreeNode) + if props.onActivated then + props.onActivated(node) + end + end, { props.onActivated }) - Toggle = React.createElement("ImageLabel", {}), + local children: { [string]: React.Node } = {} + for index, node in props.roots do + children[node.label] = React.createElement(TreeNode, { + layoutOrder = index, + node = node, + onActivated = function() + onNodeActivated(node) + end, }) end - return React.createElement("Frame", {}, { + return React.createElement("Frame", { + BackgroundTransparency = 1, + AutomaticSize = Enum.AutomaticSize.XY, + }, { Layout = React.createElement("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, + Padding = theme.paddingSmall, }), }, children) end diff --git a/src/TreeView/TreeView.story.luau b/src/TreeView/TreeView.story.luau index cca59218..33214ac1 100644 --- a/src/TreeView/TreeView.story.luau +++ b/src/TreeView/TreeView.story.luau @@ -1,33 +1,45 @@ local React = require("@pkg/React") +local ContextProviders = require("@root/Common/ContextProviders") +local MockPlugin = require("@root/Testing/MockPlugin") local TreeView = require("./TreeView") +local types = require("./types") return { story = function() - return React.createElement(TreeView, { - roots = { + local tree: types.TreeNode = { + id = "1", + label = "Top", + children = { { - id = "1", - label = "Top", - children = { - { - id = "2", - label = "Child", - parent = "1", - children = { - {}, - }, - }, + id = "2", + label = "Child", + isExpanded = true, + children = {}, + }, + { + id = "3", + label = "Sibling", + children = { { - id = "3", - label = "Sibling", - parent = "1", + id = "4", + label = "Descendant", + isExpanded = false, children = {}, }, }, }, }, + } + return React.createElement(ContextProviders, { + plugin = MockPlugin.new(), + }, { + TreeView = React.createElement(TreeView, { + roots = { + tree, + }, + }), }) end, } diff --git a/src/TreeView/types.luau b/src/TreeView/types.luau index 74e9244b..6cc4e03d 100644 --- a/src/TreeView/types.luau +++ b/src/TreeView/types.luau @@ -2,6 +2,7 @@ export type TreeNode = { id: string, label: string, icon: string?, + isExpanded: boolean?, children: { TreeNode }?, parent: TreeNode?, }