Refactor: results expose Element as a named field

Every component result type now names its element Element instead of
embedding *ui.Element. The eleven element-plus-changed results
(AccordionView, CarouselView, CollapsibleView, ImageViewerView,
PaginationResult, StepsResult, SidebarResult, TabsResult, RatingParts,
FileDropZoneParts, TransferParts) fold into ChoiceResult.

Fixes four Gallery demos where .Width(...).Changed() read the element's
flag instead of the component's: Accordion, MultiSelect, Cascader,
TreeSelect. TestDataAccordionDemoLogsChange covers the Accordion.
This commit is contained in:
ZacharyZhang-NY committed 2026-10-05 13:35:53 -04:00
1 parent 078dcab8b4
commit 8880865021
73 files changed
+163 -245

No files matched your search

+2 -2
View File
@@ -152,7 +152,7 @@ func (g *gallery) filesView(c *ui.Context, log func(string)) {
v := mujica.DataTable(c, &s.table, s.entries, mujica.DataTableOptions[fileEntry, int]{
Columns: cols, Key: func(f fileEntry) int { return f.ID }, Multiple: true, Version: s.version,
})
v.FillWidth().Height(430)
v.Element.FillWidth().Height(430)
mujica.ContextMenu(c, v.Element, mujica.ContextMenuOptions{}, func(m *mujica.PopupMenu) { g.fileMenu(m, log, targets) })
if v.Changed() {
log(fmt.Sprintf("selection %d checked", s.table.Selection.Len()))
@@ -174,7 +174,7 @@ func (g *gallery) filesView(c *ui.Context, log func(string)) {
{ID: "shown", Text: fmt.Sprintf(g.t("%d shown", "显示 %d 个"), shown), Secondary: true},
},
Right: []mujica.StatusItem{{ID: "selected", Text: fmt.Sprintf(g.t("%d selected", "已选 %d 个"), s.table.Selection.Len())}},
}).Radius(theme.CardRadius).Border(theme.BorderWidth, k.Border)
}).Element.Radius(theme.CardRadius).Border(theme.BorderWidth, k.Border)
g.fileAdders(c, log)
g.renameDialog(c, log)
g.deleteDialog(c, log)
+8 -3
View File
@@ -330,7 +330,8 @@ func multiSelectDemo(c *ui.Context, log func(string)) {
}
choiceLabeled(c, "Fruits", func() {
r := mujica.MultiSelect(c, &s.values, choiceFruits, mujica.MultiSelectOptions{Max: limit, MaxTags: 2, Disabled: s.disable, Label: "Fruits"})
if r.Width(320).Changed() {
r.Element.Width(320)
if r.Changed() {
log(fmt.Sprintf("Fruits: %v", s.values))
}
})
@@ -435,7 +436,9 @@ func cascaderDemo(c *ui.Context, log func(string)) {
}, func() {
choiceLabeled(c, "City (children load on demand)", func() {
opts := mujica.CascaderOptions{Level: level, Load: load, AnyLevel: s.anyLevel, Disabled: s.ds, Label: "City"}
if mujica.Cascader(c, &s.path, opts).Width(320).Changed() {
r := mujica.Cascader(c, &s.path, opts)
r.Element.Width(320)
if r.Changed() {
log(fmt.Sprintf("path: %v", s.path))
}
})
@@ -471,7 +474,9 @@ func treeSelectDemo(c *ui.Context, log func(string)) {
}
choiceLabeled(c, "Roles", func() {
opts := mujica.TreeSelectOptions{Multiple: s.multiple, Rule: rule, MaxTags: 2, Disabled: s.disabled, Label: "Roles"}
if mujica.TreeSelect(c, &s.sel, choiceRoles, opts).Width(320).Changed() {
r := mujica.TreeSelect(c, &s.sel, choiceRoles, opts)
r.Element.Width(320)
if r.Changed() {
log(fmt.Sprintf("Roles: %v", s.sel))
}
})
+4 -4
View File
@@ -58,7 +58,7 @@ func dataListDemo(c *ui.Context, log func(string)) {
ui.Text(c, "Office").TextColor(mujica.Tokens(c).TextMuted)
}
})
v.Size(480, 320)
v.Element.Size(480, 320)
if v.Changed() {
k, _ := s.list.Selected()
log(fmt.Sprintf("selected %d, %d chosen", k, s.list.Selection.Len()))
@@ -138,7 +138,7 @@ func dataTableDemo(c *ui.Context, log func(string)) {
v := mujica.DataTable(c, &s.table, rows, mujica.DataTableOptions[dataRelic, int]{
Columns: cols, Key: func(r dataRelic) int { return r.ID }, Multiple: s.multiple, Status: st,
})
v.Size(620, 360)
v.Element.Size(620, 360)
ui.Text(c, fmt.Sprintf("%d of %d rows shown", s.table.Rows(), len(rows))).TextColor(k.TextMuted)
if v.SortChanged() {
log(fmt.Sprintf("sort %s descending=%v", s.table.Sort.Column, s.table.Sort.Descending))
@@ -224,7 +224,7 @@ func dataTreeDemo(c *ui.Context, log func(string)) {
ui.Checkbox(c, &s.multiple, "Multiple")
})
v := mujica.Tree(c, ts, opts)
v.Size(420, 340)
v.Element.Size(420, 340)
if v.Changed() {
n, _ := ts.Selected()
log(fmt.Sprintf("selected %s, %d chosen", n, ts.Selection.Len()))
@@ -290,7 +290,7 @@ func dataTreeTableDemo(c *ui.Context, log func(string)) {
{ID: "kids", Title: "Rooms", Width: 80, Align: ui.End, Cell: func(n string) { ui.Text(c, strconv.Itoa(len(s.lazy.kids[n]))) }},
},
})
v.Size(520, 320)
v.Element.Size(520, 320)
if v.SortChanged() {
log(fmt.Sprintf("sort %s descending=%v", s.table.Sort.Column, s.table.Sort.Descending))
}
+5 -3
View File
@@ -58,7 +58,7 @@ func dataAccordionDemo(c *ui.Context, log func(string)) {
log("closed all from outside")
}
})
if mujica.Accordion(c, &s.open, []mujica.AccordionItem{
r := mujica.Accordion(c, &s.open, []mujica.AccordionItem{
{ID: "choir", Title: "Choir", Content: func() { ui.Text(c, "Twelve voices, two at the altar.") }},
{ID: "nave", Title: "Nave", Content: func() { ui.Text(c, "Pews of black oak, polished for the feast.") }},
{ID: "crypt", Title: "Crypt (disabled)", Disabled: true, Content: func() {}},
@@ -67,7 +67,9 @@ func dataAccordionDemo(c *ui.Context, log func(string)) {
log("ring the bells")
}
}},
}, mujica.AccordionOptions{Multiple: s.multiple, KeepOne: s.keepOne}).Width(420).Changed() {
}, mujica.AccordionOptions{Multiple: s.multiple, KeepOne: s.keepOne})
r.Element.Width(420)
if r.Changed() {
log(fmt.Sprintf("open %v", s.open))
}
})
@@ -235,7 +237,7 @@ func dataCarouselDemo(c *ui.Context, log func(string)) {
v := mujica.Carousel(c, &s.index, len(dataPictures), mujica.CarouselOptions{Label: "Windows", Autoplay: s.autoplay, Loop: s.loop, Interval: d}, func(i int) {
ui.Image(c, dataPictures[i].Source).Grow(1).Label(dataPictures[i].Alt)
})
v.Size(520, 300)
v.Element.Size(520, 300)
if v.Changed() {
log(fmt.Sprintf("slide %d", s.index+1))
}
+10
View File
@@ -47,3 +47,13 @@ func TestDataDemoButtonsLog(t *testing.T) {
t.Fatalf("Light candles not logged: %q", *events)
}
}
func TestDataAccordionDemoLogsChange(t *testing.T) {
tt, events := dataDemo(t, "074")
if err := tt.Click("Bells"); err != nil {
t.Fatal(err)
}
if !slices.Contains(*events, "open [bells]") {
t.Fatalf("Accordion change not logged: %q", *events)
}
}
+5 -5
View File
@@ -180,9 +180,9 @@ if r.Submitted() {
inputSection(c, "States", func() {
ui.Row(c).Gap(12).Children(func() {
e, ro, off := "1789-13-01", "Read only", "Disabled"
mujica.TextInput(c, &e, mujica.TextInputOptions{Label: "Error state", Error: "No such date"}).Grow(1)
mujica.TextInput(c, &ro, mujica.TextInputOptions{Label: "Read-only state", ReadOnly: true}).Grow(1)
mujica.TextInput(c, &off, mujica.TextInputOptions{Label: "Disabled state", Disabled: true}).Grow(1)
mujica.TextInput(c, &e, mujica.TextInputOptions{Label: "Error state", Error: "No such date"}).Element.Grow(1)
mujica.TextInput(c, &ro, mujica.TextInputOptions{Label: "Read-only state", ReadOnly: true}).Element.Grow(1)
mujica.TextInput(c, &off, mujica.TextInputOptions{Label: "Disabled state", Disabled: true}).Element.Grow(1)
})
})
}},
@@ -244,8 +244,8 @@ if r.Submitted() {
ui.Row(c).Gap(12).AlignItems(ui.Start).Children(func() {
a, b, e := 4.0, 2.0, 7.5
mujica.NumberInput(c, &a, mujica.NumberInputOptions{Min: 1, Max: 8, StepperOnly: true, Label: "Stepper state"})
mujica.NumberInput(c, &b, mujica.NumberInputOptions{Label: "Disabled state", Disabled: true}).Width(160)
mujica.NumberInput(c, &e, mujica.NumberInputOptions{Step: 0.5, Label: "Error state", Error: "Must be whole"}).Width(160)
mujica.NumberInput(c, &b, mujica.NumberInputOptions{Label: "Disabled state", Disabled: true}).Element.Width(160)
mujica.NumberInput(c, &e, mujica.NumberInputOptions{Step: 0.5, Label: "Error state", Error: "Must be whole"}).Element.Width(160)
})
})
}},
+1 -1
View File
@@ -417,7 +417,7 @@ func layoutSplitPaneDemo(c *ui.Context, log func(string)) {
Collapsible: sides[s.collapsible]},
pane("Files", "Drag the divider, or focus it and use the arrows.", k.Surface),
pane("Editor", "Enter on the divider folds the collapsible pane.", k.Background))
r.Fill()
r.Element.Fill()
if r.Resized {
log(fmt.Sprintf("resized to %.0f", s.split.Size))
}