wabi 0.24.0 → 0.26.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75765e0675d366daed554a39f13e2d1c7d477755e89b0c12d166bc5f94236c24
4
- data.tar.gz: b58622c10c1c4c8543275d363a1650568ef722b4a317eaae42f13e900347f4e7
3
+ metadata.gz: 6cf18805afd72016ed1b47913331d8e4ff775a6c499416b1617855c4a64f1554
4
+ data.tar.gz: d968d9032f9cecc8f1ccfd1c0bc363ae24dbae7729e17cf11eb5d07d50ee3fe7
5
5
  SHA512:
6
- metadata.gz: eda7a8e1443b1e612a70cefb1ce741fe75be14b473dc3751e5a2de197f91515108416de1f5f977864d9467f12368db3cb2959b180b779325d639c17081b29f5b
7
- data.tar.gz: ddb360636c4c5b484b4ff2b8ecfde429704f9e72a4c30060d7a64307525f14bc9c0e2eff96f5fa7203bef48d74ec2f8ae70f981d57c566299560929f793f86d7
6
+ metadata.gz: ad11feda811392ae825a58badd493167c65388461c0bfc05e872e93c74bff4db7b04d33411ca24027958cd1daff56af8ead5cae1c4669aa4ed562b655cc25a68
7
+ data.tar.gz: fabc543b2d794b2360c3c9811fdc9d26976846e7e44c2b8b87d97dd002ffef48fd4e29a8735892c8cf9ce5968fdbc6da8ddbf92541115781340ee7ede4dd11a2
data/CHANGELOG.md CHANGED
@@ -2,6 +2,112 @@
2
2
 
3
3
  All notable changes to Wabi land here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
4
 
