kiso 0.1.0.pre → 0.1.1.pre
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 +4 -4
- data/CHANGELOG.md +25 -2
- data/README.md +69 -27
- data/Rakefile +8 -0
- data/app/assets/tailwind/kiso/checkbox.css +18 -0
- data/app/assets/tailwind/kiso/color-mode.css +9 -0
- data/app/assets/tailwind/kiso/dashboard.css +176 -0
- data/app/assets/tailwind/kiso/engine.css +103 -0
- data/app/assets/tailwind/kiso/radio-group.css +17 -0
- data/app/helpers/kiso/component_helper.rb +46 -27
- data/app/helpers/kiso/icon_helper.rb +53 -9
- data/app/helpers/kiso/theme_helper.rb +38 -0
- data/app/javascript/controllers/kiso/combobox_controller.js +616 -0
- data/app/javascript/controllers/kiso/command_controller.js +184 -0
- data/app/javascript/controllers/kiso/command_dialog_controller.js +104 -0
- data/app/javascript/controllers/kiso/dropdown_menu_controller.js +684 -0
- data/app/javascript/controllers/kiso/index.d.ts +12 -0
- data/app/javascript/controllers/kiso/index.js +39 -0
- data/app/javascript/controllers/kiso/popover_controller.js +254 -0
- data/app/javascript/controllers/kiso/select_controller.js +307 -0
- data/app/javascript/controllers/kiso/sidebar_controller.js +84 -0
- data/app/javascript/controllers/kiso/theme_controller.js +89 -0
- data/app/javascript/controllers/kiso/toggle_controller.js +24 -0
- data/app/javascript/controllers/kiso/toggle_group_controller.js +128 -0
- data/app/javascript/kiso/utils/focusable.js +8 -0
- data/app/javascript/kiso/utils/highlight.js +43 -0
- data/app/javascript/kiso/utils/positioning.js +86 -0
- data/app/javascript/kiso/vendor/floating-ui-core.js +1 -0
- data/app/javascript/kiso/vendor/floating-ui-dom.js +1 -0
- data/app/views/kiso/components/_alert.html.erb +1 -1
- data/app/views/kiso/components/_avatar.html.erb +23 -0
- data/app/views/kiso/components/_badge.html.erb +1 -1
- data/app/views/kiso/components/_breadcrumb.html.erb +8 -0
- data/app/views/kiso/components/_button.html.erb +1 -1
- data/app/views/kiso/components/_card.html.erb +1 -1
- data/app/views/kiso/components/_checkbox.html.erb +7 -0
- data/app/views/kiso/components/_color_mode_button.html.erb +14 -0
- data/app/views/kiso/components/_color_mode_select.html.erb +24 -0
- data/app/views/kiso/components/_combobox.html.erb +12 -0
- data/app/views/kiso/components/_command.html.erb +7 -0
- data/app/views/kiso/components/_dashboard_group.html.erb +14 -0
- data/app/views/kiso/components/_dashboard_navbar.html.erb +7 -0
- data/app/views/kiso/components/_dashboard_panel.html.erb +7 -0
- data/app/views/kiso/components/_dashboard_sidebar.html.erb +11 -0
- data/app/views/kiso/components/_dashboard_toolbar.html.erb +7 -0
- data/app/views/kiso/components/_dropdown_menu.html.erb +7 -0
- data/app/views/kiso/components/{_empty_state.html.erb → _empty.html.erb} +2 -2
- data/app/views/kiso/components/_field.html.erb +12 -0
- data/app/views/kiso/components/_field_group.html.erb +7 -0
- data/app/views/kiso/components/_field_set.html.erb +7 -0
- data/app/views/kiso/components/_input.html.erb +8 -0
- data/app/views/kiso/components/_input_group.html.erb +8 -0
- data/app/views/kiso/components/_kbd.html.erb +7 -0
- data/app/views/kiso/components/_label.html.erb +5 -0
- data/app/views/kiso/components/_nav.html.erb +7 -0
- data/app/views/kiso/components/_pagination.html.erb +9 -0
- data/app/views/kiso/components/_popover.html.erb +8 -0
- data/app/views/kiso/components/_radio_group.html.erb +8 -0
- data/app/views/kiso/components/_select.html.erb +8 -0
- data/app/views/kiso/components/_separator.html.erb +1 -1
- data/app/views/kiso/components/_stats_card.html.erb +1 -1
- data/app/views/kiso/components/_stats_grid.html.erb +1 -1
- data/app/views/kiso/components/_switch.html.erb +10 -0
- data/app/views/kiso/components/_table.html.erb +2 -1
- data/app/views/kiso/components/_textarea.html.erb +9 -0
- data/app/views/kiso/components/_toggle.html.erb +12 -0
- data/app/views/kiso/components/_toggle_group.html.erb +12 -0
- data/app/views/kiso/components/alert/_description.html.erb +1 -1
- data/app/views/kiso/components/alert/_title.html.erb +1 -1
- data/app/views/kiso/components/avatar/_badge.html.erb +7 -0
- data/app/views/kiso/components/avatar/_fallback.html.erb +7 -0
- data/app/views/kiso/components/avatar/_group.html.erb +7 -0
- data/app/views/kiso/components/avatar/_group_count.html.erb +7 -0
- data/app/views/kiso/components/avatar/_image.html.erb +6 -0
- data/app/views/kiso/components/breadcrumb/_ellipsis.html.erb +10 -0
- data/app/views/kiso/components/breadcrumb/_item.html.erb +7 -0
- data/app/views/kiso/components/breadcrumb/_link.html.erb +7 -0
- data/app/views/kiso/components/breadcrumb/_list.html.erb +7 -0
- data/app/views/kiso/components/breadcrumb/_page.html.erb +9 -0
- data/app/views/kiso/components/breadcrumb/_separator.html.erb +9 -0
- data/app/views/kiso/components/card/_action.html.erb +7 -0
- data/app/views/kiso/components/card/_content.html.erb +1 -1
- data/app/views/kiso/components/card/_description.html.erb +1 -1
- data/app/views/kiso/components/card/_footer.html.erb +1 -1
- data/app/views/kiso/components/card/_header.html.erb +1 -1
- data/app/views/kiso/components/card/_title.html.erb +1 -1
- data/app/views/kiso/components/combobox/_chip.html.erb +19 -0
- data/app/views/kiso/components/combobox/_chips.html.erb +20 -0
- data/app/views/kiso/components/combobox/_chips_input.html.erb +10 -0
- data/app/views/kiso/components/combobox/_content.html.erb +9 -0
- data/app/views/kiso/components/combobox/_empty.html.erb +9 -0
- data/app/views/kiso/components/combobox/_group.html.erb +8 -0
- data/app/views/kiso/components/combobox/_input.html.erb +23 -0
- data/app/views/kiso/components/combobox/_item.html.erb +19 -0
- data/app/views/kiso/components/combobox/_label.html.erb +7 -0
- data/app/views/kiso/components/combobox/_list.html.erb +10 -0
- data/app/views/kiso/components/combobox/_separator.html.erb +6 -0
- data/app/views/kiso/components/command/_dialog.html.erb +11 -0
- data/app/views/kiso/components/command/_empty.html.erb +9 -0
- data/app/views/kiso/components/command/_group.html.erb +14 -0
- data/app/views/kiso/components/command/_input.html.erb +16 -0
- data/app/views/kiso/components/command/_item.html.erb +13 -0
- data/app/views/kiso/components/command/_list.html.erb +10 -0
- data/app/views/kiso/components/command/_separator.html.erb +7 -0
- data/app/views/kiso/components/command/_shortcut.html.erb +7 -0
- data/app/views/kiso/components/dashboard_navbar/_toggle.html.erb +11 -0
- data/app/views/kiso/components/dashboard_sidebar/_collapse.html.erb +12 -0
- data/app/views/kiso/components/dashboard_sidebar/_footer.html.erb +7 -0
- data/app/views/kiso/components/dashboard_sidebar/_header.html.erb +7 -0
- data/app/views/kiso/components/dashboard_sidebar/_toggle.html.erb +11 -0
- data/app/views/kiso/components/dashboard_toolbar/_left.html.erb +7 -0
- data/app/views/kiso/components/dashboard_toolbar/_right.html.erb +7 -0
- data/app/views/kiso/components/dropdown_menu/_checkbox_item.html.erb +18 -0
- data/app/views/kiso/components/dropdown_menu/_content.html.erb +10 -0
- data/app/views/kiso/components/dropdown_menu/_group.html.erb +8 -0
- data/app/views/kiso/components/dropdown_menu/_item.html.erb +15 -0
- data/app/views/kiso/components/dropdown_menu/_label.html.erb +8 -0
- data/app/views/kiso/components/dropdown_menu/_radio_group.html.erb +10 -0
- data/app/views/kiso/components/dropdown_menu/_radio_item.html.erb +19 -0
- data/app/views/kiso/components/dropdown_menu/_separator.html.erb +6 -0
- data/app/views/kiso/components/dropdown_menu/_shortcut.html.erb +7 -0
- data/app/views/kiso/components/dropdown_menu/_sub.html.erb +8 -0
- data/app/views/kiso/components/dropdown_menu/_sub_content.html.erb +10 -0
- data/app/views/kiso/components/dropdown_menu/_sub_trigger.html.erb +12 -0
- data/app/views/kiso/components/dropdown_menu/_trigger.html.erb +9 -0
- data/app/views/kiso/components/empty/_content.html.erb +7 -0
- data/app/views/kiso/components/empty/_description.html.erb +7 -0
- data/app/views/kiso/components/empty/_header.html.erb +7 -0
- data/app/views/kiso/components/empty/_media.html.erb +7 -0
- data/app/views/kiso/components/empty/_title.html.erb +7 -0
- data/app/views/kiso/components/field/_content.html.erb +7 -0
- data/app/views/kiso/components/field/_description.html.erb +7 -0
- data/app/views/kiso/components/field/_error.html.erb +22 -0
- data/app/views/kiso/components/field/_label.html.erb +5 -0
- data/app/views/kiso/components/field/_separator.html.erb +15 -0
- data/app/views/kiso/components/field/_title.html.erb +7 -0
- data/app/views/kiso/components/field_set/_legend.html.erb +9 -0
- data/app/views/kiso/components/input_group/_addon.html.erb +7 -0
- data/app/views/kiso/components/kbd/_group.html.erb +7 -0
- data/app/views/kiso/components/nav/_item.html.erb +15 -0
- data/app/views/kiso/components/nav/_section.html.erb +37 -0
- data/app/views/kiso/components/nav/_section_title.html.erb +7 -0
- data/app/views/kiso/components/pagination/_content.html.erb +7 -0
- data/app/views/kiso/components/pagination/_ellipsis.html.erb +9 -0
- data/app/views/kiso/components/pagination/_item.html.erb +7 -0
- data/app/views/kiso/components/pagination/_link.html.erb +9 -0
- data/app/views/kiso/components/pagination/_next.html.erb +12 -0
- data/app/views/kiso/components/pagination/_previous.html.erb +12 -0
- data/app/views/kiso/components/popover/_anchor.html.erb +8 -0
- data/app/views/kiso/components/popover/_content.html.erb +11 -0
- data/app/views/kiso/components/popover/_description.html.erb +7 -0
- data/app/views/kiso/components/popover/_header.html.erb +7 -0
- data/app/views/kiso/components/popover/_title.html.erb +7 -0
- data/app/views/kiso/components/popover/_trigger.html.erb +9 -0
- data/app/views/kiso/components/radio_group/_item.html.erb +6 -0
- data/app/views/kiso/components/select/_content.html.erb +10 -0
- data/app/views/kiso/components/select/_group.html.erb +8 -0
- data/app/views/kiso/components/select/_item.html.erb +19 -0
- data/app/views/kiso/components/select/_label.html.erb +7 -0
- data/app/views/kiso/components/select/_separator.html.erb +6 -0
- data/app/views/kiso/components/select/_trigger.html.erb +13 -0
- data/app/views/kiso/components/select/_value.html.erb +11 -0
- data/app/views/kiso/components/stats_card/_description.html.erb +1 -1
- data/app/views/kiso/components/stats_card/_header.html.erb +1 -1
- data/app/views/kiso/components/stats_card/_label.html.erb +1 -1
- data/app/views/kiso/components/stats_card/_value.html.erb +1 -1
- data/app/views/kiso/components/table/_body.html.erb +1 -1
- data/app/views/kiso/components/table/_caption.html.erb +1 -1
- data/app/views/kiso/components/table/_cell.html.erb +1 -1
- data/app/views/kiso/components/table/_footer.html.erb +1 -1
- data/app/views/kiso/components/table/_head.html.erb +1 -1
- data/app/views/kiso/components/table/_header.html.erb +1 -1
- data/app/views/kiso/components/table/_row.html.erb +1 -1
- data/app/views/kiso/components/toggle_group/_item.html.erb +13 -0
- data/config/deploy.docs.yml +31 -0
- data/config/deploy.yml +34 -0
- data/config/importmap.rb +10 -0
- data/lib/kiso/cli/base.rb +15 -0
- data/lib/kiso/cli/icons.rb +2 -1
- data/lib/kiso/cli/main.rb +6 -0
- data/lib/kiso/cli/make.rb +22 -12
- data/lib/kiso/configuration.rb +53 -0
- data/lib/kiso/engine.rb +36 -1
- data/lib/kiso/theme_overrides.rb +130 -0
- data/lib/kiso/themes/alert.rb +16 -1
- data/lib/kiso/themes/avatar.rb +53 -0
- data/lib/kiso/themes/badge.rb +15 -5
- data/lib/kiso/themes/breadcrumb.rb +44 -0
- data/lib/kiso/themes/button.rb +15 -2
- data/lib/kiso/themes/card.rb +18 -2
- data/lib/kiso/themes/checkbox.rb +33 -0
- data/lib/kiso/themes/color_mode_button.rb +15 -0
- data/lib/kiso/themes/color_mode_select.rb +7 -0
- data/lib/kiso/themes/combobox.rb +97 -0
- data/lib/kiso/themes/command.rb +79 -0
- data/lib/kiso/themes/dashboard.rb +51 -0
- data/lib/kiso/themes/dropdown_menu.rb +108 -0
- data/lib/kiso/themes/empty.rb +54 -0
- data/lib/kiso/themes/field.rb +76 -0
- data/lib/kiso/themes/field_group.rb +15 -0
- data/lib/kiso/themes/field_set.rb +32 -0
- data/lib/kiso/themes/input.rb +33 -0
- data/lib/kiso/themes/input_group.rb +39 -0
- data/lib/kiso/themes/kbd.rb +31 -0
- data/lib/kiso/themes/label.rb +16 -0
- data/lib/kiso/themes/nav.rb +27 -0
- data/lib/kiso/themes/pagination.rb +73 -0
- data/lib/kiso/themes/popover.rb +32 -0
- data/lib/kiso/themes/radio_group.rb +43 -0
- data/lib/kiso/themes/select.rb +78 -0
- data/lib/kiso/themes/separator.rb +8 -2
- data/lib/kiso/themes/shared.rb +51 -0
- data/lib/kiso/themes/stats_card.rb +26 -14
- data/lib/kiso/themes/switch.rb +56 -0
- data/lib/kiso/themes/table.rb +18 -15
- data/lib/kiso/themes/textarea.rb +33 -0
- data/lib/kiso/themes/toggle.rb +71 -0
- data/lib/kiso/themes/toggle_group.rb +13 -0
- data/lib/kiso/version.rb +4 -1
- data/lib/kiso.rb +68 -2
- metadata +174 -22
- data/app/views/kiso/components/empty_state/_content.html.erb +0 -7
- data/app/views/kiso/components/empty_state/_description.html.erb +0 -7
- data/app/views/kiso/components/empty_state/_header.html.erb +0 -7
- data/app/views/kiso/components/empty_state/_media.html.erb +0 -7
- data/app/views/kiso/components/empty_state/_title.html.erb +0 -7
- data/lib/kiso/themes/empty_state.rb +0 -42
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bda2256a79d7581462417a394433826ba6289cdab8f7f6bc04fbc451ee929478
|
|
4
|
+
data.tar.gz: a444b9108f532af991b690f8620faa3019639b533d9fd6ccda9f1aabca3b4540
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1cc8613ffb244b57a7499bcb4b4f7e4c3ec2c3c9feb8b8e6235cb55c9288cf0ea40261598424e33c221055577a0d8eeb9ec229aa18e9e0fcb20796551d5985c7
|
|
7
|
+
data.tar.gz: 93f2dee31a6a6526b7d6548b394a37eaa6ccca2bed6fa47b331664bfcb9a233bb466e41f9b5d4d1cdb8a029dcf85a46ddfb9286cb304165dc3420e7bcabd5ac3
|
data/CHANGELOG.md
CHANGED
|
@@ -7,11 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.1.pre] - 2026-03-03
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Dashboard layout system — sidebar, navbar, panel, toolbar, and nav components with cookie-persisted sidebar state
|
|
15
|
+
- Avatar component with image, fallback, badge, and group support
|
|
16
|
+
- Form components — Field, Label, Input, Textarea, InputGroup, Checkbox, RadioGroup, Switch, Select, Combobox
|
|
17
|
+
- Overlay components — Popover, DropdownMenu, Command palette
|
|
18
|
+
- Navigation components — Breadcrumb, Pagination
|
|
19
|
+
- Element components — Kbd, Toggle, ToggleGroup
|
|
20
|
+
- Dark mode system — `kiso_theme_script` helper, ColorModeButton, ColorModeSelect
|
|
21
|
+
- Floating UI positioning for popovers and dropdowns
|
|
22
|
+
- Global theme overrides via `Kiso.configure`
|
|
23
|
+
- Configurable default icons via `kiso_component_icon`
|
|
24
|
+
- Getting Started guide
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Renamed `kiso()` helper to `kui()` to avoid Rails route proxy collision
|
|
29
|
+
- Renamed `empty_state` to `empty` to match shadcn naming
|
|
30
|
+
- Adopted `data-slot` convention from shadcn v4
|
|
31
|
+
|
|
10
32
|
## [0.1.0.pre] - 2026-02-25
|
|
11
33
|
|
|
12
34
|
### Added
|
|
13
35
|
|
|
14
|
-
- Core engine with `
|
|
36
|
+
- Core engine with `kui()` component helper and `kiso_prepare_options` builder
|
|
15
37
|
- `class_variants` + `tailwind_merge` integration for variant definitions
|
|
16
38
|
- Theme CSS with 7 palettes, surface tokens, and dark mode
|
|
17
39
|
- Badge component (color × variant × size, pill shape, SVG handling)
|
|
@@ -23,5 +45,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
23
45
|
- Lookbook component previews
|
|
24
46
|
- Bridgetown documentation site
|
|
25
47
|
|
|
26
|
-
[Unreleased]: https://github.com/steveclarke/kiso/compare/v0.1.
|
|
48
|
+
[Unreleased]: https://github.com/steveclarke/kiso/compare/v0.1.1.pre...HEAD
|
|
49
|
+
[0.1.1.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.1.1.pre
|
|
27
50
|
[0.1.0.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.1.0.pre
|
data/README.md
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
UI components for Rails. Built on ERB, Tailwind CSS, and Hotwire.
|
|
4
4
|
|
|
5
|
-
Add one gem and get badges, buttons, cards, alerts, and more. They all work with screen readers and dark mode.
|
|
5
|
+
Add one gem and get badges, buttons, cards, alerts, and more. They all work with screen readers and dark mode.
|
|
6
6
|
|
|
7
7
|
No React. No extra build step. Just ERB with [class_variants](https://github.com/avo-hq/class_variants) for styling.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
> [!WARNING]
|
|
10
|
+
> Kiso is in early development and **not ready for production use**. The gem is published to reserve the name on RubyGems. APIs, component names, and theme tokens will change without notice. Watch the repo or check back in a few weeks.
|
|
10
11
|
|
|
11
|
-
##
|
|
12
|
+
## Getting started
|
|
13
|
+
|
|
14
|
+
Add the gem to your Gemfile and bundle:
|
|
12
15
|
|
|
13
16
|
```ruby
|
|
14
17
|
# Gemfile
|
|
@@ -17,36 +20,70 @@ gem "kiso"
|
|
|
17
20
|
|
|
18
21
|
```bash
|
|
19
22
|
bundle install
|
|
20
|
-
bin/rails generate kiso:install
|
|
21
23
|
```
|
|
22
24
|
|
|
25
|
+
Then add one import to your Tailwind CSS entrypoint:
|
|
26
|
+
|
|
27
|
+
```css
|
|
28
|
+
/* app/assets/tailwind/application.css */
|
|
29
|
+
@import "../builds/tailwind/kiso.css";
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
And add the dark mode helper to your layout's `<head>`:
|
|
33
|
+
|
|
34
|
+
```erb
|
|
35
|
+
<head>
|
|
36
|
+
<%= kiso_theme_script %>
|
|
37
|
+
<%= stylesheet_link_tag "tailwind" %>
|
|
38
|
+
<%= javascript_importmap_tags %>
|
|
39
|
+
</head>
|
|
40
|
+
|
|
41
|
+
<body class="bg-background text-foreground antialiased">
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
That's it. Helpers, importmap pins, asset paths, and dark mode tokens are all
|
|
45
|
+
wired up automatically by the engine. See the
|
|
46
|
+
[Getting Started guide](https://kisoui.com/getting-started) for the full
|
|
47
|
+
walkthrough.
|
|
48
|
+
|
|
49
|
+
### Bundler apps (esbuild, Vite, Bun)
|
|
50
|
+
|
|
51
|
+
If your app uses a JS bundler instead of importmaps, also install the npm
|
|
52
|
+
package for Stimulus controllers:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install kiso-ui
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
// app/javascript/controllers/index.js
|
|
60
|
+
import KisoUi from "kiso-ui"
|
|
61
|
+
KisoUi.start(application)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Importmap apps get Stimulus controllers automatically — no npm install needed.
|
|
65
|
+
|
|
23
66
|
## Usage
|
|
24
67
|
|
|
25
|
-
Use the `
|
|
68
|
+
Use the `kui()` helper to render components:
|
|
26
69
|
|
|
27
70
|
```erb
|
|
28
|
-
<%=
|
|
71
|
+
<%= kui(:badge, color: :primary) { "Active" } %>
|
|
29
72
|
```
|
|
30
73
|
|
|
31
74
|
Components are made of small parts. A card has a header, title, content, and footer:
|
|
32
75
|
|
|
33
76
|
```erb
|
|
34
|
-
<%=
|
|
35
|
-
<%=
|
|
36
|
-
<%=
|
|
77
|
+
<%= kui(:card) do %>
|
|
78
|
+
<%= kui(:card, :header) do %>
|
|
79
|
+
<%= kui(:card, :title, text: "Members") %>
|
|
37
80
|
<% end %>
|
|
38
|
-
<%=
|
|
81
|
+
<%= kui(:card, :content) do %>
|
|
39
82
|
...
|
|
40
83
|
<% end %>
|
|
41
84
|
<% end %>
|
|
42
85
|
```
|
|
43
86
|
|
|
44
|
-
Data attributes work on any HTML element too:
|
|
45
|
-
|
|
46
|
-
```erb
|
|
47
|
-
<%= f.submit "Save", data: { component: "button", variant: "primary" } %>
|
|
48
|
-
```
|
|
49
|
-
|
|
50
87
|
## How it works
|
|
51
88
|
|
|
52
89
|
Each component has two parts:
|
|
@@ -56,6 +93,10 @@ Each component has two parts:
|
|
|
56
93
|
|
|
57
94
|
Colors use tokens like `bg-primary` and `text-muted`. They switch on their own in dark mode. No `dark:` classes needed.
|
|
58
95
|
|
|
96
|
+
## Design system
|
|
97
|
+
|
|
98
|
+
Kiso follows a strict spatial system — consistent heights, padding, gaps, typography, border radius, and icon sizing across every component. See the [Design System](https://kisoui.com/design-system) page for the visual reference.
|
|
99
|
+
|
|
59
100
|
## Design principles
|
|
60
101
|
|
|
61
102
|
1. **Native HTML first.** Use `<dialog>`, `[popover]`, `<details>` before adding JavaScript.
|
|
@@ -79,11 +120,14 @@ This starts [Lookbook](https://lookbook.build) on port 4001 with a Tailwind watc
|
|
|
79
120
|
|
|
80
121
|
Cloned without `--recurse-submodules`? Run `bin/vendor init` to fetch the vendor repos.
|
|
81
122
|
|
|
82
|
-
Run tests:
|
|
123
|
+
Run tests and lint:
|
|
83
124
|
|
|
84
125
|
```bash
|
|
85
|
-
bundle exec rake test #
|
|
86
|
-
|
|
126
|
+
bundle exec rake test # Ruby tests
|
|
127
|
+
npm run test:unit # JS unit tests (Vitest)
|
|
128
|
+
npm run test:e2e # E2E tests (Playwright, needs bin/dev)
|
|
129
|
+
bundle exec standardrb # Ruby lint
|
|
130
|
+
npm run lint && npm run fmt:check # JS lint + format check
|
|
87
131
|
```
|
|
88
132
|
|
|
89
133
|
See [CONTRIBUTING.md](CONTRIBUTING.md) to help out.
|
|
@@ -93,12 +137,10 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) to help out.
|
|
|
93
137
|
```
|
|
94
138
|
app/views/kiso/components/ ERB partials
|
|
95
139
|
lib/kiso/themes/ Theme files (class_variants)
|
|
96
|
-
app/
|
|
97
|
-
app/
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
vendor/shadcn-ui/ Layout reference (git submodule)
|
|
101
|
-
vendor/nuxt-ui/ Theme reference (git submodule)
|
|
140
|
+
app/javascript/controllers/ Stimulus controllers (also shipped via npm as kiso-ui)
|
|
141
|
+
app/helpers/kiso/ kui(), kiso_prepare_options() helpers
|
|
142
|
+
app/assets/tailwind/kiso/ CSS (only transitions and pseudo-states)
|
|
143
|
+
lookbook/ Lookbook dev app (previews on port 4001)
|
|
102
144
|
docs/ Docs site (Bridgetown)
|
|
103
145
|
```
|
|
104
146
|
|
|
@@ -106,11 +148,11 @@ docs/ Docs site (Bridgetown)
|
|
|
106
148
|
|
|
107
149
|
- Ruby >= 3.3
|
|
108
150
|
- Rails >= 8.0
|
|
109
|
-
- [tailwindcss-rails](https://github.com/rails/tailwindcss-rails)
|
|
151
|
+
- A Tailwind CSS build pipeline ([tailwindcss-rails](https://github.com/rails/tailwindcss-rails) or [cssbundling-rails](https://github.com/rails/cssbundling-rails))
|
|
110
152
|
|
|
111
153
|
## Status
|
|
112
154
|
|
|
113
|
-
Early development.
|
|
155
|
+
Early development. APIs, component names, and theme tokens may change.
|
|
114
156
|
|
|
115
157
|
## License
|
|
116
158
|
|
data/Rakefile
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
require "bundler/setup"
|
|
2
2
|
require "bundler/gem_tasks"
|
|
3
|
+
require "rake/testtask"
|
|
3
4
|
|
|
4
5
|
APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
|
|
5
6
|
load "rails/tasks/engine.rake"
|
|
7
|
+
|
|
8
|
+
Rake::TestTask.new(:test) do |t|
|
|
9
|
+
t.libs << "test"
|
|
10
|
+
t.pattern = "test/**/*_test.rb"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
task default: :test
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/* Checkbox indicator — CSS ::after for the checkmark since native <input>
|
|
2
|
+
can't contain child elements. Uses mask-image with the Lucide Check icon. */
|
|
3
|
+
|
|
4
|
+
[data-component="checkbox"] {
|
|
5
|
+
display: grid;
|
|
6
|
+
place-content: center;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
[data-component="checkbox"]:checked::after {
|
|
10
|
+
content: '';
|
|
11
|
+
width: 0.875em;
|
|
12
|
+
height: 0.875em;
|
|
13
|
+
background-color: currentColor;
|
|
14
|
+
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
|
|
15
|
+
mask-size: contain;
|
|
16
|
+
mask-repeat: no-repeat;
|
|
17
|
+
mask-position: center;
|
|
18
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* ── Color Mode Components ────────────────────────────────────────────────────
|
|
2
|
+
Icon visibility for the color mode button. The .dark class on <html> drives
|
|
3
|
+
which icon is shown — sun in light mode, moon in dark mode. */
|
|
4
|
+
|
|
5
|
+
@layer components {
|
|
6
|
+
[data-slot="color-mode-icon-dark"] { display: none; }
|
|
7
|
+
.dark [data-slot="color-mode-icon-light"] { display: none; }
|
|
8
|
+
.dark [data-slot="color-mode-icon-dark"] { display: inline-block; }
|
|
9
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/* ── Kiso Dashboard Layout ────────────────────────────────────────────────────
|
|
2
|
+
Tokens and mechanics for the full-screen sidebar + topbar dashboard shell.
|
|
3
|
+
Bundled with the engine — all apps get these tokens and layout rules.
|
|
4
|
+
|
|
5
|
+
Host apps can override any token in their own @theme block:
|
|
6
|
+
@theme { --sidebar-width: 18rem; }
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/* ── Tokens ──────────────────────────────────────────────────────────────── */
|
|
10
|
+
|
|
11
|
+
@theme {
|
|
12
|
+
/* Sidebar geometry */
|
|
13
|
+
--sidebar-width: 16rem;
|
|
14
|
+
|
|
15
|
+
/* Layout heights */
|
|
16
|
+
--topbar-height: 3.5rem;
|
|
17
|
+
|
|
18
|
+
/* Sidebar surface tokens (light mode defaults) */
|
|
19
|
+
--sidebar-background: var(--color-white);
|
|
20
|
+
--sidebar-foreground: var(--color-zinc-900);
|
|
21
|
+
--sidebar-border: var(--color-zinc-200);
|
|
22
|
+
--sidebar-accent: var(--color-zinc-100);
|
|
23
|
+
--sidebar-accent-foreground: var(--color-zinc-700);
|
|
24
|
+
|
|
25
|
+
/* Animation */
|
|
26
|
+
--sidebar-duration: 220ms;
|
|
27
|
+
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
|
|
28
|
+
|
|
29
|
+
/* Z-index stack */
|
|
30
|
+
--z-topbar: 30;
|
|
31
|
+
--z-sidebar: 40;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Dark mode sidebar token overrides */
|
|
35
|
+
.dark {
|
|
36
|
+
--sidebar-background: var(--color-zinc-950);
|
|
37
|
+
--sidebar-foreground: var(--color-zinc-100);
|
|
38
|
+
--sidebar-border: var(--color-zinc-800);
|
|
39
|
+
--sidebar-accent: var(--color-zinc-800);
|
|
40
|
+
--sidebar-accent-foreground: var(--color-zinc-300);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* ── Layout mechanics ─────────────────────────────────────────────────────── */
|
|
44
|
+
|
|
45
|
+
@layer components {
|
|
46
|
+
/* Drive --sidebar-current-width from the data attribute set by sidebar controller */
|
|
47
|
+
[data-sidebar-open="true"] { --sidebar-current-width: var(--sidebar-width); }
|
|
48
|
+
[data-sidebar-open="false"] { --sidebar-current-width: 0rem; }
|
|
49
|
+
|
|
50
|
+
/* Hide sidebar border when collapsed to prevent ghost border at 0 width */
|
|
51
|
+
[data-sidebar-open="false"] [data-slot="dashboard-sidebar"] {
|
|
52
|
+
border-right-width: 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Flat 2×2 grid: topbar row + sidebar/panel row */
|
|
56
|
+
[data-slot="dashboard-group"] {
|
|
57
|
+
grid-template-rows: var(--topbar-height) 1fr;
|
|
58
|
+
grid-template-columns: var(--sidebar-current-width) 1fr;
|
|
59
|
+
transition: grid-template-columns var(--sidebar-duration) var(--ease-out-expo);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Topbar spans panel column only (sidebar owns full height) */
|
|
63
|
+
[data-slot="dashboard-navbar"] {
|
|
64
|
+
grid-column: 2;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
Sidebar: spans full height (both grid rows). background-color and
|
|
69
|
+
border-right-color are set here (not via Tailwind arbitrary classes)
|
|
70
|
+
because bg-[--css-var] classes don't generate reliably.
|
|
71
|
+
*/
|
|
72
|
+
[data-slot="dashboard-sidebar"] {
|
|
73
|
+
grid-row: 1 / -1;
|
|
74
|
+
background-color: var(--sidebar-background);
|
|
75
|
+
border-right: 1px solid var(--sidebar-border);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* Sidebar header: matches topbar height, bottom border */
|
|
79
|
+
[data-slot="dashboard-sidebar-header"] {
|
|
80
|
+
height: var(--topbar-height);
|
|
81
|
+
border-bottom: 1px solid var(--sidebar-border);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Sidebar footer: top border */
|
|
85
|
+
[data-slot="dashboard-sidebar-footer"] {
|
|
86
|
+
border-top: 1px solid var(--sidebar-border);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Inner nav: always sidebar-width, flex column for header/nav/footer layout */
|
|
90
|
+
[data-slot="dashboard-sidebar-inner"] {
|
|
91
|
+
width: var(--sidebar-width);
|
|
92
|
+
height: 100%;
|
|
93
|
+
overflow: hidden;
|
|
94
|
+
display: flex;
|
|
95
|
+
flex-direction: column;
|
|
96
|
+
color: var(--sidebar-foreground);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Panel: row 2, col 2 */
|
|
100
|
+
[data-slot="dashboard-panel"] {
|
|
101
|
+
grid-column: 2;
|
|
102
|
+
grid-row: 2;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* ── Navbar layout variant: navbar spans full width, sidebar below ────── */
|
|
106
|
+
[data-layout="navbar"] [data-slot="dashboard-navbar"] {
|
|
107
|
+
grid-column: 1 / -1;
|
|
108
|
+
}
|
|
109
|
+
[data-layout="navbar"] [data-slot="dashboard-sidebar"] {
|
|
110
|
+
grid-row: auto;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* Scrim: hidden on desktop */
|
|
114
|
+
[data-slot="dashboard-scrim"] { display: none; }
|
|
115
|
+
|
|
116
|
+
/* ── Collapse button icon switching ────────────────────────────────────── */
|
|
117
|
+
[data-sidebar-open="true"] [data-slot="collapse-icon-open"] { display: inline; }
|
|
118
|
+
[data-sidebar-open="true"] [data-slot="collapse-icon-closed"] { display: none; }
|
|
119
|
+
[data-sidebar-open="false"] [data-slot="collapse-icon-open"] { display: none; }
|
|
120
|
+
[data-sidebar-open="false"] [data-slot="collapse-icon-closed"] { display: inline; }
|
|
121
|
+
|
|
122
|
+
/* ── Nav section (details/summary) ───────────────────────────────────── */
|
|
123
|
+
[data-slot="nav-section-chevron"] {
|
|
124
|
+
transition: transform 200ms ease;
|
|
125
|
+
}
|
|
126
|
+
[data-slot="nav-section"][open] [data-slot="nav-section-chevron"] {
|
|
127
|
+
transform: rotate(180deg);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* ── Nav item sidebar context ────────────────────────────────────────── */
|
|
131
|
+
[data-slot="dashboard-sidebar-inner"] [data-slot="nav-item"]:hover {
|
|
132
|
+
background-color: var(--sidebar-accent);
|
|
133
|
+
color: var(--sidebar-accent-foreground);
|
|
134
|
+
}
|
|
135
|
+
[data-slot="dashboard-sidebar-inner"] [data-slot="nav-item"][data-active="true"] {
|
|
136
|
+
background-color: var(--sidebar-accent);
|
|
137
|
+
color: var(--sidebar-accent-foreground);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* ── Mobile: sidebar becomes a fixed full-width overlay ───────────────── */
|
|
141
|
+
@media (max-width: 767px) {
|
|
142
|
+
/* Collapse sidebar column to 0 on mobile */
|
|
143
|
+
[data-slot="dashboard-group"] {
|
|
144
|
+
grid-template-columns: 0 1fr;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* Sidebar switches from grid column to fixed overlay */
|
|
148
|
+
[data-slot="dashboard-sidebar"] {
|
|
149
|
+
position: fixed;
|
|
150
|
+
inset-block: 0;
|
|
151
|
+
inset-inline-start: 0;
|
|
152
|
+
z-index: var(--z-sidebar);
|
|
153
|
+
width: 100dvw;
|
|
154
|
+
transform: translateX(-100dvw);
|
|
155
|
+
transition: transform var(--sidebar-duration) var(--ease-out-expo);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
[data-sidebar-open="true"] [data-slot="dashboard-sidebar"] {
|
|
159
|
+
transform: translateX(0);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Inner nav fills the full-width sidebar on mobile */
|
|
163
|
+
[data-slot="dashboard-sidebar-inner"] {
|
|
164
|
+
width: 100dvw;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* Scrim: appears behind the sidebar overlay on mobile */
|
|
168
|
+
[data-sidebar-open="true"] [data-slot="dashboard-scrim"] {
|
|
169
|
+
display: block;
|
|
170
|
+
position: fixed;
|
|
171
|
+
inset: 0;
|
|
172
|
+
z-index: calc(var(--z-sidebar) - 1);
|
|
173
|
+
background: oklch(0% 0 0 / 40%);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
that are awkward to express in ERB. Most styling lives in Ruby theme modules
|
|
4
4
|
(lib/kiso/themes/) as computed Tailwind classes. */
|
|
5
5
|
|
|
6
|
+
@import "./checkbox.css";
|
|
7
|
+
@import "./radio-group.css";
|
|
8
|
+
@import "./color-mode.css";
|
|
9
|
+
@import "./dashboard.css";
|
|
10
|
+
|
|
11
|
+
/* Scan Kiso's own files so host apps don't need to know the gem's internals.
|
|
12
|
+
Paths are relative to THIS file (app/assets/tailwind/kiso/engine.css).
|
|
13
|
+
Count carefully — wrong paths fail SILENTLY (classes just won't generate). */
|
|
14
|
+
@source "../../../views"; /* → app/views */
|
|
15
|
+
@source "../../../helpers"; /* → app/helpers */
|
|
16
|
+
@source "../../../../lib/kiso/themes"; /* → lib/kiso/themes */
|
|
17
|
+
|
|
6
18
|
/* === Geist Font (by Vercel) ===
|
|
7
19
|
Self-hosted variable fonts — no CDN dependency.
|
|
8
20
|
Licensed under the SIL Open Font License (see OFL.txt).
|
|
@@ -30,3 +42,94 @@
|
|
|
30
42
|
--font-sans: "Geist", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
31
43
|
--font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
32
44
|
}
|
|
45
|
+
|
|
46
|
+
/* === Semantic Color Tokens ===
|
|
47
|
+
Purpose-named tokens that flip in dark mode. Components use bg-primary,
|
|
48
|
+
text-foreground, etc. — never raw palette shades or dark: prefixes.
|
|
49
|
+
|
|
50
|
+
Override any token in your app's CSS to retheme:
|
|
51
|
+
@theme { --color-primary: var(--color-violet-600); }
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
@theme {
|
|
55
|
+
/* Brand / action colors */
|
|
56
|
+
--color-primary: var(--color-sky-600);
|
|
57
|
+
--color-primary-foreground: white;
|
|
58
|
+
|
|
59
|
+
--color-secondary: var(--color-teal-600);
|
|
60
|
+
--color-secondary-foreground: white;
|
|
61
|
+
|
|
62
|
+
--color-success: var(--color-green-600);
|
|
63
|
+
--color-success-foreground: white;
|
|
64
|
+
|
|
65
|
+
--color-info: var(--color-sky-600);
|
|
66
|
+
--color-info-foreground: white;
|
|
67
|
+
|
|
68
|
+
--color-warning: var(--color-amber-500);
|
|
69
|
+
--color-warning-foreground: var(--color-amber-950);
|
|
70
|
+
|
|
71
|
+
--color-error: var(--color-red-600);
|
|
72
|
+
--color-error-foreground: white;
|
|
73
|
+
|
|
74
|
+
/* Surface tokens */
|
|
75
|
+
--color-background: white;
|
|
76
|
+
--color-foreground: var(--color-zinc-950);
|
|
77
|
+
|
|
78
|
+
--color-muted: var(--color-zinc-100);
|
|
79
|
+
--color-muted-foreground: var(--color-zinc-500);
|
|
80
|
+
|
|
81
|
+
--color-accent: var(--color-zinc-100);
|
|
82
|
+
--color-accent-foreground: var(--color-zinc-900);
|
|
83
|
+
|
|
84
|
+
--color-inverted: var(--color-zinc-900);
|
|
85
|
+
--color-inverted-foreground: white;
|
|
86
|
+
--color-elevated: var(--color-zinc-100);
|
|
87
|
+
--color-accented: var(--color-zinc-300);
|
|
88
|
+
|
|
89
|
+
--color-border: var(--color-zinc-200);
|
|
90
|
+
--color-border-accented: var(--color-zinc-300);
|
|
91
|
+
|
|
92
|
+
--color-ring: var(--color-zinc-400);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* === Dark Mode ===
|
|
96
|
+
Redefine tokens under .dark — components never use dark: prefixes. */
|
|
97
|
+
|
|
98
|
+
.dark {
|
|
99
|
+
--color-primary: var(--color-blue-400);
|
|
100
|
+
--color-primary-foreground: var(--color-zinc-950);
|
|
101
|
+
|
|
102
|
+
--color-secondary: var(--color-teal-400);
|
|
103
|
+
--color-secondary-foreground: var(--color-zinc-950);
|
|
104
|
+
|
|
105
|
+
--color-success: var(--color-green-400);
|
|
106
|
+
--color-success-foreground: var(--color-zinc-950);
|
|
107
|
+
|
|
108
|
+
--color-info: var(--color-sky-400);
|
|
109
|
+
--color-info-foreground: var(--color-zinc-950);
|
|
110
|
+
|
|
111
|
+
--color-warning: var(--color-amber-400);
|
|
112
|
+
--color-warning-foreground: var(--color-zinc-950);
|
|
113
|
+
|
|
114
|
+
--color-error: var(--color-red-400);
|
|
115
|
+
--color-error-foreground: var(--color-zinc-950);
|
|
116
|
+
|
|
117
|
+
--color-background: var(--color-zinc-950);
|
|
118
|
+
--color-foreground: var(--color-zinc-50);
|
|
119
|
+
|
|
120
|
+
--color-muted: var(--color-zinc-800);
|
|
121
|
+
--color-muted-foreground: var(--color-zinc-400);
|
|
122
|
+
|
|
123
|
+
--color-accent: var(--color-zinc-800);
|
|
124
|
+
--color-accent-foreground: var(--color-zinc-50);
|
|
125
|
+
|
|
126
|
+
--color-inverted: white;
|
|
127
|
+
--color-inverted-foreground: var(--color-zinc-950);
|
|
128
|
+
--color-elevated: var(--color-zinc-800);
|
|
129
|
+
--color-accented: var(--color-zinc-700);
|
|
130
|
+
|
|
131
|
+
--color-border: var(--color-zinc-800);
|
|
132
|
+
--color-border-accented: var(--color-zinc-700);
|
|
133
|
+
|
|
134
|
+
--color-ring: var(--color-zinc-600);
|
|
135
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* RadioGroupItem indicator — CSS ::after for the filled circle dot since
|
|
2
|
+
native <input type="radio"> can't contain child elements. Uses currentColor
|
|
3
|
+
which inherits from checked:text-{color}-foreground set by compound variants.
|
|
4
|
+
Follows the same pattern as Checkbox (mask-image with currentColor). */
|
|
5
|
+
|
|
6
|
+
[data-radio-group-part="item"] {
|
|
7
|
+
display: grid;
|
|
8
|
+
place-content: center;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
[data-radio-group-part="item"]:checked::after {
|
|
12
|
+
content: '';
|
|
13
|
+
width: 0.5em;
|
|
14
|
+
height: 0.5em;
|
|
15
|
+
border-radius: 9999px;
|
|
16
|
+
background-color: currentColor;
|
|
17
|
+
}
|
|
@@ -1,36 +1,29 @@
|
|
|
1
1
|
module Kiso
|
|
2
|
+
# View helpers for rendering Kiso components.
|
|
3
|
+
#
|
|
4
|
+
# Included in all views automatically by {Engine}.
|
|
2
5
|
module ComponentHelper
|
|
3
|
-
# Renders a component
|
|
6
|
+
# Renders a Kiso component partial.
|
|
4
7
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
8
|
+
# Components live in +app/views/kiso/components/+. Sub-parts are nested
|
|
9
|
+
# in a directory matching the parent component name.
|
|
7
10
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
11
|
+
# @param component [Symbol] the component name (e.g. +:badge+, +:card+)
|
|
12
|
+
# @param part [Symbol, nil] optional sub-part name (e.g. +:header+, +:footer+)
|
|
13
|
+
# @param collection [Array, nil] renders the partial once per item when present
|
|
14
|
+
# @param kwargs [Hash] locals passed to the partial (e.g. +color:+, +variant:+, +css_classes:+)
|
|
15
|
+
# @yield optional block for component content
|
|
16
|
+
# @return [ActiveSupport::SafeBuffer] rendered HTML
|
|
10
17
|
#
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if part
|
|
15
|
-
data[:"#{component}-part"] = part
|
|
16
|
-
else
|
|
17
|
-
data[:component] = component
|
|
18
|
-
data[:variant] = variant if variant
|
|
19
|
-
data[:size] = size if size
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
options[:data] = data
|
|
23
|
-
|
|
24
|
-
content_tag(element, **options, &block)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Renders a Kiso component partial.
|
|
18
|
+
# @example Render a badge
|
|
19
|
+
# kui(:badge, color: :success, variant: :soft) { "Active" }
|
|
28
20
|
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
# kiso(:badge, collection: @statuses)
|
|
21
|
+
# @example Render a card sub-part
|
|
22
|
+
# kui(:card, :header) { "Title" }
|
|
32
23
|
#
|
|
33
|
-
|
|
24
|
+
# @example Render a collection
|
|
25
|
+
# kui(:badge, collection: @tags)
|
|
26
|
+
def kui(component, part = nil, collection: nil, **kwargs, &block)
|
|
34
27
|
path = if part
|
|
35
28
|
"kiso/components/#{component}/#{part}"
|
|
36
29
|
else
|
|
@@ -38,10 +31,36 @@ module Kiso
|
|
|
38
31
|
end
|
|
39
32
|
|
|
40
33
|
if collection
|
|
41
|
-
render partial: path, collection: collection,
|
|
34
|
+
render partial: path, collection: collection, locals: kwargs, &block
|
|
42
35
|
else
|
|
43
36
|
render path, **kwargs, &block
|
|
44
37
|
end
|
|
45
38
|
end
|
|
39
|
+
|
|
40
|
+
# Prepares +component_options+ for use with +content_tag+.
|
|
41
|
+
#
|
|
42
|
+
# Sets +data-slot+ for component identity (shadcn v4 convention) and
|
|
43
|
+
# merges any additional data attributes. Raises if +class:+ is passed
|
|
44
|
+
# (use +css_classes:+ instead).
|
|
45
|
+
#
|
|
46
|
+
# @param component_options [Hash] the +**component_options+ splat from the partial.
|
|
47
|
+
# Any +data:+ key is extracted and merged with +slot+ and +data_attrs+.
|
|
48
|
+
# @param slot [String] the +data-slot+ value (kebab-case, e.g. +"card-header"+)
|
|
49
|
+
# @param data_attrs [Hash] additional data attributes (e.g. +controller: "kiso--toggle"+)
|
|
50
|
+
# @return [Hash] merged data attributes hash for +content_tag+
|
|
51
|
+
# @raise [ArgumentError] if +component_options+ contains a +class:+ key
|
|
52
|
+
#
|
|
53
|
+
# @example In a component partial
|
|
54
|
+
# data: kiso_prepare_options(component_options, slot: "badge")
|
|
55
|
+
#
|
|
56
|
+
# @example With a Stimulus controller
|
|
57
|
+
# data: kiso_prepare_options(component_options, slot: "toggle", controller: "kiso--toggle")
|
|
58
|
+
def kiso_prepare_options(component_options, slot:, **data_attrs)
|
|
59
|
+
if component_options.key?(:class)
|
|
60
|
+
raise ArgumentError, "Use css_classes: instead of class: for Kiso components"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
(component_options.delete(:data) || {}).merge(slot: slot, **data_attrs)
|
|
64
|
+
end
|
|
46
65
|
end
|
|
47
66
|
end
|