ariadne_view_components 0.0.96.13 → 0.0.97.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,13 @@
1
- <div
2
- data-controller="<%= stimulus_name %>"
3
- data-action="click@window-><%= stimulus_name %>#windowClick">
4
- <% if reveal_button? %>
5
- <%= reveal_button %>
6
- <% elsif reveal_link? %>
7
- <%= reveal_link %>
8
- <% end %>
1
+ <% unless reveal? %>
2
+ <%# Render only the dialog tag when no reveal trigger is provided %>
9
3
  <dialog
10
4
  class="<%= html_attrs[:class] %>"
11
5
  data-<%= stimulus_name %>-target="dialog"
6
+ data-controller="<%= stimulus_name %>"
12
7
  <%= html_attributes %>>
13
8
  <div class="ariadne:flex ariadne:flex-col ariadne:space-y-2 ariadne:text-center ariadne:sm:text-left">
14
9
  <span id="<%= dialog_id %>-title" class="ariadne:text-lg ariadne:font-semibold"><%= title %></span>
15
- <div data-labelled-by="<%= labelledby %>">
10
+ <div data-labelled-by="<%= labelledby %>" data-described-by="<%= describedby %>">
16
11
  <%= body %>
17
12
  </div>
18
13
  <% if footer? %>
@@ -21,10 +16,36 @@
21
16
  </div>
22
17
  <div class="ariadne:absolute ariadne:end-3 ariadne:top-3">
23
18
  <%= render Ariadne::UI::Button::Component.new(
24
- scheme: :nude,
25
- size: :xs,
26
- html_attrs: { "data-action": "click->#{stimulus_name}#close", aria: { label: dialog_close_label } }).as_icon(icon: "x-mark", variant: :outline) %>
27
- </div>
19
+ scheme: :nude,
20
+ size: :xs,
21
+ html_attrs: { "data-action": "click->#{stimulus_name}#close", aria: { label: dialog_close_label } }).as_icon(icon: "x-mark", variant: :outline) %>
28
22
  </div>
29
23
  </dialog>
24
+ <% else %>
25
+ <%# Render the wrapper div and the reveal trigger when one is provided %>
26
+ <div
27
+ data-controller="<%= stimulus_name %>"
28
+ data-action="click@window-><%= stimulus_name %>#windowClick">
29
+ <%= reveal %> <%# Render the provided button or link %>
30
+ <dialog
31
+ class="<%= html_attrs[:class] %>"
32
+ data-<%= stimulus_name %>-target="dialog"
33
+ <%= html_attributes %>>
34
+ <div class="ariadne:flex ariadne:flex-col ariadne:space-y-2 ariadne:text-center ariadne:sm:text-left">
35
+ <span id="<%= dialog_id %>-title" class="ariadne:text-lg ariadne:font-semibold"><%= title %></span>
36
+ <div data-labelled-by="<%= labelledby %>" data-described-by="<%= describedby %>">
37
+ <%= body %>
38
+ </div>
39
+ <% if footer? %>
40
+ <%= footer %>
41
+ <% end %>
42
+ </div>
43
+ <div class="ariadne:absolute ariadne:end-3 ariadne:top-3">
44
+ <%= render Ariadne::UI::Button::Component.new(
45
+ scheme: :nude,
46
+ size: :xs,
47
+ html_attrs: { "data-action": "click->#{stimulus_name}#close", aria: { label: dialog_close_label } }).as_icon(icon: "x-mark", variant: :outline) %>
48
+ </div>
49
+ </dialog>
30
50
  </div>
51
+ <% end %>
@@ -32,30 +32,34 @@ module Ariadne
32
32
  # @param [Symbol] width (:narrow) Indicates the width of the button. Can be either `:narrow` or `:full`.
33
33
  option :width, default: proc { :narrow }
34
34
 
35
+ # @!group Slots
36
+ # @!method reveal_button
35
37
  # The button to open the dialog.
36
38
  #
37
- # @param options [Hash] Same arguments as <%= link_to_component(Ariadne::UI::Button::Component) %>.
38
- renders_one :reveal_button, lambda { |**options|
39
- component_data_attrs = {
40
- action: "#{Ariadne::UI::Dialog::Component.stimulus_name}#open",
41
- }
42
-
43
- options[:html_attrs] ||= {}
44
- options[:html_attrs][:data] = merge_data_attributes(options[:html_attrs], component_data_attrs)
45
- Ariadne::UI::Button::Component.new(**options)
46
- }
47
-
39
+ # @param options [Hash] Same arguments as <%= link_to_component(Ariadne::UI::Button::Component) %>.\
40
+ # @!method reveal_link
48
41
  # A link to open the dialog.
49
42
  #
