odt-ui-rails 2.2.1 → 2.2.2

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: c6a3351e3c566a02e0cc281f7c75d8ff5aee3b9c790b49a360907aeb5118ef67
4
- data.tar.gz: c46e7e26fb322d840b5a569589d3c4d1d6ff4fa67e1215850aaff860d8ca82e0
3
+ metadata.gz: 10a40fe0221350427b615884ee7f7fb35fd430bd22f85d19753df3fc39ac5778
4
+ data.tar.gz: 61ba7e66ad20a6c4d14e269c77dce8e5ee937219b1cce0ae7097d1f36039e757
5
5
  SHA512:
6
- metadata.gz: 91490c4a98b07b40e122526c78b79baed1559f84a75edf07438a0cf1febe3b11026089a68ac76de7a86e15f1d1c9f79a5dc0bf7e69f53c79eee07867c669714d
7
- data.tar.gz: 41c74c909825e0431a27e69775ec9d7e3c61576ee2e03f0c2fbf1d27219a9a139c2f662ea17a5b75a042702aad30bf65b807aff36bf2c5d0e7115633bdbd4e3a
6
+ metadata.gz: 6c7bb314b4fd02fc10f6ccf7cd29d832d3fae2d4f4a0b0af09f91d1534f38fe3c105d7e11ca933c0ceb55a30ecb2d20b679a5d0b61670d08331a15d3083d8fa9
7
+ data.tar.gz: 0c14d0ff154e8da78825bbe5178722a9b2ebae2fefcd9861bdade3319338efbc09aa6b0d89f3535fdcfba562c4cca87205dc7453ea97e10a1b0edbc2c4fb5e1b
data/README.md CHANGED
@@ -58,7 +58,7 @@
58
58
  Add the gem to your application's `Gemfile`:
59
59
 
60
60
  ```ruby
61
- gem "odt-ui-rails", "~> 2.2.0"
61
+ gem "odt-ui-rails", "~> 2.2.2"
62
62
  ```
63
63
 
64
64
  Install dependencies:
@@ -5,6 +5,8 @@ require "rails/generators/base"
5
5
  module Odt
6
6
  module Generators
7
7
  class InstallGenerator < Rails::Generators::Base
8
+ source_root File.expand_path("templates", __dir__)
9
+
8
10
  desc "Configures ODT UI standalone stylesheets, Tailwind theme, and RBS type signatures for Rails application"
9
11
 
10
12
  def inject_stylesheets
@@ -58,28 +60,17 @@ module Odt
58
60
  end
59
61
 
60
62
  def copy_rbs_signature
61
- source = File.expand_path("../../../../../sig/odt_ui.rbs", __dir__)
62
- return unless File.exist?(source)
63
-
64
63
  empty_directory "sig"
65
- copy_file source, "sig/odt_ui.rbs"
64
+ copy_file "odt_ui.rbs", "sig/odt_ui.rbs"
66
65
  say "Copied sig/odt_ui.rbs for Ruby LSP / Solargraph support", :green
67
66
  end
68
67
 
69
68
  def copy_stimulus_controller
70
- toast_source = File.expand_path("templates/odt_toast_controller.js", __dir__)
71
- modal_source = File.expand_path("templates/odt_modal_controller.js", __dir__)
72
-
73
69
  if File.directory?("app/javascript/controllers") || File.directory?("app/javascript")
74
70
  empty_directory "app/javascript/controllers"
75
- if File.exist?(toast_source)
76
- copy_file toast_source, "app/javascript/controllers/odt_toast_controller.js"
77
- say "Copied app/javascript/controllers/odt_toast_controller.js", :green
78
- end
79
- if File.exist?(modal_source)
80
- copy_file modal_source, "app/javascript/controllers/odt_modal_controller.js"
81
- say "Copied app/javascript/controllers/odt_modal_controller.js", :green
82
- end
71
+ copy_file "odt_toast_controller.js", "app/javascript/controllers/odt_toast_controller.js"
72
+ copy_file "odt_modal_controller.js", "app/javascript/controllers/odt_modal_controller.js"
73
+ say "Copied Stimulus controllers to app/javascript/controllers/", :green
83
74
  end
84
75
  end
85
76
  end
