ariadne_view_components 0.0.47 → 0.0.48

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -25
  3. data/app/assets/javascripts/ariadne_view_components.js +2 -2
  4. data/app/assets/javascripts/ariadne_view_components.js.map +1 -1
  5. data/app/assets/javascripts/components/ariadne/accumulator_controller/accumulator_controller.d.ts +22 -0
  6. data/app/assets/javascripts/components/ariadne/dropdown/menu_component.d.ts +1 -0
  7. data/app/assets/javascripts/components/ariadne/options_controller/options_controller.d.ts +21 -0
  8. data/app/assets/javascripts/components/ariadne/toggleable_controller/toggleable_controller.d.ts +34 -0
  9. data/app/assets/stylesheets/ariadne_view_components.css +3 -3
  10. data/app/components/ariadne/accumulator_controller/accumulator_controller.d.ts +22 -0
  11. data/app/components/ariadne/accumulator_controller/accumulator_controller.js +39 -0
  12. data/app/components/ariadne/accumulator_controller/accumulator_controller.ts +48 -0
  13. data/app/components/ariadne/action_card_component.html.erb +11 -0
  14. data/app/components/ariadne/action_card_component.rb +45 -0
  15. data/app/components/ariadne/ariadne.js +6 -0
  16. data/app/components/ariadne/ariadne.ts +6 -0
  17. data/app/components/ariadne/bottom_tab_component.html.erb +4 -0
  18. data/app/components/ariadne/bottom_tab_component.rb +44 -0
  19. data/app/components/ariadne/bottom_tab_nav_component.html.erb +5 -0
  20. data/app/components/ariadne/bottom_tab_nav_component.rb +33 -0
  21. data/app/components/ariadne/breadcrumbs_component.html.erb +13 -0
  22. data/app/components/ariadne/breadcrumbs_component.rb +31 -0
  23. data/app/components/ariadne/checkbox_component.html.erb +5 -0
  24. data/app/components/ariadne/checkbox_component.rb +43 -0
  25. data/app/components/ariadne/close_button_component.html.erb +4 -0
  26. data/app/components/ariadne/close_button_component.rb +32 -0
  27. data/app/components/ariadne/dropdown/menu_component.d.ts +1 -0
  28. data/app/components/ariadne/dropdown/menu_component.js +1 -0
  29. data/app/components/ariadne/options_controller/options_controller.d.ts +21 -0
  30. data/app/components/ariadne/options_controller/options_controller.js +50 -0
  31. data/app/components/ariadne/options_controller/options_controller.ts +57 -0
  32. data/app/components/ariadne/popover_component.html.erb +11 -0
  33. data/app/components/ariadne/popover_component.rb +81 -0
  34. data/app/components/ariadne/progress_bar_component.html.erb +5 -0
  35. data/app/components/ariadne/progress_bar_component.rb +63 -0
  36. data/app/components/ariadne/relative_time_component.html.erb +3 -0
  37. data/app/components/ariadne/relative_time_component.rb +61 -0
  38. data/app/components/ariadne/show_more_button_component.html.erb +11 -0
  39. data/app/components/ariadne/show_more_button_component.rb +47 -0
  40. data/app/components/ariadne/spinner_component.html.erb +16 -0
  41. data/app/components/ariadne/spinner_component.rb +45 -0
  42. data/app/components/ariadne/subheader_component.html.erb +11 -0
  43. data/app/components/ariadne/subheader_component.rb +65 -0
  44. data/app/components/ariadne/toggle_component/toggle_component.html.erb +15 -0
  45. data/app/components/ariadne/toggle_component.rb +95 -0
  46. data/app/components/ariadne/toggleable_controller/toggleable_controller.d.ts +34 -0
  47. data/app/components/ariadne/toggleable_controller/toggleable_controller.js +74 -0
  48. data/app/components/ariadne/toggleable_controller/toggleable_controller.ts +87 -0
  49. data/lib/ariadne/view_components/version.rb +1 -1
  50. data/static/arguments.yml +50 -0
  51. data/static/audited_at.json +14 -0
  52. data/static/classes.yml +209 -173
  53. data/static/constants.json +282 -0
  54. data/static/statuses.json +14 -0
  55. data/tailwind.config.js +7 -7
  56. metadata +53 -12
  57. /data/app/assets/javascripts/{ariadne-form.d.ts → components/ariadne/ariadne-form.d.ts} +0 -0
  58. /data/app/assets/javascripts/{ariadne.d.ts → components/ariadne/ariadne.d.ts} +0 -0
  59. /data/app/assets/javascripts/{clipboard_copy_component → components/ariadne/clipboard_copy_component}/clipboard-copy-component.d.ts +0 -0
  60. /data/app/assets/javascripts/{rich_text_area_component → components/ariadne/rich_text_area_component}/rich-text-area-component.d.ts +0 -0
  61. /data/app/assets/javascripts/{slideover_component → components/ariadne/slideover_component}/slideover-component.d.ts +0 -0
  62. /data/app/assets/javascripts/{tab_container_component → components/ariadne/tab_container_component}/tab-container-component.d.ts +0 -0
  63. /data/app/assets/javascripts/{tab_nav_component → components/ariadne/tab_nav_component}/tab-nav-component.d.ts +0 -0
  64. /data/app/assets/javascripts/{time_ago_component → components/ariadne/time_ago_component}/time-ago-component.d.ts +0 -0
  65. /data/app/assets/javascripts/{tooltip_component → components/ariadne/tooltip_component}/tooltip-component.d.ts +0 -0
