Skip to content

Commit d262c97

Browse files
stevekwon211claude
andcommitted
feat(catalog): v0.29.0 — Collapsible + ButtonGroup
Catalog round-out, first batch. - Collapsible — single show/hide section; chevron-flip trigger; body collapses via max-height (Slint forbids @children inside `if`, so visible + height- collapse instead). - ButtonGroup — visually-joined cluster of Buttons (zero-gap horizontal row). Spinner / InputOTP / Carousel / Kbd defer to v0.29.1 (each needs a distinct Slint check first — continuous rotation animation, per-digit Input chain, slide math, alias). 53 components total. Cache-bust 0.29.0; WASM rebuilt. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent baba8fc commit d262c97

15 files changed

Lines changed: 184 additions & 21 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
[Live docs](https://stevekwon211.github.io/slintcn/docs/) · [Live demo](https://stevekwon211.github.io/slintcn) · [npm](https://www.npmjs.com/package/slintcn)
1010

11-
51 UI components, 8 installable blocks, a theme system, and a static registry you can host yourself.
11+
53 UI components, 8 installable blocks, a theme system, and a static registry you can host yourself.
1212

1313
<p align="center">
1414
<img src="docs/img/snapshots/section-6-dashboard.png" alt="slintcn dashboard components" width="31%">
@@ -88,6 +88,7 @@ node /path/to/slintcn/bin/slintcn.mjs add button card input dialog
8888
| **v0.26** | **Data Table** — sortable headers + paginated rows + row clicks; consumer owns data slicing → 46 components ||
8989
| **v0.27** | **Calendar + Date Picker** — month grid (`Calendar`) + Popover-wrapped trigger (`DatePicker`); consumer owns date math → 48 components ||
9090
| **v0.28** | **App-shell**`Sidebar` (collapsible nav with icons + active highlight), `Empty` (zero-state surface), `AspectRatio` (layout helper) → 51 components ||
91+
| **v0.29** | **Catalog round-out**`Collapsible` (single show/hide section), `ButtonGroup` (joined Buttons) → 53 components ||
9192
| **v1.0** | Game HUD registry expansion — hotbar, reticle, full keycap hints | later |
9293

9394
SaaS-first is a **wedge**, not a ceiling. Once tokens + motion + hover semantics

docs/ROADMAP.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
# slintcn roadmap
22

3-
## v0.28 — App-shell primitives (current)
3+
## v0.29 — catalog round-out (current)
4+
5+
- [x] **Collapsible** — single show / hide section with chevron-flip trigger.
6+
The body collapses via `max-height` (Slint forbids `@children` inside
7+
`if`, so `visible` + height-collapse instead).
8+
- [x] **ButtonGroup** — visually-joined cluster of Buttons (zero-gap row).
9+
10+
Spinner / InputOTP / Carousel / Kbd defer to v0.29.1 — each needs a small but
11+
distinct Slint-side check (animation-tick continuous rotation, per-digit
12+
Input chain, slide animation, alias).
13+
14+
## v0.28 — App-shell primitives
415

516
- [x] **Sidebar** — collapsible app sidebar; items with icons + active
617
highlight, animated width on toggle. Drives the consumer's routing via
@@ -119,10 +130,10 @@ Lead with the menu family (we already have the overlay infra) and the app-shell
119130
primitives (they serve real adopters like the Zero desktop app). Charts are a
120131
heavy, separate R&D track; the Game/HUD layer is the long-term differentiator.
121132

122-
### v0.29 — Catalog round-out (small gaps)
123-
- Collapsible, Aspect Ratio, Input OTP, Spinner, Carousel, Button Group,
124-
Empty / Field / Item, Native Select, Kbd (alias Keycap).
125-
- Why: parity polish; each is small.
133+
### v0.29.1 — Catalog round-out leftovers
134+
- Spinner (rotation via `animation-tick()` — needs Slint validation), Input
135+
OTP (per-digit Input chain), Carousel (slide math), Kbd (alias of Keycap).
136+
- Empty + AspectRatio already shipped in v0.28; Collapsible + ButtonGroup in v0.29.
126137

127138
### v0.30 — Charts (separate R&D track)
128139
- Area / Bar / Line / Pie.

examples/showcase/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/showcase/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "slintcn-showcase"
3-
version = "0.28.0"
3+
version = "0.29.0"
44
edition = "2021"
55
publish = false
66

examples/showcase/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ fn main() {
2424
"combobox", "command", "data-table",
2525
"calendar", "date-picker",
2626
"sidebar", "empty", "aspect-ratio",
27+
"collapsible", "button-group",
2728
"sign-in", "login", "pricing", "dashboard", "settings",
2829
"team", "profile", "stats",
2930
])