@@ -0,0 +1,302 @@
1
+ module OdtUi
2
+ VERSION: String
3
+
4
+ module Helper
5
+ type button_variant = :filled | :frosted | :capsule | :ghost | :light | :outline | :outlined | :subtle | String
6
+ type button_color = :primary | :secondary | :surface | :muted | :inverse | :success | :warning | :danger | :info | :neutral | String
7
+ type button_size = :xs | :sm | :md | :lg | :xl | String
8
+ type radius_size = :none | :xs | :sm | :md | :lg | :xl | :"2xl" | :"3xl" | :"4xl" | :full | Symbol | String
9
+ type shadow_size = :none | :card | :dropdown | :modal | :popover | Symbol | String
10
+
11
+ type badge_variant = :subtle | :filled | :outlined | :outline | String
12
+ type badge_color = :primary | :secondary | :success | :warning | :danger | :info | :neutral | String
13
+ type badge_size = :sm | :md | String
14
+
15
+ type card_variant = :elevated | :outlined | :subtle | :muted | :ghost | :frosted | String
16
+ type card_background = :base | :surface | :surface_elevated | :surface_muted | :surface_subtle | :gradient_primary | :gradient_secondary | :gradient_vibrant | :gradient_hero | :frosted | :frosted_muted | :frosted_subtle | :frosted_gradient_primary | :frosted_gradient_secondary | :transparent | Symbol | String
17
+ type card_border = :none | :muted | :base | :strong | :primary | :secondary | :danger | :success | bool | Symbol | String
18
+ type card_padding = :none | :xs | :sm | :md | :lg | :xl | :"2xl" | Symbol | String
19
+ type card_tag = :div | :article | :section | :aside | :main | Symbol | String
20
+
21
+ type alert_variant = :success | :warning | :danger | :info | String
22
+ type heading_tag = :h1 | :h2 | :h3 | :h4 | :h5 | :h6 | String
23
+ type heading_size = :"5xl" | :"4xl" | :"3xl" | :"2xl" | :xl | :lg | Symbol | String
24
+ type font_weight = :light | :normal | :medium | :semibold | :bold | :extrabold | Symbol | String
25
+ type typography_color = :strong | :default | :muted | :subtle | :disabled | :primary | :secondary | :success | :warning | :danger | :info | Symbol | String
26
+
27
+ type text_tag = :p | :span | :div | :label | :small | Symbol | String
28
+ type text_size = :xs | :sm | :base | :lg | :xl | :"2xl" | Symbol | String
29
+
30
+ type avatar_size = :xs | :sm | :md | :lg | :xl | :"2xl" | String
31
+ type avatar_color = :secondary | :primary | :neutral | String
32
+
33
+ type input_variant = :outlined | :filled | :frosted | String
34
+ type input_size = :sm | :md | :lg | String
35
+ type input_resize = :none | :vertical | :horizontal | :both | String
36
+ type checkbox_color = :primary | :secondary | :success | :warning | :danger | :dark | :neutral | String
37
+ type checkbox_size = :sm | :md | :lg | String
38
+
39
+ # Renders an ODT Button component.
40
+ def odt_button: (
41
+ ?String? text,
42
+ ?variant: button_variant,
43
+ ?color: button_color,
44
+ ?size: button_size,
45
+ ?radius: radius_size?,
46
+ ?shadow: shadow_size?,
47
+ ?icon_only: bool,
48
+ ?full_width: bool,
49
+ ?loading: bool,
50
+ ?disabled: bool,
51
+ ?href: String?,
52
+ ?icon: String?,
53
+ ?right_icon: String?,
54
+ ?type: String,
55
+ **untyped
56
+ ) ?{ () -> untyped } -> untyped
57
+
58
+ # Renders an ODT Badge component.
59
+ def odt_badge: (
60
+ ?String? text,
61
+ ?variant: badge_variant,
62
+ ?color: badge_color,
63
+ ?size: badge_size,
64
+ ?radius: radius_size?,
65
+ ?dot: bool,
66
+ ?icon: String?,
67
+ **untyped
68
+ ) ?{ () -> untyped } -> untyped
69
+
70
+ # Renders an ODT Card component.
71
+ def odt_card: (
72
+ ?title: String?,
73
+ ?subtitle: String?,
74
+ ?variant: card_variant,
75
+ ?background: card_background?,
76
+ ?border: card_border?,
77
+ ?shadow: shadow_size?,
78
+ ?radius: radius_size?,
79
+ ?padding: card_padding?,
80
+ ?hoverable: bool,
81
+ ?hover: bool,
82
+ ?as: card_tag,
83
+ **untyped
84
+ ) ?{ () -> untyped } -> untyped
85
+
86
+ # Renders an ODT Alert banner.
87
+ def odt_alert: (
88
+ ?String? message,
89
+ ?variant: alert_variant,
90
+ ?icon: String?,
91
+ **untyped
92
+ ) ?{ () -> untyped } -> untyped
93
+
94
+ # Renders an ODT Heading element.
95
+ def odt_heading: (
96
+ ?String? text,
97
+ ?as: heading_tag,
98
+ ?size: heading_size?,
99
+ ?weight: font_weight?,
100
+ ?color: typography_color?,
101
+ ?truncate: bool,
102
+ **untyped
103
+ ) ?{ () -> untyped } -> untyped
104
+
105
+ # Renders styled body text.
106
+ def odt_text: (
107
+ ?String? text,
108
+ ?as: text_tag,
109
+ ?size: text_size?,
110
+ ?weight: font_weight?,
111
+ ?color: typography_color?,
112
+ ?truncate: bool,
113
+ **untyped
114
+ ) ?{ () -> untyped } -> untyped
115
+
116
+ # Renders an ODT Avatar element.
117
+ def odt_avatar: (
118
+ ?name: String?,
119
+ ?src: String?,
120
+ ?size: avatar_size,
121
+ ?color: avatar_color,
122
+ ?icon: String,
123
+ ?fallback: String?,
124
+ **untyped
125
+ ) -> untyped
126
+
127
+ # Renders a styled input field.
128
+ def odt_input: (
129
+ ?label: String?,
130
+ ?variant: input_variant,
131
+ ?size: input_size,
132
+ ?radius: radius_size?,
133
+ ?type: String,
134
+ ?placeholder: String?,
135
+ ?error: String?,
136
+ ?helper: String?,
137
+ ?helper_text: String?,
138
+ ?success: String?,
139
+ ?left_icon: String?,
140
+ ?right_icon: String?,
141
+ ?prefix: String?,
142
+ ?suffix: String?,
143
+ ?addon_before: String?,
144
+ ?addon_after: String?,
145
+ ?disabled: bool,
146
+ ?full_width: bool,
147
+ **untyped
148
+ ) -> untyped
149
+
150
+ # Renders a styled textarea field.
151
+ def odt_textarea: (
152
+ ?label: String?,
153
+ ?variant: input_variant,
154
+ ?size: input_size,
155
+ ?radius: radius_size?,
156
+ ?rows: Integer,
157
+ ?resize: input_resize,
158
+ ?error: String?,
159
+ ?helper: String?,
160
+ ?helper_text: String?,
161
+ ?success: String?,
162
+ ?disabled: bool,
163
+ ?full_width: bool,
164
+ **untyped
165
+ ) ?{ () -> untyped } -> untyped
166
+
167
+ # Renders a styled native <select> dropdown.
168
+ def odt_select: (
169
+ ?label: String?,
170
+ ?options: untyped,
171
+ ?variant: input_variant,
172
+ ?size: input_size,
173
+ ?radius: radius_size?,
174
+ ?prompt: String?,
175
+ ?error: String?,
176
+ ?helper: String?,
177
+ ?helper_text: String?,
178
+ ?success: String?,
179
+ ?disabled: bool,
180
+ ?full_width: bool,
181
+ **untyped
182
+ ) -> untyped
183
+
184
+ # Renders a styled checkbox.
185
+ def odt_checkbox: (
186
+ ?label: String?,
187
+ ?description: String?,
188
+ ?checked: bool,
189
+ ?color: checkbox_color,
190
+ ?size: checkbox_size,
191
+ ?radius: radius_size?,
192
+ ?disabled: bool,
193
+ ?error: String?,
194
+ **untyped
195
+ ) -> untyped
196
+
197
+ # Renders a styled radio button.
198
+ def odt_radio: (
199
+ ?label: String?,
200
+ ?description: String?,
201
+ ?checked: bool,
202
+ ?color: checkbox_color,
203
+ ?size: checkbox_size,
204
+ ?disabled: bool,
205
+ ?error: String?,
206
+ **untyped
207
+ ) -> untyped
208
+
209
+ # Renders a form field wrapper.
210
+ def odt_form_group: (
211
+ ?label: String?,
212
+ ?error: String?,
213
+ ?helper: String?,
214
+ ?helper_text: String?,
215
+ ?success: String?,
216
+ ?required: bool,
217
+ **untyped
218
+ ) ?{ () -> untyped } -> untyped
219
+
220
+ type toaster_position = :top_right | :top_center | :top_left | :bottom_right | :bottom_center | :bottom_left | Symbol | String
221
+ type toast_variant = :success | :warning | :danger | :error | :info | :loading | :frosted | Symbol | String
222
+
223
+ # Renders an ODT Toaster viewport container.
224
+ def odt_toaster: (
225
+ ?position: toaster_position,
226
+ ?id: String,
227
+ **untyped
228
+ ) ?{ () -> untyped } -> untyped
229
+
230
+ # Renders a single ODT Toast card.
231
+ def odt_toast: (
232
+ ?String? message,
233
+ ?title: String?,
234
+ ?variant: toast_variant,
235
+ ?icon: String?,
236
+ ?duration: Integer,
237
+ ?dismissible: bool,
238
+ ?radius: radius_size?,
239
+ **untyped
240
+ ) ?{ () -> untyped } -> untyped
241
+
242
+ # Renders active flash messages as ODT Toasts.
243
+ def odt_flash_toasts: (
244
+ ?untyped flash_hash,
245
+ ?duration: Integer
246
+ ) -> untyped
247
+
248
+ # Generates a Turbo Stream action for a toast.
249
+ def odt_toast_stream: (
250
+ ?String? message,
251
+ ?title: String?,
252
+ ?variant: toast_variant,
253
+ ?target: String,
254
+ ?action: Symbol | String,
255
+ ?duration: Integer,
256
+ **untyped
257
+ ) -> untyped
258
+
259
+ type modal_size = :sm | :md | :lg | :xl | :full | Symbol | String
260
+
261
+ # Renders an ODT Modal dialog container.
262
+ def odt_modal: (
263
+ ?id: String?,
264
+ ?title: String?,
265
+ ?subtitle: String?,
266
+ ?size: modal_size,
267
+ ?radius: radius_size?,
268
+ ?dismissible: bool,
269
+ ?open: bool,
270
+ ?prevent_backdrop_close: bool,
271
+ **untyped
272
+ ) ?{ () -> untyped } -> untyped
273
+
274
+ # Renders an ODT Modal Header subcomponent.
275
+ def odt_modal_header: (
276
+ ?title: String?,
277
+ ?subtitle: String?,
278
+ ?dismissible: bool,
279
+ **untyped
280
+ ) ?{ () -> untyped } -> untyped
281
+
282
+ # Renders an ODT Modal Body subcomponent.
283
+ def odt_modal_body: (
284
+ **untyped
285
+ ) ?{ () -> untyped } -> untyped
286
+
287
+ # Renders an ODT Modal Footer subcomponent.
288
+ def odt_modal_footer: (
289
+ **untyped
290
+ ) ?{ () -> untyped } -> untyped
291
+ end
292
+ end
293
+
294
+ module ActionView
295
+ class Base
296
+ include OdtUi::Helper
297
+ end
298
+
299
+ module Helpers
300
+ include OdtUi::Helper
301
+ end
302
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OdtUi
4
- VERSION = "2.2.1"
4
+ VERSION = "2.2.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: odt-ui-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pixel
@@ -29,164 +29,15 @@ dependencies:
29
29
  - - "<"