@@ -0,0 +1,22 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class AccumulatorController extends Controller {
3
+ static targets: string[];
4
+ static values: {
5
+ syncAttrs: {
6
+ type: ArrayConstructor;
7
+ default: string[];
8
+ };
9
+ sumAttr: {
10
+ type: string;
11
+ default: string;
12
+ };
13
+ };
14
+ sumTargets: Array<HTMLElement>;
15
+ accumulatorTarget?: HTMLElement;
16
+ syncAttrsValue: Array<string>;
17
+ sumAttrValue: string;
18
+ connect(): void;
19
+ accumulate(): void;
20
+ setAttributesTo(sum: number): void;
21
+ get accumulator(): Element;
22
+ }
@@ -0,0 +1 @@
1
+ import '@github/details-menu-element';
@@ -0,0 +1,21 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class OptionsController extends Controller {
3
+ #private;
4
+ static targets: string[];
5
+ static values: {
6
+ activeIndex: {
7
+ type: NumberConstructor;
8
+ default: number;
9
+ };
10
+ syncedAttrs: ArrayConstructor;
11
+ antiAttrs: ArrayConstructor;
12
+ };
13
+ readonly optionTargets: Array<Element>;
14
+ activeIndexValue: number;
15
+ readonly syncedAttrsValue: string[];
16
+ readonly hasSyncedAttrsValue: boolean;
17
+ readonly antiAttrsValue: string[];
18
+ readonly hasAntiAttrsValue: boolean;
19
+ connect(): void;
20
+ select(e: Event, newIndex?: number): void;
21
+ }
@@ -0,0 +1,34 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export interface ToggleableOutlet {
3
+ toggle: (event: Event, value?: boolean) => void;
4
+ }
5
+ export default class ToggleableController extends Controller implements ToggleableOutlet {
6
+ #private;
7
+ static outlets: string[];
8
+ static values: {
9
+ state: {
10
+ type: BooleanConstructor;
11
+ default: boolean;
12
+ };
13
+ syncedAttrs: ArrayConstructor;
14
+ antiAttrs: ArrayConstructor;
15
+ closeOnOutsideClick: {
16
+ type: BooleanConstructor;
17
+ default: boolean;
18
+ };
19
+ };
20
+ static removeOnFalseAttrs: {
21
+ [k: string]: boolean;
22
+ };
23
+ stateValue: boolean;
24
+ readonly toggleableOutlets: Array<ToggleableOutlet>;
25
+ readonly hasToggleableOutlet: boolean;
26
+ readonly syncedAttrsValue: string[];
27
+ readonly hasSyncedAttrsValue: boolean;
28
+ readonly antiAttrsValue: string[];
29
+ readonly hasAntiAttrsValue: boolean;
30
+ readonly closeOnOutsideClickValue: boolean;
31
+ connect(): void;
32
+ toggle(event: Event, value?: boolean): void;
33
+ clickOutside(event: Event): void;
34
+ }
@@ -1,6 +1,6 @@
1
- @import 'tailwindcss/base';
2
- @import 'tailwindcss/components';
3
- @import 'tailwindcss/utilities';
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
4
 