50
- # @param options [Hash] Same arguments as <%= link_to_component(Ariadne::UI::Link::Component) %>.
51
- renders_one :reveal_link, lambda { |**options|
52
- component_data_attrs = {
53
- action: "#{Ariadne::UI::Dialog::Component.stimulus_name}#open",
54
- }
55
-
56
- options[:html_attrs] ||= {}
57
- options[:html_attrs][:data] = merge_data_attributes(options[:html_attrs], component_data_attrs)
58
- Ariadne::UI::Link::Component.new(**options)
43
+ # @param options [Hash] Same arguments as <%= link_to_component(Ariadne::UI::Link::Component) %>.\
44
+ renders_one :reveal, types: {
45
+ button: lambda { |**options|
46
+ component_data_attrs = {
47
+ action: "#{stimulus_name}#open", # Use the component's stimulus_name method
48
+ }
49
+ options[:html_attrs] ||= {}
50
+ # Ensure merge_data_attributes helper exists and is used correctly
51
+ options[:html_attrs][:data] = merge_data_attributes(options.fetch(:html_attrs, {}), component_data_attrs)
52
+ Ariadne::UI::Button::Component.new(**options) # Pass remaining options
53
+ },
54
+ link: lambda { |**options|
55
+ component_data_attrs = {
56
+ action: "#{stimulus_name}#open", # Use the component's stimulus_name method
57
+ }
58
+ options[:html_attrs] ||= {}
59
+ # Ensure merge_data_attributes helper exists and is used correctly
60
+ options[:html_attrs][:data] = merge_data_attributes(options.fetch(:html_attrs, {}), component_data_attrs)
61
+ Ariadne::UI::Link::Component.new(**options) # Pass remaining options
62
+ },
59
63
  }
60
64
 
61
65
  # The main content within the dialog.
@@ -82,6 +86,9 @@ module Ariadne
82
86
  }
83
87
  )
84
88
 
89
+ component_data_attrs = {}
90
+ html_attrs[:data] = merge_data_attributes(html_attrs, component_data_attrs)
91
+
85
92
  html_attrs
86
93
  end
87
94
 
@@ -1,27 +1,87 @@
1
1
  import {controllerFactory} from '@utils/createController'
2
2
  import {disableBodyScroll, enableBodyScroll} from 'body-scroll-lock'
3
3
 
