lightning_ui_kit 0.2.3 → 0.2.5

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/Rakefile +9 -2
  4. data/app/assets/builds/lightning_ui_kit.css +588 -31
  5. data/app/assets/builds/lightning_ui_kit.js +9 -2
  6. data/app/assets/builds/lightning_ui_kit.js.map +4 -4
  7. data/app/assets/vendor/lightning_ui_kit.css +582 -88
  8. data/app/assets/vendor/lightning_ui_kit.js +9 -2
  9. data/app/components/lightning_ui_kit/button_component.html.erb +4 -0
  10. data/app/components/lightning_ui_kit/button_component.rb +24 -3
  11. data/app/components/lightning_ui_kit/combobox_component.html.erb +137 -0
  12. data/app/components/lightning_ui_kit/combobox_component.rb +205 -0
  13. data/app/components/lightning_ui_kit/dropdown_component.html.erb +1 -1
  14. data/app/components/lightning_ui_kit/dropdown_component.rb +1 -1
  15. data/app/components/lightning_ui_kit/dropzone_component.html.erb +13 -38
  16. data/app/components/lightning_ui_kit/dropzone_component.rb +43 -16
  17. data/app/components/lightning_ui_kit/file_input_component.html.erb +4 -34
  18. data/app/components/lightning_ui_kit/file_input_component.rb +54 -20
  19. data/app/components/lightning_ui_kit/input_component.html.erb +14 -98
  20. data/app/components/lightning_ui_kit/input_component.rb +154 -19
  21. data/app/components/lightning_ui_kit/layout_component.html.erb +118 -0
  22. data/app/components/lightning_ui_kit/layout_component.rb +26 -0
  23. data/app/components/lightning_ui_kit/modal_component.html.erb +2 -2
  24. data/app/components/lightning_ui_kit/select_component.html.erb +6 -27
  25. data/app/components/lightning_ui_kit/select_component.rb +65 -23
  26. data/app/components/lightning_ui_kit/sidebar_link_component.html.erb +6 -0
  27. data/app/components/lightning_ui_kit/sidebar_link_component.rb +33 -0
  28. data/app/components/lightning_ui_kit/sidebar_section_component.html.erb +8 -0
  29. data/app/components/lightning_ui_kit/sidebar_section_component.rb +18 -0
  30. data/app/components/lightning_ui_kit/textarea_component.html.erb +5 -37
  31. data/app/components/lightning_ui_kit/textarea_component.rb +50 -17
  32. data/app/components/lightning_ui_kit/tooltip_component.html.erb +15 -0
  33. data/app/components/lightning_ui_kit/tooltip_component.rb +26 -0
  34. data/app/javascript/lightning_ui_kit/controllers/combobox_controller.js +704 -0
  35. data/app/javascript/lightning_ui_kit/controllers/field_controller.js +23 -0
  36. data/app/javascript/lightning_ui_kit/controllers/layout_controller.js +19 -0
  37. data/app/javascript/lightning_ui_kit/controllers/modal_controller.js +7 -1
  38. data/app/javascript/lightning_ui_kit/controllers/tooltip_controller.js +235 -0
  39. data/app/javascript/lightning_ui_kit/index.js +8 -0
  40. data/config/deploy.yml +2 -5
  41. data/lib/lightning_ui_kit/engine.rb +1 -6
  42. data/lib/lightning_ui_kit/version.rb +1 -1
  43. metadata +17 -17
@@ -0,0 +1,23 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = ["field"]
5
+
6
+ fieldTargetConnected(element) {
7
+ element.addEventListener("mouseenter", this.handleMouseEnter)
8
+ element.addEventListener("mouseleave", this.handleMouseLeave)
9
+ }
10
+
11
+ fieldTargetDisconnected(element) {
12
+ element.removeEventListener("mouseenter", this.handleMouseEnter)
13
+ element.removeEventListener("mouseleave", this.handleMouseLeave)
14
+ }
15
+
16
+ handleMouseEnter = (event) => {
17
+ event.target.dataset.hover = ""
18
+ }
19
+
20
+ handleMouseLeave = (event) => {
21
+ delete event.target.dataset.hover
22
+ }
23
+ }
@@ -0,0 +1,19 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = ["overlay"]
5
+
6
+ openSidebar() {
7
+ this.overlayTarget.dataset.open = ""
8
+ document.body.style.overflow = "hidden"
9
+ }
10
+
11
+ closeSidebar() {
12
+ delete this.overlayTarget.dataset.open
13
+ document.body.style.overflow = ""
14
+ }
15
+
16
+ disconnect() {
17
+ document.body.style.overflow = ""
18
+ }
19
+ }
@@ -1,7 +1,7 @@
1
1
  import { Controller } from "@hotwired/stimulus"