examples/showcase/ui/app_window.slint

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ import { DatePicker } from "slintcn/components/date-pi
6565
import { Sidebar, SidebarItem } from "slintcn/components/sidebar.slint";
6666
import { Empty } from "slintcn/components/empty.slint";
6767
import { AspectRatio } from "slintcn/components/aspect-ratio.slint";
68+
import { Collapsible } from "slintcn/components/collapsible.slint";
69+
import { ButtonGroup } from "slintcn/components/button-group.slint";
6870
import { SignIn } from "slintcn/blocks/sign-in.slint";
6971
import { Login } from "slintcn/blocks/login.slint";
7072
import { Pricing } from "slintcn/blocks/pricing.slint";
@@ -330,6 +332,23 @@ component PreviewHost inherits Rectangle {
330332
description: "Invite your first customer to get started.";
331333
action-label: "Invite customer";
332334
}
335+
if root.name == "collapsible": Rectangle {
336+
width: 420px;
337+
Collapsible {
338+
title: "Advanced settings";
339+
open: true;
340+
Text {
341+
text: "Hidden by default. Click the title to toggle.";
342+
color: Tokens.color-muted-foreground;
343+
font-size: Tokens.typography-body-size;
344+
}
345+
}
346+
}
347+
if root.name == "button-group": ButtonGroup {
348+
Button { variant: ButtonVariant.outline; text: "Day"; }
349+
Button { variant: ButtonVariant.outline; text: "Week"; }
350+
Button { variant: ButtonVariant.outline; text: "Month"; }
351+
}
333352
if root.name == "aspect-ratio": AspectRatio {
334353
ratio: 16 / 9;
335354
width: 480px;
@@ -443,7 +462,7 @@ export component AppWindow inherits Window {
443462
font-weight: Tokens.typography-weight-semibold;
444463
}
445464
Badge {
446-
text: "v0.28";
465+
text: "v0.29";
447466
variant: BadgeVariant.secondary;
448467
size: BadgeSize.sm;
449468
}
@@ -651,7 +670,7 @@ export component AppWindow inherits Window {
651670
spacing: 8px;
652671
alignment: start;
653672
Label { text: "Sign up for the beta"; variant: LabelVariant.default; }
654-
Badge { text: "v0.28"; variant: BadgeVariant.secondary; size: BadgeSize.sm; }
673+
Badge { text: "v0.29"; variant: BadgeVariant.secondary; size: BadgeSize.sm; }
655674
}
656675

657676
VerticalLayout {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "slintcn",
3-
"version": "0.28.0",
3+
"version": "0.29.0",
44
"description": "Beautiful copy-paste Slint components — shadcn for native UI",
55
"keywords": [
66
"slint",

registry/default/a11y.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,7 @@
3232
"date-picker": { "focusable": false, "keyboard": [], "focusTrap": false, "escapeDismiss": true },
3333
"sidebar": { "focusable": false, "keyboard": [], "focusTrap": false, "escapeDismiss": false },
3434
"empty": { "focusable": false, "keyboard": [], "focusTrap": false, "escapeDismiss": false },
35-
"aspect-ratio": { "focusable": false, "keyboard": [], "focusTrap": false, "escapeDismiss": false }
35+
"aspect-ratio": { "focusable": false, "keyboard": [], "focusTrap": false, "escapeDismiss": false },
36+
"collapsible": { "focusable": false, "keyboard": [], "focusTrap": false, "escapeDismiss": false },
37+
"button-group": { "focusable": false, "keyboard": [], "focusTrap": false, "escapeDismiss": false }
3638
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Tokens } from "../theme/tokens.slint";
2+
3+
// Visually-joined cluster of Buttons. Drop two or more `Button`s as
4+
// `@children`; the group lays them out in a single row with no gap. Each
5+
// Button keeps its own variant + rounded corners — `ButtonGroup` is layout
6+
// only, not a style override. Pair with `variant: ButtonVariant.outline` for
7+
// the classic "segmented action" look.
8+
export component ButtonGroup inherits Rectangle {
9+
background: transparent;
10+
preferred-width: row.preferred-width;
11+
preferred-height: row.preferred-height;
12+
13+
row := HorizontalLayout {
14+
spacing: 0;
15+
@children
16+
}
17+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Tokens } from "../theme/tokens.slint";
2+
import { Icon } from "icon.slint";
3+
import { LucidePaths } from "lucide-paths.slint";
4+
5+
// Single show / hide section. Like Accordion but for a standalone block — the
6+
// trigger row toggles the visibility of `@children`. The chevron flips on
7+
// open. Useful for filter sections, optional settings, inline FAQ rows.
8+
export component Collapsible inherits Rectangle {
9+
// Trigger label shown next to the chevron.
10+
in property <string> title;
11+
// Two-way; when true, `@children` are visible.
12+
in-out property <bool> open: false;
13+
// Fired with the new `open` value after a toggle click.
14+
callback toggled(bool);
15+
16+
background: transparent;
17+
18+
VerticalLayout {
19+
spacing: 0;
20+
21+
// Trigger row — click anywhere to toggle.
22+
Rectangle {
23+
height: 40px;
24+
border-radius: Tokens.radius-sm;
25+
background: trigger-touch.has-hover
26+
? Tokens.color-surface-1 : transparent;
27+
HorizontalLayout {
28+
padding-left: 12px;
29+
padding-right: 12px;
30+
spacing: 8px;
31+
Text {
32+
text: root.title;
33+
color: Tokens.color-foreground;
34+
font-size: Tokens.typography-body-size;
35+
font-weight: Tokens.typography-weight-semibold;
36+
vertical-alignment: center;
37+
horizontal-stretch: 1;
38+
}
39+
VerticalLayout {
40+
alignment: center;
41+
Icon {
42+
commands: root.open
43+
? LucidePaths.chevron-up
44+
: LucidePaths.chevron-down;
45+
size: 14px;
46+
tint: Tokens.color-muted-foreground;
47+
}
48+
}
49+
}
50+
trigger-touch := TouchArea {
51+
mouse-cursor: pointer;
52+
clicked => {
53+
root.open = !root.open;
54+
root.toggled(root.open);
55+
}
56+
}
57+
animate background {
58+
duration: Tokens.motion-fast;
59+
easing: Tokens.motion-easing-standard;
60+
}
61+
}
62+
63+
// Body — `@children` must live at top-level (Slint forbids it inside
64+
// `if`), so we toggle `visible` + collapse the height instead.
65+
body := VerticalLayout {
66+
visible: root.open;
67+
min-height: root.open ? 0px : 0px;
68+
max-height: root.open ? body.preferred-height : 0px;
69+
padding-top: 8px;
70+
padding-bottom: 8px;
71+
padding-left: 12px;
72+
padding-right: 12px;
73+
spacing: 8px;
74+
@children
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)