4
+ // Declare global registry type
5
+ declare global {
6
+ interface Window {
7
+ AriadneDialogRegistry?: Record<string, DialogController>
8
+ }
9
+ }
10
+
4
11
  export default class DialogController extends controllerFactory()({
5
12
  targets: {dialog: HTMLDialogElement},
13
+ // Remove the idValue as it's no longer needed
14
+ // values: {id: {type: String, default: ''}}
6
15
  }) {
7
- close(e?:MouseEvent) {
8
- if (!this.dialogTarget.open) return
9
- this.dialogTarget.close()
10
- enableBodyScroll(this.dialogTarget)
16
+ static values = {
17
+ dialogId: String // Expect dialogIdValue on the *trigger* element for external opening
18
+ }
19
+
20
+ connect() {
21
+ // Only register if this controller instance is directly on the <dialog> tag
22
+ // which indicates it was rendered without an inline reveal trigger.
23
+ if (this.element.tagName === 'DIALOG') {
24
+ // Create global registry if it doesn't exist
25
+ window.AriadneDialogRegistry = window.AriadneDialogRegistry || {}
26
+ // Use the dialog's actual ID for registration
27
+ window.AriadneDialogRegistry[this.element.id] = this
28
+ }
11
29
  }
12
30
 
13
31
  disconnect() {
32
+ // Only unregister if this controller instance is directly on the <dialog> tag
33
+ if (this.element.tagName === 'DIALOG') {
34
+ if (window.AriadneDialogRegistry && window.AriadneDialogRegistry[this.element.id]) {
35
+ delete window.AriadneDialogRegistry[this.element.id]
36
+ }
37
+ }
38
+ // Ensure scroll lock is released if component is destroyed while open
14
39
  this.close()
15
40
  }
16
41
 
17
- open(e: MouseEvent) {
42
+ close(e?: Event) { // Accept generic Event
43
+ // Find the actual dialog element, which might be a target or the element itself
44
+ const dialogElement = this.hasDialogTarget ? this.dialogTarget : this.element as HTMLDialogElement
45
+ if (!dialogElement.open) return
46
+ if (e) e.preventDefault(); // Prevent default if called from an event
47
+ dialogElement.close()
48
+ enableBodyScroll(dialogElement)
49
+ }
50
+
51
+ open(e?: Event) { // Accept generic Event
52
+ // Find the actual dialog element
53
+ const dialogElement = this.hasDialogTarget ? this.dialogTarget : this.element as HTMLDialogElement
54
+ if (dialogElement.open) return; // Don't re-open if already open
55
+ if (e) e.preventDefault(); // Prevent default if called from an event
56
+ dialogElement.showModal()
57
+ disableBodyScroll(dialogElement, {reserveScrollBarGap: true})
58
+ }
59
+
60
+ // Action called by an external trigger element (button/link)
61
+ // The trigger element must have:
62
+ // data-controller="ariadne-ui-dialog"
63
+ // data-action="click->ariadne-ui-dialog#openDialogExternally"
64
+ // data-ariadne-ui-dialog-dialog-id-value="the-target-dialog-id"
65
+ openDialogExternally(e: Event) {
18
66
  e.preventDefault();
19
- this.dialogTarget.showModal()
20
- disableBodyScroll(this.dialogTarget, {reserveScrollBarGap: true})
67
+ const targetDialogId = this.dialogIdValue; // Read value from the trigger element
68
+ if (!targetDialogId) {
69
+ console.error("Dialog trigger clicked without a data-ariadne-ui-dialog-dialog-id-value attribute.");
70
+ return;
71
+ }
72
+
73
+ const targetDialogController = window.AriadneDialogRegistry?.[targetDialogId];
74
+ if (targetDialogController) {
75
+ targetDialogController.open(); // Call open on the *target* dialog controller
76
+ } else {
77
+ console.error(`Dialog with ID "${targetDialogId}" not found in registry.`);
78
+ }
21
79
  }
22
80
 
23
81
  windowClick(e: MouseEvent) {
24
- if (e.target === this.dialogTarget) {
82
+ // Use dialogTarget if available (when controller is on wrapper), otherwise use element (when controller is on dialog)
83
+ const dialogElement = this.hasDialogTarget ? this.dialogTarget : this.element as HTMLDialogElement
84
+ if (e.target === dialogElement) {
25
85
  this.close()
26
86
  }
27
87
  }
@@ -0,0 +1,47 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ // Import DialogController for type reference
4
+ import DialogController from '../dialog/component'
5
+
6
+ // Declare global registry type
7
+ declare global {
8
+ interface Window {
9
+ AriadneDialogRegistry?: Record<string, DialogController>
10
+ }
11
+ }
12
+
13
+ interface HTMLDialogElement extends HTMLElement {
14
+ showModal(): void;
15
+ close(): void;
16
+ open: boolean;
17
+ }
18
+
19
+ export default class DialogTriggerController extends Controller {
20
+ static values = {
21
+ dialogId: String
22
+ }
23
+
24
+ // TypeScript property definitions
25
+ declare readonly dialogIdValue: string
26
+
27
+ openDialog(event: MouseEvent) {
28
+ event.preventDefault()
29
+
30
+ // Find the dialog in the registry
31
+ const registry = window.AriadneDialogRegistry || {}
32
+ const dialogController = registry[this.dialogIdValue]
33
+
34
+ if (dialogController) {
35
+ // Use the dialog controller's open method
36
+ dialogController.open()
37
+ } else {
38
+ // Fallback to finding by ID if not in registry
39
+ const dialog = document.getElementById(this.dialogIdValue) as HTMLDialogElement | null
40
+ if (dialog && dialog.tagName === 'DIALOG') {
41
+ dialog.showModal()
42
+ } else {
43
+ console.warn(`Dialog with ID ${this.dialogIdValue} not found`)
44
+ }
45
+ }
46
+ }
47
+ }
@@ -86,7 +86,7 @@
86
86
  --theme-color-muted-foreground: oklch(0.71 0.0129 286.07);
87
87
  --theme-color-popover: oklch(0.14 0.0044 285.82);
88
88
  --theme-color-popover-foreground: oklch(0.98 0 0);
89
- --theme-color-card: oklch(0.14 0.0044 285.82);
89
+ --theme-color-card: oklch(0.195313 0.040625 300);
90
90
  --theme-color-card-foreground: oklch(0.98 0 0);
91
91
 
92
92
  /* Semantic colors */
@@ -3,6 +3,6 @@
3
3
  # :nocov:
4
4
  module Ariadne
5
5
  module ViewComponents
6
- VERSION = "0.0.96.13"
6
+ VERSION = "0.0.97.1"
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ariadne_view_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.96.13
4
+ version: 0.0.97.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen J. Torikian
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-08 00:00:00.000000000 Z
11
+ date: 2025-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tailwind_merge
@@ -163,6 +163,7 @@ files:
163
163
  - app/components/ariadne/form/toggle_group/option/component.rb
164
164
  - app/components/ariadne/form/validation_message/component.html.erb
165
165
  - app/components/ariadne/form/validation_message/component.rb
166
+ - app/components/ariadne/layout/content/README.md
166
167
  - app/components/ariadne/layout/content/component.html.erb
167
168
  - app/components/ariadne/layout/content/component.rb
168
169
  - app/components/ariadne/layout/grid/component.html.erb
@@ -232,6 +233,7 @@ files:
232
233
  - app/components/ariadne/ui/dialog/component.ts
233
234
  - app/components/ariadne/ui/dialog/footer/component.html.erb
234
235
  - app/components/ariadne/ui/dialog/footer/component.rb
236
+ - app/components/ariadne/ui/dialog_trigger/component.ts
235
237
  - app/components/ariadne/ui/heroicon/component.html.erb
236
238
  - app/components/ariadne/ui/heroicon/component.rb
237
239
  - app/components/ariadne/ui/image/component.rb