From da11df039474103b7784376c19176f2fbb4d121a Mon Sep 17 00:00:00 2001 From: Robert Jelic <36573031+NoryiE@users.noreply.github.com> Date: Wed, 29 Oct 2025 18:28:59 +0100 Subject: [PATCH] Update .gitignore and enhance XML documentation with state management and custom tags --- .gitignore | 12 +- docs/.vitepress/config.mts | 8 +- docs/guides/xml.md | 267 +++++++++++++++++++++++++++++++++---- 3 files changed, 256 insertions(+), 31 deletions(-) diff --git a/.gitignore b/.gitignore index c22a369..e768144 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,14 @@ test2.lua basaltImage.lua .vscode todo.txt -tools \ No newline at end of file +tools +SplitPane.lua +Accordion.lua +Stepper.lua +Drawer.lua +Breadcrumb.lua +Dialog.lua +DockLayout.lua +ContextMenu.lua +Toast.lua +src \ No newline at end of file diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index a314d3d..15aa5b8 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -116,6 +116,8 @@ export default defineConfig({ items: [ { text: 'BaseFrame', link: 'references/elements/BaseFrame' }, { text: 'Frame', link: 'references/elements/Frame' }, + { text: 'ScrollFrame', link: 'references/elements/ScrollFrame' }, + { text: 'SideNav', link: 'references/elements/SideNav' }, { text: 'TabControl', link: 'references/elements/TabControl' }, ], }, @@ -133,11 +135,13 @@ export default defineConfig({ { text: 'Input', link: 'references/elements/Input' }, { text: 'Label', link: 'references/elements/Label' }, { - text: 'List', - link: 'references/elements/List', + text: 'Collection', + link: 'references/elements/Collection', collapsed: true, items: [ + { text: 'ComboBox', link: 'references/elements/ComboBox' }, { text: 'DropDown', link: 'references/elements/DropDown' }, + { text: 'List', link: 'references/elements/List' }, { text: 'Menu', link: 'references/elements/Menu' }, ], }, diff --git a/docs/guides/xml.md b/docs/guides/xml.md index 1ec253f..3624013 100644 --- a/docs/guides/xml.md +++ b/docs/guides/xml.md @@ -41,6 +41,163 @@ main:loadXML([[ ]], scope) ``` +## State Management + +Basalt's state system integrates seamlessly with XML, allowing you to bind element properties to reactive states. + +### Inline State Binding + +Use the `State:` suffix on any attribute to bind it to a state: + +```lua +local scope = {} + +main:loadXML([[ + +]], scope) +``` +## Custom XML Tags + +You can register custom tags to create reusable components or handle special logic. + +### Registering a Custom Tag + +```lua +local XMLParser = basalt.getXMLParser() + +XMLParser.registerTagHandler("card", function(node, parent, scope) + -- Create a frame container + local card = parent:addFrame() + card:setBackground(colors.gray) + card:setSize(20, 10) + + -- Parse title attribute + if node.attributes.title then + local title = node.attributes.title:gsub("^\"", ""):gsub("\"$", "") + local titleLabel = card:addLabel() + titleLabel:setText(title) + titleLabel:setPosition(2, 1) + end + + -- Process children inside the card + if node.children then + for _, child in ipairs(node.children) do + local childTag = child.tag:sub(1,1):upper() .. child.tag:sub(2) + if card["add" .. childTag] then + local element = card["add" .. childTag](card) + element:fromXML(child, scope) + end + end + end + + return card +end) +``` + +### Using Custom Tags + +```lua +main:loadXML([[ + + +]]) +``` + +### Advanced Custom Tag Example + +Create a reusable dialog component: + +```lua +XMLParser.registerTagHandler("dialog", function(node, parent, scope) + local dialog = parent:addFrame() + dialog:setSize(30, 15) + dialog:setBackground(colors.black) + dialog:addBorder({left=true, right=true, top=true, bottom=true}) + dialog:center() + + -- Title bar + if node.attributes.title then + local title = node.attributes.title:gsub("^\"", ""):gsub("\"$", "") + local titleBar = dialog:addLabel() + titleBar:setText(title) + titleBar:setPosition(2, 1) + titleBar:setForeground(colors.white) + end + + -- Close button + local closeBtn = dialog:addButton() + closeBtn:setText("X") + closeBtn:setPosition(28, 1) + closeBtn:setSize(2, 1) + closeBtn:onClick(function() + dialog:remove() + end) + + -- Content area (process children) + if node.children then + for _, child in ipairs(node.children) do + local childTag = child.tag:sub(1,1):upper() .. child.tag:sub(2) + if dialog["add" .. childTag] then + local element = dialog["add" .. childTag](dialog) + element:fromXML(child, scope) + end + end + end + + return dialog +end) + +-- Usage +main:loadXML([[ + + +]]) +``` + +### Unregistering Custom Tags + +```lua +XMLParser.unregisterTagHandler("card") +``` + +### Checking for Custom Tags + +```lua +local handler = XMLParser.getTagHandler("card") +if handler then + -- Handler exists +end +``` + ## Event Handlers There are two ways to define event handlers: @@ -84,6 +241,27 @@ The XML parser automatically converts values based on the property type: /> ``` +## Custom Attributes + +Elements can store custom XML data that isn't a standard property: + +```lua +main:loadXML([[ + +]]) +``` + +Custom attributes and children are stored in the `customXML` property and can be accessed via `getCustomXML()`. + ## Important Notes 1. **Scope Variables** @@ -101,41 +279,74 @@ The XML parser automatically converts values based on the property type: - Expressions have access to scope variables - Complex logic should be in Lua code -## Example with Multiple Features +4. **State Bindings** + - State names are automatically extracted from attribute names + - Use `propertyState:stateName` format for inline binding + - Nested `` tags provide better organization + +5. **Custom Tags** + - Custom handlers have full access to parent, node, and scope + - Must manually process child nodes if needed + - Can return elements for further manipulation + +## Complete Example ```lua +local XMLParser = basalt.getAPI("xml") + +-- Register custom card component +XMLParser.registerTagHandler("card", function(node, parent, scope) + local card = parent:addFrame() + card:setBackground(colors.gray) + card:setSize(25, 8) + + if node.attributes.title then + local title = node.attributes.title:gsub("^\"", ""):gsub("\"$", "") + card:addLabel():setText(title):setPosition(2, 1) + end + + if node.children then + for _, child in ipairs(node.children) do + local childTag = child.tag:sub(1,1):upper() .. child.tag:sub(2) + if card["add" .. childTag] then + local element = card["add" .. childTag](card) + element:fromXML(child, scope) + end + end + end + + return card +end) + +-- Setup scope local scope = { appTitle = "My App", colors = colors, + hoverColor = colors.lightGray, handleSubmit = function(self) - -- handle submission + basalt.debug("Submitted!") end } -local xmlFile = fs.open("example.xml", "r") -main:loadXML(xmlFile.readAll(), scope) -xmlFile.close() -``` - -```xml - -