30
30
  - !ruby/object:Gem::Version
31
31
  version: '9'
32
- description: "<div align=\"center\">\n\n# ODT UI for Ruby on Rails (`odt-ui-rails`)\n\n**Standalone
33
- CSS-first design tokens, Hotwire-ready UI components, and ActionView helpers for
34
- Ruby on Rails.**\n\n[![Gem Version](https://badge.fury.io/rb/odt-ui-rails.svg)](https://badge.fury.io/rb/odt-ui-rails)\n[![License:
35
- MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Ruby](https://img.shields.io/badge/Ruby-%3E%3D%203.0-ruby.svg)](https://www.ruby-lang.org)\n[![Rails](https://img.shields.io/badge/Rails-%3E%3D%206.1-red.svg)](https://rubyonrails.org)\n[![Hotwire
36
- Ready](https://img.shields.io/badge/Hotwire-Turbo%20%26%20Stimulus-orange.svg)](https://hotwired.dev)\n[![Type
37
- Checked](https://img.shields.io/badge/RBS-Type%20Signatures-green.svg)](sig/odt_ui.rbs)\n\n</div>\n\n---\n\n##
38
- Overview\n\n`odt-ui-rails` brings the **ODT Design System** directly into Ruby on
39
- Rails. It is architected from the ground up to provide a **Standalone CSS First**
40
- experience:\n\n- \U0001F4E6 **Zero Host Build Tools Required:** Ships pre-compiled
41
- CSS custom properties and `.odt-*` component styles. Works out-of-the-box with Propshaft,
42
- Sprockets, or no asset pipeline at all.\n- ⚡ **Seamless Tailwind CSS v4 Interoperability:**
43
- Includes a complete `@theme` token configuration for Tailwind v4 projects, allowing
44
- custom utility classes (`class: \"...\"`) to merge effortlessly onto components.\n-
45
- \U0001F680 **Hotwire & Turbo Native:** First-class helpers for Turbo Streams (`odt_toast_stream`),
46
- Flash message auto-toasts (`odt_flash_toasts`), and Stimulus-powered Modals (`odt_modal`).\n-
47
- \U0001F48E **Strict Type Signatures:** Full RBS definitions included for Ruby LSP,
48
- Steep, and Solargraph IDE autocompletion.\n\n---\n\n## Table of Contents\n\n- [Installation](#installation)\n-
49
- [Asset Pipeline Configuration](#asset-pipeline-configuration)\n- [Component Reference](#component-reference)\n
50
- \ - [Feedback & Overlays](#feedback--overlays)\n - [Toasts & Toaster](#toasts--toaster)\n
51
- \ - [Modals](#modals)\n - [Alerts](#alerts)\n - [Actions & Indicators](#actions--indicators)\n
52
- \ - [Buttons](#buttons)\n - [Badges](#badges)\n - [Form Controls](#form-controls)\n
53
- \ - [Input Field](#input-field)\n - [Textarea](#textarea)\n - [Select Dropdown](#select-dropdown)\n
54
- \ - [Checkbox & Radio](#checkbox--radio)\n - [Form Group](#form-group)\n -
55
- [Layout & Typography](#layout--typography)\n - [Cards](#cards)\n - [Typography
56
- (Heading & Text)](#typography-heading--text)\n - [Avatars](#avatars)\n- [Theming
57
- & Dark Mode](#theming--dark-mode)\n- [License](#license)\n\n---\n\n## Installation\n\nAdd
58
- the gem to your application's `Gemfile`:\n\n```ruby\ngem \"odt-ui-rails\", \"~>
59
- 2.2.0\"\n```\n\nInstall dependencies:\n\n```bash\nbundle install\n```\n\nRun the
60
- automated install generator:\n\n```bash\nbin/rails g odt:install\n```\n\nThe generator
61
- will:\n\n1. Detect your asset pipeline (Tailwind CSS v4, Propshaft, or Sprockets)
62
- and safely configure the required `@import` statements.\n2. Copy `sig/odt_ui.rbs`
63
- for Ruby LSP IDE autocompletion.\n3. Copy Stimulus controllers (`odt_toast_controller.js`,
64
- `odt_modal_controller.js`) to `app/javascript/controllers/` if Stimulus is present.\n\n---\n\n##
65
- Asset Pipeline Configuration\n\nIf configuring stylesheets manually, use the configuration
66
- below:\n\n### Option A: Tailwind CSS v4 (`app/assets/tailwind/application.css`)\n\n```css\n@import
67
- \"tailwindcss\";\n@import \"odt_ui/tokens.css\";\n@import \"odt_ui/styles.css\";\n@import
68
- \"odt_ui/theme.css\";\n```\n\n### Option B: Propshaft / Sprockets / Standard Rails
69
- (`app/assets/stylesheets/application.css`)\n\n```css\n@import \"odt_ui/tokens.css\";\n@import
70
- \"odt_ui/styles.css\";\n```\n\n---\n\n## Component Reference\n\nAll helpers are
71
- globally available in all ERB templates, layouts, and helpers.\n\n---\n\n### Feedback
72
- & Overlays\n\n#### Toasts & Toaster\n\nProvides viewport stacking containers, automated
73
- Flash message toasts on redirects, and Turbo Stream responses for async form actions.\n\n```erb\n<%#
74
- In app/views/layouts/application.html.erb %>\n<body class=\"bg-surface text-fg font-sans
75
- antialiased\">\n <%= odt_toaster position: :top_right do %>\n <%= odt_flash_toasts
76
- %>\n <% end %>\n\n <%= yield %>\n</body>\n```\n\n**Controller Turbo Stream Action:**\n\n```ruby\ndef
77
- create\n @todo = Todo.new(todo_params)\n if @todo.save\n respond_to do |format|\n
78
- \ format.turbo_stream do\n render turbo_stream: [\n turbo_stream.prepend(\"todos\",
79
- @todo),\n odt_toast_stream(\"Todo created successfully!\", variant: :success)\n
80
- \ ]\n end\n format.html { redirect_to todos_path, notice: \"Todo
81
- created successfully!\" }\n end\n end\nend\n```\n\n**Individual Toast Helper:**\n\n```erb\n<%=
82
- odt_toast \"Settings updated\", title: \"Saved\", variant: :success, duration: 4000
83
- %>\n<%= odt_toast \"Failed to sync records\", variant: :danger %>\n```\n\n| Parameter
84
- \ | Type | Default | Description |\n|
85
- :------------ | :-------- | :--------- | :---------------------------------------------------------------------------
86
- |\n| `message` | `String` | `nil` | Toast description or body text |\n|
87
- `title` | `String` | `nil` | Optional bold header title |\n|
88
- `variant` | `Symbol` | `:success` | `:success`, `:warning`, `:danger`, `:error`,
89
- `:info`, `:loading`, `:frosted` |\n| `duration` | `Integer` | `4000` | Auto-dismiss
90
- duration in ms (`0` to disable) |\n| `dismissible`
91
- | `Boolean` | `true` | Renders close button (`×`) |\n\n---\n\n####
92
- Modals\n\nAccessible dialog containers with backdrop overlay, ESC key handling,
93
- scroll locking, and smooth scale transitions.\n\n```erb\n<%# Trigger Button %>\n<%=
94
- odt_button \"New Task\", color: :primary, data: { action: \"click->odt-modal#open\"
95
- } %>\n\n<%# Standard Modal %>\n<%= odt_modal id: \"new_task_modal\", title: \"Create
96
- Task\", subtitle: \"Add a task to your board\", size: :md do %>\n <%= render \"form\",
97
- todo: Todo.new %>\n<% end %>\n\n<%# Custom Composition Modal %>\n<%= odt_modal id:
98
- \"confirm_delete_modal\", size: :sm do %>\n <%= odt_modal_header title: \"Delete
99
- Item?\", subtitle: \"This action cannot be undone.\" %>\n <%= odt_modal_body do
100
- %>\n <p class=\"text-sm text-fg-muted\">Are you sure you want to permanently
101
- remove this record?</p>\n <% end %>\n <%= odt_modal_footer do %>\n <%= odt_button
102
- \"Cancel\", variant: :ghost, data: { action: \"click->odt-modal#close\" } %>\n <%=
103
- odt_button \"Delete\", color: :danger, data: { turbo_method: :delete } %>\n <%
104
- end %>\n<% end %>\n```\n\n| Parameter | Type | Default | Description
105
- \ |\n| :----------------------- | :-------- | :-------
106
- | :------------------------------------------- |\n| `id` | `String`
107
- \ | `nil` | HTML identifier for Stimulus/Turbo targeting |\n| `title` / `subtitle`
108
- \ | `String` | `nil` | Header titles |\n|
109
- `size` | `Symbol` | `:md` | `:sm`, `:md`, `:lg`, `:xl`, `:full`
110
- \ |\n| `radius` | `Symbol` | `:\"2xl\"` | `:none` to `:\"4xl\"`,
111
- `:full` |\n| `dismissible` | `Boolean` | `true` | Renders
112
- close button |\n| `open` | `Boolean` |
113
- `false` | Initial visible state |\n| `prevent_backdrop_close`
114
- | `Boolean` | `false` | Disables closing on overlay click |\n\n---\n\n####
115
- Alerts\n\nInline banners for status notices, warning messages, and form callouts.\n\n```erb\n<%=
116
- odt_alert \"Your subscription will renew on May 1st.\", variant: :info %>\n<%= odt_alert
117
- \"Payment failed. Please update billing info.\", variant: :danger, icon: \"fa-solid
118
- fa-triangle-exclamation\" %>\n```\n\n---\n\n### Actions & Indicators\n\n#### Buttons\n\nVersatile
119
- action buttons supporting brand colors, frosted glass surfaces, loading states,
120
- and icon decorations.\n\n```erb\n<%# Standard Brand Action %>\n<%= odt_button \"Save
121
- Changes\", color: :primary, variant: :filled, radius: :full %>\n\n<%# Secondary
122
- & Frosted Glass %>\n<%= odt_button \"Secondary\", variant: :subtle, color: :secondary
123
- %>\n<%= odt_button \"Frosted Glass\", variant: :frosted, color: :primary %>\n\n<%#
124
- Link as Button %>\n<%= odt_button \"View Project\", href: project_path(@project),
125
- variant: :subtle %>\n\n<%# Loading & Icons %>\n<%= odt_button \"Add Task\", icon:
126
- \"fa-solid fa-plus\", color: :primary %>\n<%= odt_button \"Saving...\", loading:
127
- true %>\n<%= odt_button icon: \"fa-solid fa-trash\", icon_only: true, color: :danger,
128
- variant: :ghost %>\n```\n\n| Option | Type | Default | Description
129
- \ |\n|
130
- :-------------------- | :-------- | :--------- | :-----------------------------------------------------------------------------------------------------------------
131
- |\n| `variant` | `Symbol` | `:filled` | `:filled`, `:subtle`, `:ghost`,
132
- `:outline`, `:capsule`, `:frosted`, `:light` |\n|
133
- `color` | `Symbol` | `:primary` | `:primary`, `:secondary`, `:surface`,
134
- `:muted`, `:inverse`, `:success`, `:warning`, `:danger`, `:info`, `:neutral` |\n|
135
- `size` | `Symbol` | `:md` | `:xs`, `:sm`, `:md`, `:lg`, `:xl`
136
- \ |\n|
137
- `radius` | `Symbol` | `:\"2xl\"` | `:none`, `:xs`, `:sm`, `:md`,
138
- `:lg`, `:xl`, `:\"2xl\"`, `:\"3xl\"`, `:\"4xl\"`, `:full` |\n|
139
- `icon` / `right_icon` | `String` | `nil` | FontAwesome class or inline SVG
140
- string |\n|
141
- `icon_only` | `Boolean` | `false` | Square icon button formatting |\n|
142
- `loading` | `Boolean` | `false` | Replaces icon with spinning loader
143
- \ |\n|
144
- `disabled` | `Boolean` | `false` | HTML disabled state |\n|
145
- `full_width` | `Boolean` | `false` | Expands width to 100% |\n\n---\n\n####
146
- Badges\n\nCompact status indicators with optional indicator dots and icons.\n\n```erb\n<%=
147
- odt_badge \"Active\", variant: :subtle, color: :success, dot: true %>\n<%= odt_badge
148
- \"High Priority\", variant: :filled, color: :danger, radius: :full %>\n<%= odt_badge
149
- \"Calendar\", icon: \"fa-regular fa-calendar\", variant: :outlined %>\n```\n\n---\n\n###
150
- Form Controls\n\nAccessible form components complete with labels, helper text, error
151
- validations, icons, and input adornments.\n\n```erb\n<%= form_with model: @user,
152
- class: \"space-y-4\" do |f| %>\n <%# Text Input with Left Icon %>\n <%= odt_input(\n
153
- \ label: \"Email Address\",\n name: \"user[email]\",\n value: @user.email,\n
154
- \ type: \"email\",\n placeholder: \"you@example.com\",\n left_icon: \"fa-solid
155
- fa-envelope\",\n error: @user.errors[:email].first,\n required: true\n )
156
- %>\n\n <%# Textarea %>\n <%= odt_textarea(\n label: \"Bio\",\n name: \"user[bio]\",\n
157
- \ value: @user.bio,\n rows: 4,\n helper: \"Brief summary for your profile\"\n
158
- \ ) %>\n\n <%# Select Dropdown %>\n <%= odt_select(\n label: \"Country\",\n
159
- \ name: \"user[country]\",\n options: [[\"Thailand\", \"TH\"], [\"United States\",
160
- \"US\"], [\"Japan\", \"JP\"]],\n selected: @user.country,\n prompt: \"Select
161
- country\"\n ) %>\n\n <%# Checkbox %>\n <%= odt_checkbox(\n label: \"Subscribe
162
- to newsletter\",\n description: \"Receive product updates once a week\",\n name:
163
- \"user[subscribed]\",\n checked: true,\n color: :primary\n ) %>\n\n <%#
164
- Radio Group %>\n <%= odt_radio label: \"Monthly Billing\", name: \"plan\", value:
165
- \"monthly\", checked: true %>\n <%= odt_radio label: \"Annual Billing (Save 20%)\",
166
- name: \"plan\", value: \"annual\" %>\n\n <%# Custom Slot Form Group %>\n <%= odt_form_group
167
- label: \"Custom Input\", helper: \"Unique value required\" do %>\n <input type=\"text\"
168
- class=\"odt-input odt-input--outlined odt-input--md\" name=\"custom\" />\n <% end
169
- %>\n<% end %>\n```\n\n---\n\n### Layout & Typography\n\n#### Cards\n\nVersatile
170
- containers supporting header metadata, multiple surface styles, and hover transitions.\n\n```erb\n<%=
171
- odt_card title: \"Analytics Overview\", subtitle: \"Monthly performance\", variant:
172
- :elevated, radius: :\"3xl\" do %>\n <p class=\"text-sm text-fg\">Dashboard charts
173
- and statistics...</p>\n<% end %>\n\n<%= odt_card variant: :frosted, radius: :\"2xl\",
174
- hoverable: true do %>\n <span>Interactive frosted glass card</span>\n<% end %>\n```\n\n####
175
- Typography (`odt_heading` & `odt_text`)\n\nStandardized typographic elements mapped
176
- to the design system scale.\n\n```erb\n<%= odt_heading \"Task Dashboard\", as: :h1,
177
- size: :\"4xl\", weight: :bold, color: :strong %>\n<%= odt_heading \"Section Title\",
178
- as: :h3, size: :xl %>\n\n<%= odt_text \"Manage all project deliverables in one workspace.\",
179
- size: :sm, color: :muted %>\n<%= odt_text \"A very long single-line description...\",
180
- truncate: true %>\n```\n\n#### Avatars\n\nRenders image avatars or automatically
181
- computes two-letter initials from full names.\n\n```erb\n<%# Generates initials
182
- avatar \"JD\" %>\n<%= odt_avatar name: \"John Doe\", size: :lg, color: :secondary
183
- %>\n\n<%# Image avatar with fallback %>\n<%= odt_avatar src: \"https://avatar.vercel.sh/pixel\",
184
- size: :md %>\n```\n\n---\n\n## Theming & Dark Mode\n\nThe design system is fully
185
- dark mode ready. Apply `data-theme=\"dark\"` or the `.dark` class to `<html>` or
186
- any sub-container:\n\n```html\n<html data-theme=\"dark\" class=\"dark\">\n ...\n</html>\n```\n\nAll
187
- design tokens (backgrounds, surfaces, borders, text, and shadows) adapt automatically
188
- without custom CSS.\n\n---\n\n## License\n\nThe gem is available as open source
189
- under the terms of the [MIT License](LICENSE).\n"
32
+ description: |
33
+ ODT UI for Ruby on Rails brings the ODT Design System directly into Rails applications with a Standalone CSS First architecture.
34
+
35
+ Key Features:
36
+ * Standalone CSS First: Ships pre-compiled design tokens and component styles with zero host build tools required (compatible with Propshaft, Sprockets, or no asset pipeline).
37
+ * Seamless Tailwind CSS v4 Interop: Full @theme preset configuration allowing custom utility classes to merge cleanly.
38
+ * Hotwire & Turbo Ready: Out-of-the-box ActionView helpers for Flash Toasts, Turbo Stream notifications, and Stimulus-powered Modals.
39
+ * Complete Component Set: Buttons, Badges, Cards, Alerts, Toasts, Modals, Headings, Text, Avatars, Inputs, Selects, Checkboxes, Radios, and Form Groups.
40
+ * Type Checked: Full RBS type signatures included for Ruby LSP and Solargraph autocompletion.
190
41
  email:
191
42
  - pixxel.tk@gmail.com
192
43
  executables: []
@@ -203,6 +54,7 @@ files:
203
54
  - lib/generators/odt/install_generator.rb
204
55
  - lib/generators/odt/templates/odt_modal_controller.js
205
56
  - lib/generators/odt/templates/odt_toast_controller.js
57
+ - lib/generators/odt/templates/odt_ui.rbs
206
58
  - lib/odt-ui-rails.rb
207
59
  - lib/odt_ui/engine.rb
208
60
  - lib/odt_ui/helper.rb