2
2
 
3
3
  export default class extends Controller {
4
- static targets = ["dialog"]
4
+ static targets = ["dialog", "panel"]
5
5
  static values = {
6
6
  open: Boolean
7
7
  }
@@ -38,6 +38,12 @@ export default class extends Controller {
38
38
  }
39
39
  }
40
40
 
41
+ closeOnBackdrop(event) {
42
+ if (this.hasPanelTarget && !this.panelTarget.contains(event.target)) {
43
+ this.close()
44
+ }
45
+ }
46
+
41
47
  submitForm() {
42
48
  this.dialogTarget.querySelector("form").requestSubmit()
43
49
  }
@@ -0,0 +1,235 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import { computePosition, autoUpdate, offset, flip, shift, arrow, size } from "@floating-ui/dom"
3
+
4
+ export default class extends Controller {
5
+ static targets = ["template"]
6
+ static values = {
7
+ active: Boolean,
8
+ position: String,
9
+ delay: { type: Number, default: 0 },
10
+ offset: { type: Number, default: 8 }
11
+ }
12
+
13
+ connect() {
14
+ this.showTimeout = null
15
+ this.hideTimeout = null
16
+ this.cleanup = null
17
+
18
+ // Handle ESC key to close tooltip
19
+ this.handleKeydown = this.handleKeydown.bind(this)
20
+
21
+ // Handle touch devices - click to toggle
22
+ if ('ontouchstart' in window) {
23
+ this.element.addEventListener('click', this.toggle.bind(this))
24
+ }
25
+ }
26
+
27
+ disconnect() {
28
+ this.hide()
29
+ this.clearTimeouts()
30
+
31
+ if ('ontouchstart' in window) {
32
+ this.element.removeEventListener('click', this.toggle.bind(this))
33
+ }
34
+ }
35
+
36
+ show(event) {
37
+ if (!this.activeValue) return
38
+
39
+ // Prevent multiple tooltips
40
+ this.hideOtherTooltips()
41
+
42
+ // Clear any pending hide
43
+ this.clearTimeouts()
44
+
45
+ if (this.delayValue > 0) {
46
+ this.showTimeout = setTimeout(() => this.createTooltip(event), this.delayValue)
47
+ } else {
48
+ this.createTooltip(event)
49
+ }
50
+ }
51
+
52
+ hide() {
53
+ this.clearTimeouts()
54
+
55
+ if (this.delayValue > 0) {
56
+ this.hideTimeout = setTimeout(() => this.destroyTooltip(), this.delayValue)
57
+ } else {
58
+ this.destroyTooltip()
59
+ }
60
+ }
61
+
62
+ toggle(event) {
63
+ if (this.tooltip) {
64
+ this.hide()
65
+ } else {
66
+ this.show(event)
67
+ }
68
+ }
69
+
70
+ createTooltip(event) {
71
+ if (this.tooltip) return
72
+
73
+ const triggerElement = event?.currentTarget || this.element
74
+
75
+ try {
76
+ // Create tooltip element
77
+ const tooltip = document.createElement("div")
78
+ tooltip.innerHTML = this.templateTarget.innerHTML
79
+ tooltip.style.position = "absolute"
80
+ tooltip.style.zIndex = "9999"
81
+ tooltip.setAttribute('role', 'tooltip')
82
+ tooltip.setAttribute('data-lui-tooltip-instance', 'true')
83
+ document.body.appendChild(tooltip)
84
+ this.tooltip = tooltip
85
+
86
+ // Find the actual tooltip content (first child)
87
+ const tooltipContent = tooltip.firstElementChild
88
+ const arrowElement = tooltipContent?.querySelector("[data-tooltip-arrow]")
89
+
90
+ if (tooltipContent) {
91
+ // Set up auto-updating position
92
+ this.cleanup = autoUpdate(
93
+ triggerElement,
94
+ tooltipContent,
95
+ () => this.updatePosition(triggerElement, tooltipContent, arrowElement)
96
+ )
97
+
98
+ // Trigger fade-in animation
99
+ requestAnimationFrame(() => {
100
+ tooltipContent.style.opacity = '1'
101
+ })
102
+
103
+ // Add keyboard listener
104
+ document.addEventListener('keydown', this.handleKeydown)
105
+ }
106
+ } catch (error) {
107
+ console.warn('Tooltip positioning failed:', error)
108
+ this.destroyTooltip()
109
+ }
110
+ }
111
+
112
+ destroyTooltip() {
113
+ if (this.cleanup) {
114
+ this.cleanup()
115
+ this.cleanup = null
116
+ }
117
+
118
+ if (this.tooltip) {
119
+ const tooltipContent = this.tooltip.firstElementChild
120
+
121
+ if (tooltipContent) {
122
+ // Fade out animation
123
+ tooltipContent.style.opacity = '0'
124
+
125
+ // Remove after transition completes
126
+ setTimeout(() => {
127
+ if (this.tooltip) {
128
+ this.tooltip.remove()
129
+ this.tooltip = null
130
+ }
131
+ }, 200) // Match the transition duration
132
+ } else {
133
+ this.tooltip.remove()
134
+ this.tooltip = null
135
+ }
136
+ }
137
+
138
+ document.removeEventListener('keydown', this.handleKeydown)
139
+ }
140
+
141
+ updatePosition(triggerElement, tooltipContent, arrowElement) {
142
+ if (!tooltipContent) return
143
+
144
+ computePosition(triggerElement, tooltipContent, {
145
+ placement: this.positionValue || "bottom",
146
+ middleware: [
147
+ offset(this.offsetValue),
148
+ size(),
149
+ flip(),
150
+ shift({ padding: 5 }),
151
+ ...(arrowElement ? [arrow({ element: arrowElement })] : [])
152
+ ],
153
+ }).then(({ x, y, placement, middlewareData }) => {
154
+ Object.assign(tooltipContent.style, {
155
+ left: `${x}px`,
156
+ top: `${y}px`,
157
+ })
158
+
159
+ if (arrowElement && middlewareData.arrow) {
160
+ this.positionArrow(arrowElement, placement, middlewareData.arrow)
161
+ }
162
+ }).catch(error => {
163
+ console.warn('Tooltip positioning update failed:', error)
164
+ })
165
+ }
166
+
167
+ positionArrow(arrowElement, placement, arrowData) {
168
+ const { x: arrowX, y: arrowY } = arrowData
169
+ const primaryPlacement = placement.split('-')[0]
170
+
171
+ // Reset arrow styles
172
+ Object.assign(arrowElement.style, {
173
+ left: '',
174
+ top: '',
175
+ right: '',
176
+ bottom: '',
177
+ })
178
+
179
+ const arrowOffset = '-4px'
180
+
181
+ switch (primaryPlacement) {
182
+ case 'top':
183
+ Object.assign(arrowElement.style, {
184
+ left: arrowX != null ? `${arrowX}px` : '',
185
+ bottom: arrowOffset,
186
+ })
187
+ break
188
+ case 'bottom':
189
+ Object.assign(arrowElement.style, {
190
+ left: arrowX != null ? `${arrowX}px` : '',
191
+ top: arrowOffset,
192
+ })
193
+ break
194
+ case 'left':
195
+ Object.assign(arrowElement.style, {
196
+ top: arrowY != null ? `${arrowY}px` : '',
197
+ right: arrowOffset,
198
+ })
199
+ break
200
+ case 'right':
201
+ Object.assign(arrowElement.style, {
202
+ top: arrowY != null ? `${arrowY}px` : '',
203
+ left: arrowOffset,
204
+ })
205
+ break
206
+ }
207
+ }
208
+
209
+ handleKeydown(event) {
210
+ if (event.key === 'Escape' && this.tooltip) {
211
+ this.hide()
212
+ }
213
+ }
214
+
215
+ hideOtherTooltips() {
216
+ // Hide any other active tooltips
217
+ document.querySelectorAll('[data-lui-tooltip-instance="true"]').forEach(tooltip => {
218
+ if (tooltip !== this.tooltip) {
219
+ tooltip.remove()
220
+ }
221
+ })
222
+ }
223
+
224
+ clearTimeouts() {
225
+ if (this.showTimeout) {
226
+ clearTimeout(this.showTimeout)
227
+ this.showTimeout = null
228
+ }
229
+
230
+ if (this.hideTimeout) {
231
+ clearTimeout(this.hideTimeout)
232
+ this.hideTimeout = null
233
+ }
234
+ }
235
+ }
@@ -11,6 +11,7 @@ window.Stimulus = application
11
11
  import ClipboardController from './controllers/clipboard_controller'
