phlex_kit 0.2.0 → 0.2.1

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +138 -52
  3. data/lib/phlex_kit/version.rb +1 -1
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d165b8e5ecbb24ef238be1c9472db2d19cdcb30079c85e2e839019547d5324fa
4
- data.tar.gz: 89f8058734e7d2745b3ea96e32cea6845e721c4f2e28a8621bc7c4978183c510
3
+ metadata.gz: 14f1ab06594f344904b8fbeecd23bca4c08005b35faf16325aca36edf6079c2b
4
+ data.tar.gz: 9cbdd5092ce76896536a59de10dc9e23734ee68cce9f85acf5e88b11ebf3d092
5
5
  SHA512:
6
- metadata.gz: 2c1b8608a4175ae249ed98ecae2c0ffccbb1c8a5f07d9fea298bf29e39d0eee3f401f6accd822da8fb42cc194560690fa4ed72e389bd448e89d2f6f008f494de
7
- data.tar.gz: 87773e1fa4628d51cdeef7d93684fe3c91d728fe77f80d3e093fbcfeb1d210d1e176d6fd0f3d89901bb7c2c4ffc67db04104fc44437a017ee7df8cd5d9ca3037
6
+ metadata.gz: 725e6b9a212702970cfedac729769373d378015409db9c56aee565b03c6d30dca6283567df66547e56b3d0271083e324ec73a97d2daa7baf74d93b9c2101119f
7
+ data.tar.gz: 4a3edb915f2082b66b18d96f89cc990aebedf6241a8a2e28eacd60329e9b563a080fa15789fee0b8b7e040a274baecd2c28cc000b38b15721dbbaf0b8a2b8a62
data/README.md CHANGED
@@ -1,18 +1,28 @@
1
1
  # PhlexKit
2
2
 