5
+ ## 0.26.0 - 2026-06-09
6
+
7
+ An API-standardization pass ahead of 1.0, a documentation consistency sweep across all 49 component pages, and automated gem releases. **This release contains breaking API changes** (allowed pre-1.0 per SemVer) — they close the last naming/typing inconsistencies before the public API freezes at 1.0.
8
+
9
+ ### Breaking changes
10
+ - **accordion** — `AccordionTrigger`'s `heading_level:` (symbol, e.g. `:h3`) is now `level:` (Integer 1-6, default `3`), mirroring `CardTitle`. Pass `level: nil` to opt out of heading semantics (renders a `<div>` wrapper).
11
+ - **`aria_label:` rename** — the keyword that maps to the HTML `aria-label` attribute is now `aria_label:` (was `label:`) in: `progress`, `radio_group`, `number_input`, `input_otp`, `splitter` (resize trigger), and `context_menu` (radio group). Components that render a real `<label>` element keep `label:` (`checkbox`, `command`, `tree_view`).
12
+
13
+ ### Added
14
+ - `invalid:` on **textarea** (parity with `input`) → emits `aria-invalid="true"`.
15
+ - `aria_label:` on **dropdown_menu** radio group (parity with `context_menu`).
16
+
17
+ ### Changed (non-breaking)
18
+ - Relaxed the required `name:` keyword to optional across form inputs (`combobox`, `radio_group`, `rating_group`, `slider`, `tags_input`, `input_otp`, `number_input`, `file_upload`, `date_picker` incl. `Calendar`); **toggle_group** `type:` now defaults to `:single`. Callers that already pass these are unaffected.
19
+ - Enum defaults are now symbols: `tree_view` `selection_mode: :single`, `color_picker` `format: :rgba` (strings are still accepted — output is unchanged).
20
+ - User `class:` routes uniformly through `merge_class` in the breadcrumb/popover/alert_dialog/tooltip triggers.
21
+
22
+ ### Fixed
23
+ - `Wabi::ClassMerge.call` returns `nil` (not `""`) for an empty result, so components never emit a spurious empty `class=""` attribute.
24
+ - **date_picker** range mode no longer emits malformed `name="[start]"`/`name="[end]"` hidden inputs when `name:` is omitted.
25
+
26
+ ### Docs
27
+ - Consistency sweep across all 49 component pages: descriptions sourced from the component manifests, complete `SOURCE_PATHS` (the Source section now shows every file you install), copy-pasteable example code (no placeholders), richer variant coverage, and a missing accessibility section added to `skeleton`.
28
+
29
+ ### Tooling
30
+ - Automated gem publishing via **RubyGems Trusted Publishing (OIDC)** on `vX.Y.Z` tags — see `.github/workflows/gem-release.yml` and `RELEASING.md`. No stored credentials.
31
+
32
+ ## 0.25.0 - 2026-06-08
33
+
34
+ Component count 47 → **49**. Two new components, a project-wide WCAG-AA accessibility audit, and the first `CONTRIBUTING.md`.
35
+
36
+ ### Added
37
+ - **Color Picker** (`color_picker`) — popover picker with a 2D saturation/value
38
+ area, hue + alpha channel sliders, a hex input, and preset swatches. Backed by
39
+ `@zag-js/color-picker`; portals to `<body>`; submit with `name:` for a hidden form field.
40
+ - **Tree View** (`tree_view`) — data-driven, accessible tree (pass a nested `items:`
41
+ array): expand/collapse, single/multiple selection, keyboard nav + typeahead,
42
+ optional per-node checkboxes, folder/file icons. Backed by `@zag-js/tree-view`.
43
+ - **`CONTRIBUTING.md`** — monorepo layout, per-component anatomy (Wabi::Base +
44
+ variants DSL + merge_class), the Zag.js wiring pattern, the docs↔registry
45
+ byte-identical rule, testing (RSpec + Vitest + headless-Chrome), and how to add a
46
+ component end to end.
47
+
48
+ ### Accessibility (WCAG-AA audit)
49
+ A full audit of all 49 components fixed 100+ findings across roles/semantics,
50
+ keyboard, focus, accessible names, states, live regions, motion, and contrast:
51
+ - **Motion:** `motion-reduce:` guards on every transition/animation (and
52
+ `prefers-reduced-motion` guards in the toast/date-picker controllers).
53
+ - **Decorative icons:** `aria-hidden` on decorative SVGs/indicators.
54
+ - **Names:** accessible names for icon-only triggers and form controls (optional
55
+ `aria_label:`/`label:` params — no breaking changes); `aria-label` passthrough.
56
+ - **Roles/states:** `alert_dialog` now `role="alertdialog"`; `aria-expanded`/
57
+ `aria-selected`/`aria-sort`/`aria-disabled`/`aria-invalid` wired where missing;
58
+ breadcrumb current-page and hover-card trigger semantics corrected; separator
59
+ emits a native `<hr>` when non-decorative.
60
+ - **Focus:** visible `focus-visible` rings on previously-unindicated controls;
61
+ `switch`/`checkbox` rings moved to the element that actually receives focus.
62
+ - **Live regions:** carousel slide announcer, toaster `<ol>` live region, form/
63
+ command/file-upload/tags-input status & error regions.
64
+ - **Contrast:** `muted-foreground`, `destructive`, and weak focus rings darkened to
65
+ meet AA across all 8 themes (light + dark); subtle borders documented as
66
+ decorative-exempt (WCAG 1.4.11).
67
+
68
+ ### Fixed
69
+ - **Color Picker:** the saturation/value spectrum now renders (the area background
70
+ no longer collapses to height 0 under Zag's inline `position`); the value text
71
+ shows the current color.
72
+ - **Tree View:** leaf rows now indent by depth (indentation moved off the
73
+ Zag-managed row, whose `style` Zag overwrites, onto an inner wrapper).
74
+
75
+ ## 0.24.3 - 2026-06-07
76
+
77
+ ### Fixed
78
+ - **Splitter:** dragging the gutter now resizes the panels. Zag initializes panel
79
+ sizes (`syncSize`) at start, but bails when the root has no layout yet — inside an
80
+ inactive tab panel, below the fold, or a closed overlay — leaving the sizes empty
81
+ so a drag had no base to resize from (the gutter showed a resize cursor but
82
+ nothing moved). The controller now re-syncs sizes via `IntersectionObserver` once
83
+ the splitter is visible. Same class of fix as Carousel in 0.24.2.
84
+
85
+ Component count unchanged (47).
86
+
87
+ ## 0.24.2 - 2026-06-07
88
+
89
+ ### Fixed
90
+ - **Collapsible:** the content now actually expands/collapses. Zag nulls the
91
+ content's `data-state` once open + settled (its canonical animation keys off a
92
+ `--height` variable), which left our `grid-rows` height transition stuck closed;
93
+ the controller now re-asserts `data-state` from the open state so the animation
94
+ runs.
95
+ - **Carousel:** prev/next now scroll the slides. Zag computes scroll-snap points
96
+ right after start, but when the carousel isn't laid out yet (inside an inactive
97
+ tab panel, below the fold, or a closed overlay) the points collapsed to ~0 and
98
+ navigation moved only the indicators. The controller now refreshes the snap
99
+ points via `IntersectionObserver` once the carousel becomes visible.
100
+
101
+ Component count unchanged (47).
102
+
103
+ ## 0.24.1 - 2026-06-07
104
+
105
+ ### Fixed
106
+ - **Navigation Menu:** dropdown panels now portal to `<body>` and are positioned
107
+ `fixed` under their trigger, so they are no longer clipped by `overflow-hidden`
108
+ or stacking-context ancestors (e.g. inside cards/previews). Hover-to-panel and
109
+ click-outside dismiss are unchanged. Component count unchanged (47).
110
+
5
111
  ## 0.24.0 - 2026-06-06
