senren-ui 0.1.5 → 0.2.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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +124 -2
  3. data/CONTRIBUTING.md +79 -9
  4. data/README.md +149 -14
  5. data/Rakefile +14 -1
  6. data/docs/components.md +222 -0
  7. data/docs/hot_reload.md +103 -0
  8. data/docs/performance_testing.md +38 -0
  9. data/lib/commands/senren/add/add_command.rb +35 -0
  10. data/lib/generators/senren/component/templates/controller.js.tt +7 -4
  11. data/lib/generators/senren/install/install_generator.rb +74 -0
  12. data/lib/generators/senren/install/templates/base_component.rb.tt +89 -8
  13. data/lib/generators/senren/install/templates/conventions.md.tt +26 -7
  14. data/lib/senren/rails/agent_rules_writer.rb +62 -19
  15. data/lib/senren/rails/asset_path_guard.rb +128 -0
  16. data/lib/senren/rails/base_component_patch.rb +64 -0
  17. data/lib/senren/rails/component_copier.rb +138 -18
  18. data/lib/senren/rails/component_installer.rb +73 -0
  19. data/lib/senren/rails/doctor.rb +7 -4
  20. data/lib/senren/rails/engine.rb +23 -0
  21. data/lib/senren/rails/host_paths.rb +11 -2
  22. data/lib/senren/rails/marker_block.rb +81 -0
  23. data/lib/senren/rails/registry.rb +73 -35
  24. data/lib/senren/rails/safe_write.rb +169 -0
  25. data/lib/senren/rails/skill_writer.rb +48 -12
  26. data/lib/senren/rails/version.rb +1 -1
  27. data/lib/senren/rails.rb +2 -1
  28. data/lib/senren-ui.rb +15 -0
  29. data/lib/tasks/senren.rake +53 -34
  30. data/registry/components.yml +45 -0
  31. data/registry/recipes.yml +12 -0
  32. data/templates/components/alert_dialog/alert_dialog_component.rb +1 -1
  33. data/templates/components/api_key_field/api_key_field_component.html.erb +1 -1
  34. data/templates/components/aspect_ratio/aspect_ratio_component.rb +7 -0
  35. data/templates/components/avatar/avatar_component.rb +8 -1
  36. data/templates/components/billing_plan_card/billing_plan_card_component.html.erb +1 -1
  37. data/templates/components/breadcrumb/breadcrumb_component.rb +2 -2
  38. data/templates/components/button/button_component.html.erb +1 -1
  39. data/templates/components/carousel/carousel_component.rb +1 -1
  40. data/templates/components/cart/cart_component.html.erb +61 -0
  41. data/templates/components/cart/cart_component.rb +71 -0
  42. data/templates/components/checkbox/checkbox_component.rb +1 -1
  43. data/templates/components/clipboard/clipboard_component.html.erb +1 -1
  44. data/templates/components/command/command_component.rb +2 -2
  45. data/templates/components/date_picker/date_picker_component.html.erb +1 -1
  46. data/templates/components/dialog/dialog_component.rb +1 -1
  47. data/templates/components/dropdown_menu/dropdown_menu_component.rb +10 -7
  48. data/templates/components/form/form_component.html.erb +8 -1
  49. data/templates/components/form/form_component.rb +12 -2
  50. data/templates/components/input/input_component.html.erb +1 -1
  51. data/templates/components/input/input_component.rb +19 -0
  52. data/templates/components/invite_member_dialog/invite_member_dialog_component.rb +1 -1
  53. data/templates/components/label/label_component.html.erb +1 -2
  54. data/templates/components/label/label_component.rb +12 -2
  55. data/templates/components/link/link_component.html.erb +1 -1
  56. data/templates/components/native_select/native_select_component.html.erb +19 -5
  57. data/templates/components/native_select/native_select_component.rb +17 -5
  58. data/templates/components/pagination/pagination_component.rb +2 -1
  59. data/templates/components/product_card/product_card_component.html.erb +38 -0
  60. data/templates/components/product_card/product_card_component.rb +49 -0
  61. data/templates/components/rich_text_editor_lite/rich_text_editor_lite_component.html.erb +1 -1
  62. data/templates/components/rich_text_editor_lite/rich_text_editor_lite_component.rb +1 -1
  63. data/templates/components/separator/separator_component.rb +7 -0
  64. data/templates/components/sheet/sheet_component.rb +1 -1
  65. data/templates/components/sidebar/sidebar_component.rb +2 -2
  66. data/templates/components/switch/switch_component.html.erb +2 -2
  67. data/templates/components/tooltip/tooltip_component.rb +2 -2
  68. data/templates/components/top_nav/top_nav_component.rb +2 -2
  69. data/templates/components/typography/typography_component.rb +7 -0
  70. data/templates/controllers/accordion_controller.js +1 -1
  71. data/templates/controllers/alert_dialog_controller.js +31 -7
  72. data/templates/controllers/cart_controller.js +83 -0
  73. data/templates/controllers/clipboard_controller.js +12 -1
  74. data/templates/controllers/command_controller.js +3 -4
  75. data/templates/controllers/context_menu_controller.js +38 -11
  76. data/templates/controllers/data_table_controller.js +8 -3
  77. data/templates/controllers/dialog_controller.js +47 -21
  78. data/templates/controllers/dropdown_menu_controller.js +40 -27
  79. data/templates/controllers/hover_card_controller.js +8 -0
  80. data/templates/controllers/invite_member_dialog_controller.js +6 -0
  81. data/templates/controllers/masked_input_controller.js +8 -1
  82. data/templates/controllers/popover_controller.js +25 -10
  83. data/templates/controllers/rich_text_editor_lite_controller.js +175 -28
  84. data/templates/controllers/sheet_controller.js +41 -11
  85. metadata +20 -6
  86. data/lib/senren/rails/installer.rb +0 -84