3
- A [ruby_ui](https://ruby-ui.com)-style component kit for [Phlex](https://phlex.fun),
4
- styled with **vanilla CSS + design tokens instead of Tailwind**, and built so
5
- [phlex-reactive](https://github.com/mhenrixon/phlex-reactive) is an *optional,
6
- per-component* integration — never a required dependency.
7
-
8
- - **No build step.** Components ship as plain Ruby classes with co-located vanilla
9
- CSS. No Tailwind, no Node, no PostCSS. Assets are precompiled-static in the gem.
10
- - **Theme with CSS custom properties.** Every component reads `--pk-*` tokens via
11
- `var()` + `color-mix()`. Redefine `:root` and the whole kit re-themes live —
12
- including dark/light/system with no rebuild.
13
- - **Reactive when you want it.** Components pass `**attrs` straight through Phlex's
14
- `mix`, so a phlex-reactive `**on(:event)` bundle composes onto the root element
15
- with zero coupling. Non-reactive components never touch phlex-reactive.
3
+ [![Gem Version](https://img.shields.io/gem/v/phlex_kit)](https://rubygems.org/gems/phlex_kit)
4
+ [![CI](https://github.com/MatthewKennedy/phlex_kit/actions/workflows/ci.yml/badge.svg)](https://github.com/MatthewKennedy/phlex_kit/actions/workflows/ci.yml)
5
+
6
+ A [shadcn/ui](https://ui.shadcn.com)-grade component kit for
7
+ [Phlex](https://phlex.fun) + Rails, styled with **vanilla CSS + design tokens
8
+ instead of Tailwind**. The full [ruby_ui](https://ruby-ui.com) catalog plus
9
+ shadcn's own additions 70 component families, 38 Stimulus controllers
10
+ with the default theme lifted verbatim from shadcn/ui's current token system.
11
+
12
+ - **No build step.** Components are plain Ruby classes with co-located vanilla
13
+ CSS, served precompiled-static through Propshaft. No Tailwind, no Node, no
14
+ PostCSS.
15
+ - **The shadcn look, themeable.** Every component reads `--pk-*` custom
16
+ properties. The default palette, radii, and control geometry match
17
+ ui.shadcn.com; redefine `:root` and the whole kit re-themes live — dark,
18
+ light, and system included.
19
+ - **`@hotwired/stimulus` only.** Every interactive component works with one
20
+ registration call. The JS dependencies the upstream kits lean on
21
+ (floating-ui, embla, fuse.js, vaul, Radix, chart.js, …) are all replaced
22
+ with small vanilla equivalents — or, for charts, left to the host.
23
+ - **Reactive when you want it.** Components pass `**attrs` straight through
24
+ Phlex's `mix`, so a [phlex-reactive](https://github.com/mhenrixon/phlex-reactive)
25
+ `**on(:event)` bundle composes onto the root element with zero coupling.
16
26
 
17
27
  ## Install
18
28
 
@@ -28,7 +38,19 @@ bin/rails g phlex_kit:install
28
38
 
29
39
  The installer adds `@import url("phlex_kit/phlex_kit.css");` to your
30
40
  `application.css`, drops `config/initializers/phlex_kit.rb`, and prints the
31
- Stimulus wiring. That's it no Tailwind config, no content globs.
41
+ Stimulus wiring. Then register the controllers once in your Stimulus
42
+ entrypoint:
43
+
44
+ ```js
45
+ // app/javascript/application.js
46
+ import { Application } from "@hotwired/stimulus"
47
+ import { registerPhlexKitControllers } from "phlex_kit/controllers"
48
+
49
+ const application = Application.start()
50
+ registerPhlexKitControllers(application)
51
+ ```
52
+
53
+ That's it — no Tailwind config, no content globs, no bundler.
32
54
 
33
55
  ## Usage
34
56
 
@@ -38,14 +60,41 @@ render PhlexKit::Button.new(variant: :primary, size: :lg) { "Save changes" }
38
60
  render PhlexKit::Card.new do
39
61
  render PhlexKit::CardHeader.new do
40
62
  render PhlexKit::CardTitle.new { "Team" }
63
+ render PhlexKit::CardDescription.new { "Invite and manage members." }
41
64
  end
42
65
  render PhlexKit::CardContent.new { "…" }
43
66
  end
44
67
 
45
- render PhlexKit::Badge.new(variant: :success) { "Live" }
68
+ render PhlexKit::Badge.new(variant: :secondary) { "Live" }
69
+ ```
70
+
71
+ A form field with client-side live validation (fills the error once the
72
+ browser flags the control invalid, clears it as the user types):
73
+
74
+ ```ruby
75
+ render PhlexKit::Form.new(action: "/users", method: "post") do
76
+ render PhlexKit::FormField.new do
77
+ render PhlexKit::FormFieldLabel.new(for: "email") { "Email" }
78
+ render PhlexKit::Input.new(
79
+ type: :email, id: "email", name: "email", required: true,
80
+ data: { value_missing: "Email is required." }
81
+ )
82
+ render PhlexKit::FormFieldError.new
83
+ end
84
+ div(class: "pk-form-actions") do
85
+ render PhlexKit::Button.new(type: :submit) { "Create account" }
86
+ end
87
+ end
88
+ ```
89
+
90
+ A toast, spawned from anywhere (mount `PhlexKit::ToastRegion.new(flash: flash)`
91
+ once at the end of `<body>` — server flash messages render as toasts too):
92
+
93
+ ```js
94
+ PhlexKit.toast.success("Saved", { description: "Your changes are live." })
46
95
  ```
47
96
 
48
- Prefer revue-style `UI::Button`? Turn on the alias in the initializer:
97
+ Prefer `UI::Button`? Turn on the alias in the initializer:
49
98
 
50
99
  ```ruby
51
100
  PhlexKit.configure { |c| c.define_ui_alias = true } # UI == PhlexKit
@@ -53,41 +102,50 @@ PhlexKit.configure { |c| c.define_ui_alias = true } # UI == PhlexKit
53
102
 
54
103
  ## Theming
55
104
 
56
- The gem ships a default dark/light/system token set (`_tokens.css`). Override any
57
- token in your own stylesheet — your app's CSS sorts ahead of the gem's, so you win:
105
+ The gem ships shadcn/ui's default (neutral) token set dark by default, light
106
+ via `<html data-theme="light">`, OS-following via `data-theme="system"`.
107
+ Override any token in your own stylesheet; your app's CSS sorts ahead of the
108
+ gem's, so you win:
58
109
 
59
110
  ```css
60
111
  @import url("phlex_kit/phlex_kit.css");
61
112
 
62
113
  :root {
63
- --pk-brand: #3b5bdb;
64
- --pk-radius: 6px;
114
+ --pk-brand: #3b5bdb; /* primary buttons, selected states, slider fill */
115
+ --pk-radius: 0.375rem; /* every component radius derives from this */
65
116
  }
66
117
  ```
67
118
 
68
- Want a completely custom palette? Delete the `_tokens` import line from your
69
- manifest and define the `--pk-*` properties yourself. Every component has a
70
- literal fallback in `var(--pk-*, …)`, so nothing breaks if a token is missing.
119
+ The full token surface: `--pk-bg`, `--pk-surface`, `--pk-surface-2`,
120
+ `--pk-accent` (hover fills), `--pk-border`, `--pk-input` (control borders),
121
+ `--pk-ring` (focus rings), `--pk-text`, `--pk-text-2`, `--pk-muted`,
122
+ `--pk-brand`, `--pk-brand-ink`, `--pk-green`, `--pk-amber`, `--pk-red`,
123
+ `--pk-chart-1..5`, `--pk-radius`. Want a fully custom palette? Drop the
124
+ `_tokens.css` import and define them all yourself.
71
125
 
72
- ## Interactive components (Stimulus)
126
+ ## Charts
73
127
 
74
- Dialog, Dropdown, Select, and Avatar ship plain Stimulus controllers (no
75
- phlex-reactive needed). Register them once in your Stimulus entrypoint:
128
+ `PhlexKit::Chart` is deliberately a thin wrapper **no charting library is
129
+ bundled**. Expose [Chart.js](https://www.chartjs.org) as `window.Chart` (a
130
+ vendored UMD file and one `javascript_include_tag` is enough) and the kit
131
+ builds the chart with shadcn-style theming: series colored from
132
+ `--pk-chart-1..5`, translucent area fills, hairline grids, re-rendering on
133
+ theme change.
76
134
 
77
- ```js
78
- import { registerPhlexKitControllers } from "phlex_kit/controllers"
79
- registerPhlexKitControllers(application)
135
+ ```ruby
136
+ render PhlexKit::Chart.new(options: {
137
+ type: "line",
138
+ data: { labels: %w[Jan Feb Mar], datasets: [ { label: "Orders", data: [3, 7, 4], fill: true } ] }
139
+ })
80
140
  ```
81
141
 
82
- ## phlex-reactive (optional)
142
+ No `window.Chart`? The controller dispatches `phlex-kit--chart:connect` with
143
+ `{ canvas, options }` so you can drive any other library.
83
144
 
84
- For components that own server-state behavior (live counters, moderation queues,
85
- cross-tab updates), add phlex-reactive and include its mixin in a component:
145
+ ## phlex-reactive (optional)
86
146
 
87
- ```ruby
88
- # Gemfile
89
- gem "phlex-reactive"
90
- ```
147
+ For components that own server-state behavior, add phlex-reactive and include
148
+ its mixin — PhlexKit does **not** depend on it:
91
149
 
92
150
  ```ruby
93
151
  class MyCounter < PhlexKit::BaseComponent
@@ -97,8 +155,7 @@ class MyCounter < PhlexKit::BaseComponent
97
155
  end
98
156
  ```
99
157
 
100
- PhlexKit does **not** depend on phlex-reactive. `PhlexKit.reactive?` auto-detects
101
- it; set `config.reactive` to force it on/off.
158
+ `PhlexKit.reactive?` auto-detects the gem; set `config.reactive` to force it.
102
159
 
103
160
  ## Ejecting components (shadcn-style)
104
161
 
@@ -111,25 +168,54 @@ bin/rails g phlex_kit:component button
111
168
  This copies `button.rb` + `button.css` into `app/components/phlex_kit/button/`
112
169
  and wires its `@import`. Your copy shadows the gem's.
113
170
 
114
- ## How the asset wiring works
171
+ ## The gallery
115
172
 
116
- Three engine initializers reproduce the pattern proven in production (revue):
117
-
118
- 1. `app/components` and the stylesheet dir go on Propshaft's load path so CSS can
119
- sit beside each `.rb`.
120
- 2. Component folders are Zeitwerk-`collapse`d, so `button/button.rb` is
121
- `PhlexKit::Button` (not `PhlexKit::Button::Button`) and `card/card_header.rb`
122
- is `PhlexKit::CardHeader`.
123
- 3. A private-method guard keeps Propshaft from serving Ruby source out of
124
- `public/assets/` (covered by `test/assets/asset_load_path_test.rb`).
173
+ A dummy Rails app renders every component on one page — useful as living
174
+ documentation and for eyeballing theme changes:
125
175
 
126
- Only the `@import url("…")` form is fingerprinted by Propshaft — a bare
127
- `@import "…"` ships un-digested and 404s. The manifest always uses `url()`.
176
+ ```bash
177
+ git clone https://github.com/MatthewKennedy/phlex_kit && cd phlex_kit
178
+ bundle install
179
+ bundle exec puma -p 3999 test/dummy/config.ru
180
+ # open http://127.0.0.1:3999
181
+ ```
128
182
 
129
183
  ## Components
130
184
 
131
- See [ROADMAP.md](ROADMAP.md) for the full inventory and porting status.
185
+ Everything in ruby_ui (53/53) plus shadcn/ui's own catalog: accordion, alert,
186
+ alert dialog, aspect ratio, attachment, avatar (+ group), badge, breadcrumb,
187
+ bubble, button, button group, calendar, card, carousel, chart, checkbox,
188
+ clipboard, codeblock, collapsible, combobox (button/input/badge-chip
189
+ triggers), command palette, context menu, data table, date picker, dialog,
190
+ drawer, dropdown menu, empty, form + form field, hover card, input, input
191
+ group, input OTP, item, kbd, label, link, masked input, menubar, message,
192
+ message scroller, native select, navigation menu, pagination, popover,
193
+ progress, radio button + radio group, resizable, scroll area, select,
194
+ separator, sheet, shortcut key, sidebar, skeleton, slider, spinner, stars,
195
+ switch, table, tabs, textarea, theme toggle, toast (sonner-style), toggle,
196
+ toggle group, tooltip, typography.
197
+
198
+ Inventory and porting notes: [ROADMAP.md](ROADMAP.md). Architecture and
199
+ conventions: [docs/](docs/).
200
+
201
+ ## How the asset wiring works
202
+
203
+ Four engine initializers make the zero-build story hold:
204
+
205
+ 1. `app/components`, the stylesheet dir, and `app/javascript` go on
206
+ Propshaft's load path, so CSS sits beside each `.rb` and the importmap pins
207
+ resolve.
208
+ 2. Component folders are Zeitwerk-`collapse`d, so `button/button.rb` is
209
+ `PhlexKit::Button` and `card/card_header.rb` is `PhlexKit::CardHeader`.
210
+ 3. A guard keeps Propshaft from serving Ruby source out of `public/assets/`.
211
+ 4. The gem's importmap (pinning every controller) is appended to the host's.
212
+
213
+ Manifest imports use the `@import url("…")` form (Propshaft only fingerprints
214
+ `url()`) with paths relative to the manifest's own directory — both guarded by
215
+ tests.
132
216
 
133
217
  ## License
134
218
 
135
- MIT.
219
+ MIT. Component design ported from [ruby_ui](https://github.com/ruby-ui/ruby_ui)
220
+ and [shadcn/ui](https://ui.shadcn.com) (both MIT), with attribution comments
221
+ retained per component.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PhlexKit
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phlex_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Kennedy