6
112
 
7
113
  Four new components (43 → 47), all backed by Zag.js 1.41 via `@zag-js/vanilla`.
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Wabi is an open-source UI component library for **Ruby on Rails 8**, built on **Phlex + Tailwind 4 + Stimulus + Hotwire**. Inspired by shadcn/ui, components are *copied* into your app — you own the code, customize freely, no upstream API to drift away from.
6
6
 
7
- 🎉 **Status:** v0.24.0 alpha — [available on RubyGems](https://rubygems.org/gems/wabi). 47 components, 8 theme palettes, WCAG-AA targeted, live docs + registry at [wabi-docs.onrender.com](https://wabi-docs.onrender.com).
7
+ 🎉 **Status:** v0.26.0 alpha — [available on RubyGems](https://rubygems.org/gems/wabi). 49 components, 8 theme palettes, WCAG-AA audited, live docs + registry at [wabi-docs.onrender.com](https://wabi-docs.onrender.com).
8
8
 
9
9
  ---
10
10
 
@@ -31,15 +31,15 @@ Then add `@import "./wabi/tokens.css";` AFTER `@import "tailwindcss";` in your `
31
31
 
32
32
  ## What's in the box
33
33
 
34
- ### 47 components
34
+ ### 49 components
35
35
 
36
36
  | Group | Components |
37
37
  |---|---|
38
- | **Forms** (19) | Button, Input, NumberInput, Textarea, Label, Checkbox, Switch, Select, RadioGroup, Slider, Toggle, ToggleGroup, Combobox, Form, DatePicker, InputOTP, FileUpload, RatingGroup, TagsInput |
38
+ | **Forms** (20) | Button, Input, NumberInput, Textarea, Label, Checkbox, Switch, Select, RadioGroup, Slider, Toggle, ToggleGroup, Combobox, Form, DatePicker, InputOTP, FileUpload, RatingGroup, TagsInput, ColorPicker |
39
39
  | **Layout & Display** (11) | Card, Badge, Separator, Alert, Avatar, Table, DataTable, Skeleton, Sidebar, Carousel, Splitter |
40
40
  | **Overlays** (7) | Dialog, AlertDialog, Drawer (4 sides), Tooltip, Popover, Command, HoverCard |
41
41
  | **Menus** (2) | DropdownMenu (nested submenus, checkbox + radio items), ContextMenu |
42
- | **Navigation** (6) | Accordion, Tabs, Breadcrumb, Pagination, Collapsible, NavigationMenu |
42
+ | **Navigation** (7) | Accordion, Tabs, Breadcrumb, Pagination, Collapsible, NavigationMenu, TreeView |
43
43
  | **Feedback** (2) | Toast + Toaster, Progress |
44
44
 
45
45
  Compound components (Card, Alert, Avatar, Dialog, Drawer, Table, Form, Combobox, …) ship as composable sub-component sets. All interactive components wire through **Zag.js 1.x** state machines for WAI-ARIA roles, keyboard semantics, and focus management. Toast is the one exception: it uses a custom Stimulus coordinator for Sonner-style stacking, group pause-on-hover, and swipe-to-dismiss — `@zag-js/toast`'s imperative DOM-creation model conflicts with Wabi's SSR + Turbo Stream append.
@@ -183,6 +183,7 @@ Requires Node 20+ in PATH (Pagefind is fetched via `npx` on demand).
183
183
  | v0.11 | Table component (shadcn parity); ClassMerge text-align fix | ✅ shipped 2026-06-01 |
184
184
  | v0.12 | Skeleton, Breadcrumb, Pagination, Progress, AlertDialog | ✅ shipped 2026-06-01 |
185
185
  | v0.13 | DataTable (server-driven: sortable headers + row selection) | ✅ shipped 2026-06-01 |
186
+ | v0.14–0.25 | JS test suite + coverage floors; +29 components (Sidebar, Carousel, Splitter, NavigationMenu, RatingGroup, HoverCard, TagsInput, Collapsible, ColorPicker, TreeView, …); full WCAG-AA audit | ✅ shipped 2026-06-08 |
186
187
  | v1.0 | API stability; external a11y audit | 2027-04 target |
187
188
 
188
189
  See [ROADMAP.md](./ROADMAP.md) for the long-term view and [CHANGELOG.md](./CHANGELOG.md) for the per-release detail.
@@ -191,7 +192,7 @@ See [ROADMAP.md](./ROADMAP.md) for the long-term view and [CHANGELOG.md](./CHANG
191
192
 
192
193
  ## Contributing
193
194
 
194
- Wabi is in alpha and the API is still moving. Filing issues with concrete repros, suggestions for components, or theme palette ideas is the most useful kind of contribution right now. A `CONTRIBUTING.md` documenting the per-component anatomy and the Zag.js wiring conventions is still on the to-do list.
195
+ Wabi is in alpha and the API is still moving. Filing issues with concrete repros, suggestions for components, or theme palette ideas is the most useful kind of contribution right now. See **[CONTRIBUTING.md](https://github.com/wabikit/wabi/blob/main/CONTRIBUTING.md)** for the monorepo layout, the per-component anatomy, the Zag.js wiring conventions, and how to add a component end to end.
195
196
 
196
197
  ---
197
198
 
@@ -25,7 +25,13 @@ module Wabi
25
25
  tokens.each do |token|
26
26
  seen[group_key(token)] = token
27
27
  end
28
- seen.values.join(" ")
28
+ merged = seen.values.join(" ")
29
+ # Return nil (not "") for an all-empty merge so Phlex omits the attribute
30
+ # entirely instead of emitting a spurious `class=""`. Base-class-less
31
+ # components (e.g. breadcrumb root, popover/alert_dialog/tooltip triggers)
32
+ # call merge_class(user_class) with no class, and would otherwise render
33
+ # `class=""`. Non-empty results are unaffected.
34
+ merged.empty? ? nil : merged
29
35
  end
30
36
 
31
37
  def group_key(token)
data/lib/wabi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wabi
4
- VERSION = "0.24.0"
4
+ VERSION = "0.26.0"
5
5
  end
data/templates/tokens.css CHANGED
@@ -83,6 +83,13 @@
83
83
  --color-accent-foreground: hsl(var(--accent-foreground));
84
84
  --color-destructive: hsl(var(--destructive));
85
85
  --color-destructive-foreground: hsl(var(--destructive-foreground));
86
+ /* --border / --input render intentionally subtle (~1.2–1.4:1 vs background).
87
+ * Per WCAG 1.4.11, decorative borders that are not the SOLE means of
88
+ * identifying a component or its state are exempt from the 3:1 UI-contrast
89
+ * requirement — Wabi components convey structure/state via fill, text, and
90
+ * focus rings, not the border alone. --ring (the focus indicator) IS held to
91
+ * >=3:1 against background in every theme; --muted-foreground and
92
+ * --destructive meet AA 4.5:1 for text. See the a11y audit notes. */
86
93
  --color-border: hsl(var(--border));
87
94
  --color-input: hsl(var(--input));
88
95
  --color-ring: hsl(var(--ring));
@@ -114,10 +121,10 @@
114
121
  --secondary: 240 4.8% 95.9%;
115
122
  --secondary-foreground: 240 5.9% 10%;
116
123
  --muted: 240 4.8% 95.9%;
117
- --muted-foreground: 240 3.8% 46.1%;
124
+ --muted-foreground: 240 3.8% 45.1%;
118
125
  --accent: 240 4.8% 95.9%;
119
126
  --accent-foreground: 240 5.9% 10%;
120
- --destructive: 0 84.2% 60.2%;
127
+ --destructive: 0 84.2% 48.6%;
121
128
  --destructive-foreground: 0 0% 98%;
122
129
  --border: 240 5.9% 90%;
123
130
  --input: 240 5.9% 90%;
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wabi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.24.0
4
+ version: 0.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Ortega