5
5
  @import 'tooltip-component.css';
6
6
  @import 'prosemirror.css';
@@ -0,0 +1,22 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class AccumulatorController extends Controller {
3
+ static targets: string[];
4
+ static values: {
5
+ syncAttrs: {
6
+ type: ArrayConstructor;
7
+ default: string[];
8
+ };
9
+ sumAttr: {
10
+ type: string;
11
+ default: string;
12
+ };
13
+ };
14
+ sumTargets: Array<HTMLElement>;
15
+ accumulatorTarget?: HTMLElement;
16
+ syncAttrsValue: Array<string>;
17
+ sumAttrValue: string;
18
+ connect(): void;
19
+ accumulate(): void;
20
+ setAttributesTo(sum: number): void;
21
+ get accumulator(): Element;
22
+ }
@@ -0,0 +1,39 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ class AccumulatorController extends Controller {
3
+ connect() {
4
+ this.accumulate();
5
+ }
6
+ accumulate() {
7
+ let sum = 0;
8
+ for (let i in this.sumTargets) {
9
+ const target = this.sumTargets[i];
10
+ const value = Number(target.getAttribute(this.sumAttrValue));
11
+ if (!isNaN(value)) {
12
+ sum += value;
13
+ }
14
+ }
15
+ this.setAttributesTo(sum);
16
+ }
17
+ setAttributesTo(sum) {
18
+ for (let i in this.syncAttrsValue) {
19
+ const attr = this.syncAttrsValue[i];
20
+ this.accumulator.setAttribute(attr, sum.toString());
21
+ }
22
+ }
23
+ get accumulator() {
24
+ var _a;
25
+ return (_a = this.accumulatorTarget) !== null && _a !== void 0 ? _a : this.element;
26
+ }
27
+ }
28
+ AccumulatorController.targets = ['sum', 'accumulator'];
29
+ AccumulatorController.values = {
30
+ syncAttrs: {
31
+ type: Array,
32
+ default: ['aria-valuenow'],
33
+ },
34
+ sumAttr: {
35
+ type: 'string',
36
+ default: 'data-value',
37
+ },
38
+ };
39
+ export default AccumulatorController;
@@ -0,0 +1,48 @@
1
+ import {Controller} from '@hotwired/stimulus'
2
+
3
+ export default class AccumulatorController extends Controller {
4
+ static targets = ['sum', 'accumulator']
5
+ static values = {
6
+ syncAttrs: {
7
+ type: Array,
8
+ default: ['aria-valuenow'],
9
+ },
10
+ sumAttr: {
11
+ type: 'string',
12
+ default: 'data-value',
13
+ },
14
+ }
15
+
16
+ declare sumTargets: Array<HTMLElement>
17
+ declare accumulatorTarget?: HTMLElement
18
+ declare syncAttrsValue: Array<string>
19
+ declare sumAttrValue: string
20
+
21
+ connect(): void {
22
+ this.accumulate()
23
+ }
24
+
25
+ accumulate() {
26
+ let sum = 0
27
+ for (let i in this.sumTargets) {
28
+ const target = this.sumTargets[i]
29
+ const value = Number(target.getAttribute(this.sumAttrValue))
30
+ if (!isNaN(value)) {
31
+ sum += value
32
+ }
33
+ }
34
+
35
+ this.setAttributesTo(sum)
36
+ }
37
+
38
+ setAttributesTo(sum: number) {
39
+ for (let i in this.syncAttrsValue) {
40
+ const attr = this.syncAttrsValue[i]
41
+ this.accumulator.setAttribute(attr, sum.toString())
42
+ }
43
+ }
44
+
45
+ get accumulator() {
46
+ return this.accumulatorTarget ?? this.element
47
+ }
48
+ }
@@ -0,0 +1,11 @@
1
+ <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |component| %>
2
+ <%= icon %>
3
+ <%= title %>
4
+ <% if actions? %>
5
+ <div class="<%= @actions_wrapper_classes %>">
6
+ <% actions.each do |action| %>
7
+ <%= action %>
8
+ <% end %>
9
+ </div>
10
+ <% end %>
11
+ <% end %>
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # Add a general description of component here
5
+ # Add additional usage considerations or best practices that may aid the user to use the component correctly.
6
+ # @accessibility Add any accessibility considerations
7
+ class ActionCardComponent < Ariadne::Component
8
+ DEFAULT_TAG = :div
9
+ TAG_OPTIONS = [DEFAULT_TAG].freeze
10
+
11
+ DEFAULT_CLASSES = {
12
+ wrapper: "ariadne-w-fit ariadne-flex ariadne-flex-col ariadne-items-center",
13
+ actions_wrapper: "ariadne-flex",
14
+ }
15
+
16
+ DEFAULT_ATTRIBUTES = {
17
+ wrapper: {},
18
+ }
19
+
20
+ renders_one :icon, Ariadne::HeroiconComponent
21
+
22
+ renders_one :title, Ariadne::HeadingComponent
23
+
24
+ renders_many :actions, Ariadne::ButtonComponent
25
+
26
+ # @example Default
27
+ #
28
+ # <%= render(Ariadne::ActionCardComponent.new) { "Example" } %>
29
+ #
30
+ # @param tag [Symbol, String] The rendered tag name.
31
+ # @param classes [String] <%= link_to_classes_docs %>
32
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
33
+ def initialize(
34
+ tag: DEFAULT_TAG,
35
+ classes: "",
36
+ attributes: {},
37
+ actions_wrapper_classes: ""
38
+ )
39
+ @tag = check_incoming_tag(DEFAULT_TAG, tag)
40
+ @classes = merge_class_names(DEFAULT_CLASSES[:wrapper], classes)
41
+ @attributes = DEFAULT_ATTRIBUTES[:wrapper].merge(attributes)
42
+ @actions_wrapper_classes = merge_class_names(DEFAULT_CLASSES[:actions_wrapper], actions_wrapper_classes)
43
+ end
44
+ end
45
+ end
@@ -1,5 +1,8 @@
1
1
  import { Application } from '@hotwired/stimulus';
2
2
  import AriadneForm from './ariadne-form';
3
+ import OptionsController from './options_controller/options_controller';
4
+ import AccumulatorController from './accumulator_controller/accumulator_controller';
5
+ import ToggleableController from './toggleable_controller/toggleable_controller';
3
6
  import ClipboardCopyComponent from './clipboard_copy_component/clipboard-copy-component';
4
7
  import RichTextAreaComponent from './rich_text_area_component/rich-text-area-component';
5
8
  import SlideoverComponent from './slideover_component/slideover-component';
@@ -14,3 +17,6 @@ application.register('rich-text-area-component', RichTextAreaComponent);
14
17
  application.register('slideover-component', SlideoverComponent);
15
18
  application.register('tab-nav-component', TabNavComponent);
16
19
  application.register('tooltip-component', TooltipComponent);
20
+ application.register('toggleable', ToggleableController);
21
+ application.register('accumulator', AccumulatorController);
22
+ application.register('options', OptionsController);
@@ -2,6 +2,9 @@ import {Application} from '@hotwired/stimulus'
2
2
 
3
3
  import AriadneForm from './ariadne-form'
4
4
 
5
+ import OptionsController from './options_controller/options_controller'
6
+ import AccumulatorController from './accumulator_controller/accumulator_controller'
7
+ import ToggleableController from './toggleable_controller/toggleable_controller'
5
8
  import ClipboardCopyComponent from './clipboard_copy_component/clipboard-copy-component'
6
9
  import RichTextAreaComponent from './rich_text_area_component/rich-text-area-component'
7
10
  import SlideoverComponent from './slideover_component/slideover-component'
@@ -19,3 +22,6 @@ application.register('rich-text-area-component', RichTextAreaComponent)
19
22
  application.register('slideover-component', SlideoverComponent)
20
23
  application.register('tab-nav-component', TabNavComponent)
21
24
  application.register('tooltip-component', TooltipComponent)
25
+ application.register('toggleable', ToggleableController)
26
+ application.register('accumulator', AccumulatorController)
27
+ application.register('options', OptionsController)
@@ -0,0 +1,4 @@
1
+ <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |component| %>
2
+ <%= icon %>
3
+ <%= content %>
4
+ <% end %>
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # Tab component to be used with bottom_tab_nav
5
+
6
+ # Accessibility considerations:
7
+ # aria-controls="tabpanelID": Use this if content is being conditionally controlled. Reference the ID of the content being controlled
8
+ class BottomTabComponent < Ariadne::Component
9
+ DEFAULT_TAG = :a
10
+ TAG_OPTIONS = [DEFAULT_TAG].freeze
11
+
12
+ DEFAULT_CLASSES = "ariadne-w-full ariadne-py-4 ariadne-flex ariadne-flex-col ariadne-justify-center ariadne-items-center ariadne-cursor-pointer [&>span]:ariadne-p-0 ariadne-border-y-2 ariadne-border-r-2 first:ariadne-border-l-2 ariadne-border-solid ariadne-border-black"
13
+ TAB_BACKGROUND_COLOR_CLASSES = "aria-selected:ariadne-bg-gray-200"
14
+
15
+ DEFAULT_ATTRIBUTES = {
16
+ "data-action": "click->options#select",
17
+ "data-options-target": "option",
18
+ role: "tab",
19
+ tabindex: "0",
20
+ }
21
+
22
+ renders_one :icon, Ariadne::HeroiconComponent
23
+
24
+ # @example Default
25
+ #
26
+ # <%= render(Ariadne::BottomTabComponent.new) { "Example" } %>
27
+ #
28
+ # @param tag [Symbol, String] The rendered tag name.
29
+ # @param classes [String] <%= link_to_classes_docs %>
30
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
31
+ def initialize(tag: DEFAULT_TAG, classes: "", active: false, attributes: {})
32
+ @tag = check_incoming_tag(DEFAULT_TAG, tag)
33
+ @classes = merge_class_names(
34
+ DEFAULT_CLASSES,
35
+ TAB_BACKGROUND_COLOR_CLASSES,
36
+ classes,
37
+ )
38
+
39
+ @attributes = DEFAULT_ATTRIBUTES
40
+ .merge({ "aria-selected": active })
41
+ .merge(attributes)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,5 @@
1
+ <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do %>
2
+ <% tabs.each do |tab| %>
3
+ <%= tab %>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # Navigation component for BottomTabs
5
+ class BottomTabNavComponent < Ariadne::Component
6
+ DEFAULT_TAG = :nav
7
+ DEFAULT_TAB_TAG = :a
8
+ TAG_OPTIONS = [DEFAULT_TAG].freeze
9
+
10
+ DEFAULT_CLASSES = "ariadne-flex"
11
+
12
+ DEFAULT_ATTRIBUTES = {
13
+ "data-controller": "options",
14
+ "data-options-synced-attrs-value": '["aria-selected"]',
15
+ role: "tablist",
16
+ }
17
+
18
+ renders_many :tabs, Ariadne::BottomTabComponent
19
+
20
+ # @example Default
21
+ #
22
+ # <%= render(Ariadne::BottomTabNavComponent.new) { "Example" } %>
23
+ #
24
+ # @param tag [Symbol, String] The rendered tag name.
25
+ # @param classes [String] <%= link_to_classes_docs %>
26
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
27
+ def initialize(tag: DEFAULT_TAG, classes: "", attributes: {})
28
+ @tag = check_incoming_tag(DEFAULT_TAG, tag)
29
+ @classes = merge_class_names(DEFAULT_CLASSES, classes)
30
+ @attributes = DEFAULT_ATTRIBUTES.merge(attributes)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |component| %>
2
+ <ol class="ariadne-flex ariadne-gap-2 ariadne-items-center">
3
+ <% @items.each_with_index do |item, index| %>
4
+ <% if index == @items.size - 1 %>
5
+ <li class="<%= @active_item_classes %>" aria-current="page"><%= item[:title] %></li>
6
+ <% else %>
7
+ <li class="<%= @item_classes %>"><a href="<%= item[:url] %>"><%= item[:title] %></a></li>
8
+ <%= render Ariadne::HeroiconComponent.new(tag: :svg, icon: "chevron-right", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, size: :xs) do |icon| %>
9
+ <% end %>
10
+ <% end %>
11
+ <% end %>
12
+ </ol>
13
+ <% end %>
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # Breadcrumb component showing current navigation. The last item is considered the active one
5
+ class BreadcrumbsComponent < Ariadne::Component
6
+ DEFAULT_TAG = :nav
7
+ TAG_OPTIONS = [DEFAULT_TAG].freeze
8
+
9
+ DEFAULT_CLASSES = { wrapper: "", item: "", active_item: "ariadne-underline" }
10
+
11
+ # @example Default
12
+ #
13
+ # <%= render(Ariadne::BreadcrumbsComponent.new) { "Example" } %>
14
+ #
15
+ # @param tag [Symbol, String] The rendered tag name.
16
+ # @param classes [String] <%= link_to_classes_docs %>
17
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
18
+ def initialize(tag: DEFAULT_TAG, classes: "", items: [], item_classes: "", active_item_classes: "", attributes: {})
19
+ @tag = check_incoming_tag(DEFAULT_TAG, tag)
20
+ @classes = merge_class_names(
21
+ DEFAULT_CLASSES[:wrapper],
22
+ classes,
23
+ )
24
+
25
+ @items = items
26
+ @item_classes = merge_class_names(DEFAULT_CLASSES[:item], item_classes)
27
+ @active_item_classes = merge_class_names(DEFAULT_CLASSES[:item], DEFAULT_CLASSES[:active_item], item_classes, active_item_classes)
28
+ @attributes = attributes
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @label_classes, attributes: @label_attributes) do |component| %>
2
+ <%= render Ariadne::BaseComponent.new(tag: :input, classes: @input_classes, attributes: @input_attributes) do |input| %>
3
+ <% end %>
4
+ <%= content %>
5
+ <% end %>
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # Just a checkbox with a label, state managed by toggleable controller
5
+ class CheckboxComponent < Ariadne::Component
6
+ DEFAULT_TAG = :label
7
+ TAG_OPTIONS = [DEFAULT_TAG].freeze
8
+
9
+ DEFAULT_CLASSES = {
10
+ input: "ariadne-mr-2",
11
+ label: "ariadne-flex ariadne-items-center ariadne-cursor-pointer ariadne-w-fit",
12
+ }
13
+
14
+ DEFAULT_ATTRIBUTES = {
15
+ input: {
16
+ type: "checkbox",
17
+ "data-controller": "toggleable",
18
+ "data-toggleable-synced-attrs-value": '["checked", "aria-checked"]',
19
+ "data-action": "click->toggleable#toggle",
20
+ },
21
+ label: {},
22
+ }
23
+
24
+ # @example Default
25
+ #
26
+ # <%= render(Ariadne::CheckboxComponent.new) { "Example" } %>
27
+ #
28
+ # @param tag [Symbol, String] The rendered tag name.
29
+ # @param classes [String] <%= link_to_classes_docs %>
30
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
31
+ def initialize(tag: DEFAULT_TAG, classes: "", input_classes: "", initial_value: false, input_attributes: {}, attributes: {})
32
+ @tag = @tag = check_incoming_tag(DEFAULT_TAG, tag)
33
+
34
+ @label_attributes = DEFAULT_ATTRIBUTES[:label].merge(attributes)
35
+ @label_classes = merge_class_names(DEFAULT_CLASSES[:label], classes)
36
+
37
+ @input_classes = merge_class_names(DEFAULT_CLASSES[:input], input_classes)
38
+ @input_attributes = DEFAULT_ATTRIBUTES[:input]
39
+ .merge({ "data-toggleable-state-value": initial_value.to_s })
40
+ .merge(input_attributes)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,4 @@
1
+ <%= render Ariadne::ButtonComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |component| %>
2
+ <%= render Ariadne::HeroiconComponent.new(icon: "x-mark", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, classes: @icon_classes, size: @size) do |icon| %>
3
+ <% end %>
4
+ <% end %>
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # Simple button with X icon to close models and such
5
+ class CloseButtonComponent < Ariadne::Component
6
+ DEFAULT_TAG = :button
7
+ TAG_OPTIONS = [DEFAULT_TAG].freeze
8
+
9
+ DEFAULT_CLASSES = "ariadne-border-none ariadne-bg-transparent ariadne-shadow-none hover:ariadne-bg-transparent"
10
+
11
+ # @example Default
12
+ #
13
+ # <%= render(Ariadne::CloseButtonComponent.new) { "Example" } %>
14
+ #
15
+ # @param tag [Symbol, String] The rendered tag name.
16
+ # @param classes [String] <%= link_to_classes_docs %>
17
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
18
+ def initialize(tag: DEFAULT_TAG, classes: "", icon_classes: "", size: :xs, aria_label: nil, attributes: {})
19
+ raise ArgumentError, "An 'aria_label' argument is required to use a Close Button. Include as much detail as you can about what the button will be closing." if aria_label.blank?
20
+
21
+ @tag = check_incoming_tag(DEFAULT_TAG, tag)
22
+ @attributes = { "aria-label": aria_label }.merge(attributes)
23
+ @classes = merge_class_names(
24
+ DEFAULT_CLASSES,
25
+ classes,
26
+ )
27
+
28
+ @size = size
29
+ @icon_classses = icon_classes
30
+ end
31
+ end
32
+ end
@@ -0,0 +1 @@
1
+ import '@github/details-menu-element';
@@ -0,0 +1 @@
1
+ import '@github/details-menu-element';
@@ -0,0 +1,21 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class OptionsController extends Controller {
3
+ #private;
4
+ static targets: string[];
5
+ static values: {
6
+ activeIndex: {
7
+ type: NumberConstructor;
8
+ default: number;
9
+ };
10
+ syncedAttrs: ArrayConstructor;
11
+ antiAttrs: ArrayConstructor;
12
+ };
13
+ readonly optionTargets: Array<Element>;
14
+ activeIndexValue: number;
15
+ readonly syncedAttrsValue: string[];
16
+ readonly hasSyncedAttrsValue: boolean;
17
+ readonly antiAttrsValue: string[];
18
+ readonly hasAntiAttrsValue: boolean;
19
+ connect(): void;
20
+ select(e: Event, newIndex?: number): void;
21
+ }
@@ -0,0 +1,50 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var _OptionsController_instances, _OptionsController_updateAllAttrsForElement, _OptionsController_syncAttrsForTarget;
7
+ import { Controller } from '@hotwired/stimulus';
8
+ class OptionsController extends Controller {
9
+ constructor() {
10
+ super(...arguments);
11
+ _OptionsController_instances.add(this);
12
+ }
13
+ connect() {
14
+ this.select(new Event('Init'), this.activeIndexValue);
15
+ }
16
+ select(e, newIndex) {
17
+ for (let index in this.optionTargets) {
18
+ const target = this.optionTargets[index];
19
+ const isActive = newIndex === undefined ? target === e.currentTarget : Number(index) === Number(newIndex);
20
+ if (isActive) {
21
+ this.activeIndexValue = Number(index);
22
+ }
23
+ __classPrivateFieldGet(this, _OptionsController_instances, "m", _OptionsController_updateAllAttrsForElement).call(this, target, isActive);
24
+ }
25
+ }
26
+ }
27
+ _OptionsController_instances = new WeakSet(), _OptionsController_updateAllAttrsForElement = function _OptionsController_updateAllAttrsForElement(element, value) {
28
+ if (this.hasSyncedAttrsValue) {
29
+ __classPrivateFieldGet(this, _OptionsController_instances, "m", _OptionsController_syncAttrsForTarget).call(this, element, this.syncedAttrsValue, value);
30
+ }
31
+ if (this.hasAntiAttrsValue) {
32
+ __classPrivateFieldGet(this, _OptionsController_instances, "m", _OptionsController_syncAttrsForTarget).call(this, element, this.antiAttrsValue, !value);
33
+ }
34
+ }, _OptionsController_syncAttrsForTarget = function _OptionsController_syncAttrsForTarget(element, attrs, value) {
35
+ const attrState = String(value);
36
+ for (let index in attrs) {
37
+ const attr = attrs[index];
38
+ element.setAttribute(attr, attrState);
39
+ }
40
+ };
41
+ OptionsController.targets = ['option'];
42
+ OptionsController.values = {
43
+ activeIndex: {
44
+ type: Number,
45
+ default: 0,
46
+ },
47
+ syncedAttrs: Array,
48
+ antiAttrs: Array,
49
+ };
50
+ export default OptionsController;
@@ -0,0 +1,57 @@
1
+ import {Controller} from '@hotwired/stimulus'
2
+
3
+ export default class OptionsController extends Controller {
4
+ static targets = ['option']
5
+
6
+ static values = {
7
+ activeIndex: {
8
+ type: Number,
9
+ default: 0,
10
+ },
11
+ syncedAttrs: Array,
12
+ antiAttrs: Array,
13
+ }
14
+
15
+ declare readonly optionTargets: Array<Element>
16
+ declare activeIndexValue: number
17
+
18
+ declare readonly syncedAttrsValue: string[]
19
+ declare readonly hasSyncedAttrsValue: boolean
20
+ declare readonly antiAttrsValue: string[]
21
+ declare readonly hasAntiAttrsValue: boolean
22
+
23
+ connect(): void {
24
+ this.select(new Event('Init'), this.activeIndexValue)
25
+ }
26
+
27
+ select(e: Event, newIndex?: number) {
28
+ for (let index in this.optionTargets) {
29
+ const target = this.optionTargets[index]
30
+ const isActive = newIndex === undefined ? target === e.currentTarget : Number(index) === Number(newIndex)
31
+
32
+ if (isActive) {
33
+ this.activeIndexValue = Number(index)
34
+ }
35
+
36
+ this.#updateAllAttrsForElement(target, isActive)
37
+ }
38
+ }
39
+
40
+ #updateAllAttrsForElement(element: Element, value: boolean) {
41
+ if (this.hasSyncedAttrsValue) {
42
+ this.#syncAttrsForTarget(element, this.syncedAttrsValue, value)
43
+ }
44
+
45
+ if (this.hasAntiAttrsValue) {
46
+ this.#syncAttrsForTarget(element, this.antiAttrsValue, !value)
47
+ }
48
+ }
49
+
50
+ #syncAttrsForTarget(element: Element, attrs: string[], value: boolean) {
51
+ const attrState = String(value)
52
+ for (let index in attrs) {
53
+ const attr = attrs[index]
54
+ element.setAttribute(attr, attrState)
55
+ }
56
+ }
57
+ }