@@ -2,33 +2,63 @@ import { Controller } from "@hotwired/stimulus"
2
2
 
3
3
  // senren--sheet
4
4
  // Side panel; behaves like a dialog.
5
+ //
6
+ // State lives in `openValue`. Actions assign it; openValueChanged performs every
7
+ // DOM change, so the panel can be opened from the server and survives a morph.
5
8
  export default class extends Controller {
6
9
  static targets = ["overlay", "panel", "trigger"]
10
+ static values = { open: Boolean }
11
+
12
+ connect() {
13
+ this._onKey = this._onKey.bind(this)
14
+ this._onBeforeCache = this._onBeforeCache.bind(this)
15
+ document.addEventListener("turbo:before-cache", this._onBeforeCache)
16
+ }
7
17
 
8
- connect() { this._onKey = this._onKey.bind(this) }
9
18
  disconnect() {
10
19
  document.removeEventListener("keydown", this._onKey)
20
+ document.removeEventListener("turbo:before-cache", this._onBeforeCache)
11
21
  document.body.style.overflow = ""
12
22
  }
13
23
 
14
24
  open(event) {
15
25
  event?.preventDefault()
16
- this.overlayTarget.hidden = false
17
- this.panelTarget.hidden = false
18
- this.panelTarget.dataset.open = "true"
19
- document.addEventListener("keydown", this._onKey)
20
- document.body.style.overflow = "hidden"
21
- queueMicrotask(() => this.panelTarget?.focus())
26
+ this.openValue = true
22
27
  }
23
28
 
24
29
  close(event) {
25
30
  event?.preventDefault()
26
- this.overlayTarget.hidden = true
27
- this.panelTarget.hidden = true
28
- this.panelTarget.dataset.open = "false"
31
+ this.openValue = false
32
+ }
33
+
34
+ openValueChanged(isOpen, wasOpen) {
35
+ if (this.hasOverlayTarget) this.overlayTarget.hidden = !isOpen
36
+ if (this.hasPanelTarget) {
37
+ this.panelTarget.hidden = !isOpen
38
+ this.panelTarget.dataset.open = isOpen ? "true" : "false"
39
+ }
40
+
41
+ if (isOpen) {
42
+ document.addEventListener("keydown", this._onKey)
43
+ document.body.style.overflow = "hidden"
44
+ queueMicrotask(() => this.panelTarget?.focus())
45
+ this.dispatch("opened")
46
+ return
47
+ }
48
+
29
49
  document.removeEventListener("keydown", this._onKey)
30
50
  document.body.style.overflow = ""
51
+ if (wasOpen !== undefined) this.dispatch("closed")
52
+ }
53
+
54
+ _onKey(event) {
55
+ if (event.key === "Escape") this.close()
31
56
  }
32
57
 
33
- _onKey(event) { if (event.key === "Escape") this.close() }
58
+ // Turbo snapshots the page before navigating away; without this the scroll
59
+ // lock is captured while applied and a back navigation restores a page that
60
+ // cannot be scrolled.
61
+ _onBeforeCache() {
62
+ this.openValue = false
63
+ }
34
64
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: senren-ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - vutt
@@ -29,14 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: '3.0'
32
+ version: 4.9.0
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '3.0'
39
+ version: 4.9.0
40
40
  description: |
41
41
  Senren UI is a Rails-native UI component library inspired by the developer
42
42
  experience of shadcn/ui. It ships generators, a registry, and a centralized
@@ -53,7 +53,11 @@ files:
53
53
  - LICENSE
54
54
  - README.md
55
55
  - Rakefile
56
+ - docs/components.md
57
+ - docs/hot_reload.md
58
+ - docs/performance_testing.md
56
59
  - docs/visual_style.md
60
+ - lib/commands/senren/add/add_command.rb
57
61
  - lib/generators/senren/component/component_generator.rb
58
62
  - lib/generators/senren/component/templates/component.html.erb.tt
59
63
  - lib/generators/senren/component/templates/component.rb.tt
@@ -65,15 +69,20 @@ files:
65
69
  - lib/generators/senren/install/templates/conventions.md.tt
66
70
  - lib/generators/senren/install/templates/installed_components.yml.tt
67
71
  - lib/generators/senren/install/templates/senren.css.tt
72
+ - lib/senren-ui.rb
68
73
  - lib/senren/rails.rb
69
74
  - lib/senren/rails/agent_rules_writer.rb
75
+ - lib/senren/rails/asset_path_guard.rb
76
+ - lib/senren/rails/base_component_patch.rb
70
77
  - lib/senren/rails/component_copier.rb
78
+ - lib/senren/rails/component_installer.rb
71
79
  - lib/senren/rails/doctor.rb
72
80
  - lib/senren/rails/engine.rb
73
81
  - lib/senren/rails/host_paths.rb
74
- - lib/senren/rails/installer.rb
75
82
  - lib/senren/rails/llms_writer.rb
83
+ - lib/senren/rails/marker_block.rb
76
84
  - lib/senren/rails/registry.rb
85
+ - lib/senren/rails/safe_write.rb
77
86
  - lib/senren/rails/skill_writer.rb
78
87
  - lib/senren/rails/version.rb
79
88
  - lib/tasks/senren.rake
@@ -112,6 +121,8 @@ files:
112
121
  - templates/components/card/card_component.rb
113
122
  - templates/components/carousel/carousel_component.html.erb
114
123
  - templates/components/carousel/carousel_component.rb
124
+ - templates/components/cart/cart_component.html.erb
125
+ - templates/components/cart/cart_component.rb
115
126
  - templates/components/checkbox/checkbox_component.html.erb
116
127
  - templates/components/checkbox/checkbox_component.rb
117
128
  - templates/components/checkbox_group/checkbox_group_component.html.erb
@@ -162,6 +173,8 @@ files:
162
173
  - templates/components/pagination/pagination_component.rb
163
174
  - templates/components/popover/popover_component.html.erb
164
175
  - templates/components/popover/popover_component.rb
176
+ - templates/components/product_card/product_card_component.html.erb
177
+ - templates/components/product_card/product_card_component.rb
165
178
  - templates/components/progress/progress_component.html.erb
166
179
  - templates/components/progress/progress_component.rb
167
180
  - templates/components/radio_button/radio_button_component.html.erb
@@ -209,6 +222,7 @@ files:
209
222
  - templates/controllers/api_key_field_controller.js
210
223
  - templates/controllers/calendar_controller.js
211
224
  - templates/controllers/carousel_controller.js
225
+ - templates/controllers/cart_controller.js
212
226
  - templates/controllers/clipboard_controller.js
213
227
  - templates/controllers/collapsible_controller.js
214
228
  - templates/controllers/combobox_controller.js
@@ -245,14 +259,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
245
259
  requirements:
246
260
  - - ">="
247
261
  - !ruby/object:Gem::Version
248
- version: 3.1.0
262
+ version: 3.2.0
249
263
  required_rubygems_version: !ruby/object:Gem::Requirement
250
264
  requirements:
251
265
  - - ">="
252
266
  - !ruby/object:Gem::Version
253
267
  version: '0'
254
268
  requirements: []
255
- rubygems_version: 4.0.3
269
+ rubygems_version: 4.0.6
256
270
  specification_version: 4
257
271
  summary: Rails-native UI component library with ViewComponent, Hotwire, Tailwind,
258
272
  and AI-agent skill files.
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'fileutils'
4
-
5
- module Senren
6
- module Rails
7
- # Idempotent installer that lays down the .senren directory, base
8
- # component, stylesheet, and agent instruction files. Reused by the install
9
- # generator and by ad-hoc rake task entry points.
10
- class Installer
11
- attr_reader :paths, :stdout
12
-
13
- def initialize(paths: HostPaths.new, stdout: $stdout)
14
- @paths = paths
15
- @stdout = stdout
16
- end
17
-
18
- def run!(force: false)
19
- paths.ensure_dirs!
20
- install_static_files(force: force)
21
- mirror_registry
22
- SkillWriter.new(paths: paths).sync!
23
- AgentRulesWriter.new(paths: paths).sync!
24
- print_next_steps
25
- true
26
- end
27
-
28
- INSTALL_GENERATOR_TEMPLATES = File.expand_path(
29
- '../../generators/senren/install/templates', __dir__
30
- ).freeze
31
-
32
- STATIC_FILES = {
33
- 'conventions.md.tt' => :conventions_file,
34
- 'installed_components.yml.tt' => :installed_components,
35
- 'base_component.rb.tt' => :base_component_path,
36
- 'senren.css.tt' => :stylesheet_path
37
- }.freeze
38
-
39
- private
40
-
41
- def install_static_files(force:)
42
- STATIC_FILES.each do |template_basename, paths_method|
43
- src = File.join(INSTALL_GENERATOR_TEMPLATES, template_basename)
44
- dest = paths.public_send(paths_method)
45
- copy_template(src, dest, force: force)
46
- end
47
- end
48
-
49
- def copy_template(src, dest, force:)
50
- unless File.exist?(src)
51
- stdout.puts " warn template missing: #{src}"
52
- return
53
- end
54
- if File.exist?(dest) && !force
55
- stdout.puts " skip #{dest}"
56
- return
57
- end
58
- FileUtils.mkdir_p(File.dirname(dest))
59
- FileUtils.cp(src, dest)
60
- stdout.puts " copy #{dest}"
61
- end
62
-
63
- def mirror_registry
64
- FileUtils.mkdir_p(paths.registry_mirror.dirname)
65
- FileUtils.cp(Senren::Rails.registry_path, paths.registry_mirror)
66
- stdout.puts " mirror #{paths.registry_mirror}"
67
- end
68
-
69
- def print_next_steps
70
- stdout.puts <<~MSG
71
-
72
- Senren installed. Next steps:
73
-
74
- bin/rails senren:add button card badge alert
75
- bin/rails senren:add dialog dropdown_menu
76
- bin/rails senren:agents:sync
77
- bin/rails senren:doctor
78
-
79
- Read .senren/skill.md and .senren/conventions.md to get oriented.
80
- MSG
81
- end
82
- end
83
- end
84
- end