12
12
  import CheckboxController from './controllers/checkbox_controller'
13
13
  import BannerController from './controllers/banner_controller'
14
+ import LayoutController from './controllers/layout_controller'
14
15
  import MainController from './controllers/main_controller'
15
16
  import AccordionController from './controllers/accordion_controller'
16
17
  import ModalController from './controllers/modal_controller'
@@ -19,11 +20,15 @@ import SwitchController from './controllers/switch_controller'
19
20
  import DropdownController from './controllers/dropdown_controller'
20
21
  import DropzoneController from './controllers/dropzone_controller'
21
22
  import ToastController from './controllers/toast_controller'
23
+ import TooltipController from './controllers/tooltip_controller'
24
+ import ComboboxController from './controllers/combobox_controller'
25
+ import FieldController from './controllers/field_controller'
22
26
 
23
27
  export function registerLuiControllers(application) {
24
28
  application.register(`${namespace}-clipboard`, ClipboardController)
25
29
  application.register(`${namespace}-checkbox`, CheckboxController)
26
30
  application.register(`${namespace}-banner`, BannerController)
31
+ application.register(`${namespace}-layout`, LayoutController)
27
32
  application.register(`${namespace}-main`, MainController)
28
33
  application.register(`${namespace}-accordion`, AccordionController)
29
34
  application.register(`${namespace}-modal`, ModalController)
@@ -32,6 +37,9 @@ export function registerLuiControllers(application) {
32
37
  application.register(`${namespace}-dropdown`, DropdownController)
33
38
  application.register(`${namespace}-dropzone`, DropzoneController)
34
39
  application.register(`${namespace}-toast`, ToastController)
40
+ application.register(`${namespace}-tooltip`, TooltipController)
41
+ application.register(`${namespace}-combobox`, ComboboxController)
42
+ application.register(`${namespace}-field`, FieldController)
35
43
  }
36
44
  registerLuiControllers(application)
37
45
 
data/config/deploy.yml CHANGED
@@ -5,10 +5,7 @@ ssh:
5
5
  user: www
6
6
 
7
7
  registry:
8
- server: ghcr.io
9
- username: k0va1
10
- password:
11
- - KAMAL_REGISTRY_PASSWORD
8
+ server: "localhost:5555"
12
9
 
13
10
  builder:
14
11
  arch: amd64
@@ -37,8 +34,8 @@ env:
37
34
 
38
35
  proxy:
39
36
  ssl: false
37
+ host: ui.k0va1.dev
40
38
  app_port: 8000
41
- host: ui.lightningrails.xyz
42
39
  forward_headers: true
43
40
  healthcheck:
44
41
  interval: 3
@@ -4,12 +4,7 @@ module LightningUiKit
4
4
  class Engine < ::Rails::Engine
5
5
  isolate_namespace LightningUiKit
6
6
 
7
- config.autoload_paths = %W[
8
- #{root}/app/components
9
- #{root}/app/helpers
10
- ]
11
-
12
- initializer "lightning_ui_kit.helpers" do
7
+ config.to_prepare do
13
8
  ActiveSupport.on_load(:action_controller_base) do
14
9
  helper LightningUiKit::ApplicationHelper
15
10
  helper LightningUiKit::HeroiconHelper
@@ -1,3 +1,3 @@
1
1
  module LightningUiKit
2
- VERSION = "0.2.3"
2
+ VERSION = "0.2.5"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lightning_ui_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Koval
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-08-04 00:00:00.000000000 Z
11
+ date: 2026-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -80,20 +80,6 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rspec-rails
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
83
  description: Lightning UI is a collection of UI components for Rails applications
98
84
  email:
99
85
  - al3xander.koval@gmail.com
@@ -123,6 +109,8 @@ files:
123
109
  - app/components/lightning_ui_kit/button_component.rb
124
110
  - app/components/lightning_ui_kit/checkbox_component.html.erb
125
111
  - app/components/lightning_ui_kit/checkbox_component.rb
112
+ - app/components/lightning_ui_kit/combobox_component.html.erb
113
+ - app/components/lightning_ui_kit/combobox_component.rb
126
114
  - app/components/lightning_ui_kit/description_list/item_component.html.erb
127
115
  - app/components/lightning_ui_kit/description_list/item_component.rb
128
116
  - app/components/lightning_ui_kit/description_list_component.html.erb
@@ -137,6 +125,8 @@ files:
137
125
  - app/components/lightning_ui_kit/file_input_component.rb
138
126
  - app/components/lightning_ui_kit/input_component.html.erb
139
127
  - app/components/lightning_ui_kit/input_component.rb
128
+ - app/components/lightning_ui_kit/layout_component.html.erb
129
+ - app/components/lightning_ui_kit/layout_component.rb
140
130
  - app/components/lightning_ui_kit/link_component.html.erb
141
131
  - app/components/lightning_ui_kit/link_component.rb
142
132
  - app/components/lightning_ui_kit/modal_component.html.erb
@@ -147,6 +137,10 @@ files:
147
137
  - app/components/lightning_ui_kit/select_component.rb
148
138
  - app/components/lightning_ui_kit/sidebar_component.html.erb
149
139
  - app/components/lightning_ui_kit/sidebar_component.rb
140
+ - app/components/lightning_ui_kit/sidebar_link_component.html.erb
141
+ - app/components/lightning_ui_kit/sidebar_link_component.rb
142
+ - app/components/lightning_ui_kit/sidebar_section_component.html.erb
143
+ - app/components/lightning_ui_kit/sidebar_section_component.rb
150
144
  - app/components/lightning_ui_kit/skeleton_component.html.erb
151
145
  - app/components/lightning_ui_kit/skeleton_component.rb
152
146
  - app/components/lightning_ui_kit/spinner_component.html.erb
@@ -163,19 +157,25 @@ files:
163
157
  - app/components/lightning_ui_kit/textarea_component.rb
164
158
  - app/components/lightning_ui_kit/toast_component.html.erb
165
159
  - app/components/lightning_ui_kit/toast_component.rb
160
+ - app/components/lightning_ui_kit/tooltip_component.html.erb
161
+ - app/components/lightning_ui_kit/tooltip_component.rb
166
162
  - app/helpers/lightning_ui_kit/application_helper.rb
167
163
  - app/helpers/lightning_ui_kit/heroicon_helper.rb
168
164
  - app/javascript/lightning_ui_kit/controllers/accordion_controller.js
169
165
  - app/javascript/lightning_ui_kit/controllers/banner_controller.js
170
166
  - app/javascript/lightning_ui_kit/controllers/checkbox_controller.js
171
167
  - app/javascript/lightning_ui_kit/controllers/clipboard_controller.js
168
+ - app/javascript/lightning_ui_kit/controllers/combobox_controller.js
172
169
  - app/javascript/lightning_ui_kit/controllers/dropdown_controller.js
173
170
  - app/javascript/lightning_ui_kit/controllers/dropzone_controller.js
171
+ - app/javascript/lightning_ui_kit/controllers/field_controller.js
172
+ - app/javascript/lightning_ui_kit/controllers/layout_controller.js
174
173
  - app/javascript/lightning_ui_kit/controllers/main_controller.js
175
174
  - app/javascript/lightning_ui_kit/controllers/modal_controller.js
176
175
  - app/javascript/lightning_ui_kit/controllers/reveal_controller.js
177
176
  - app/javascript/lightning_ui_kit/controllers/switch_controller.js
178
177
  - app/javascript/lightning_ui_kit/controllers/toast_controller.js
178
+ - app/javascript/lightning_ui_kit/controllers/tooltip_controller.js
179
179
  - app/javascript/lightning_ui_kit/index.js
180
180
  - config/deploy.yml
181
181
  - config/initializers/heroicons.rb
@@ -189,7 +189,7 @@ licenses:
189
189
  metadata:
190
190
  homepage_uri: https://github.com/k0va1/lightning_ui_kit
191
191
  source_code_uri: https://github.com/k0va1/lightning_ui_kit
192
- changelog_uri: https://github.com/k0va1/lightning_ui_kit/blob/main/CHANGELOG.md
192
+ changelog_uri: https://github.com/k0va1/lightning_ui_kit/blob/master/CHANGELOG.md
193
193
  post_install_message:
194
194
  rdoc_options: []
195
195
  require_paths: