shadcn-ui 0.0.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.
Files changed (169) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +10 -0
  3. data/.prettierignore +43 -0
  4. data/.prettierrc.json +28 -0
  5. data/.rspec +1 -0
  6. data/.ruby-version +1 -0
  7. data/.vscode/settings.json +11 -0
  8. data/CHANGELOG.md +6 -0
  9. data/CODE_OF_CONDUCT.md +113 -0
  10. data/LICENSE.md +18 -0
  11. data/Procfile.dev +2 -0
  12. data/README.md +90 -0
  13. data/Rakefile +12 -0
  14. data/app/assets/builds/.keep +0 -0
  15. data/app/assets/config/manifest.js +5 -0
  16. data/app/assets/images/.keep +0 -0
  17. data/app/assets/stylesheets/application.scss +42 -0
  18. data/app/assets/stylesheets/application.tailwind.css +92 -0
  19. data/app/assets/stylesheets/lambda.light.scss +136 -0
  20. data/app/channels/application_cable/channel.rb +4 -0
  21. data/app/channels/application_cable/connection.rb +4 -0
  22. data/app/controllers/application_controller.rb +8 -0
  23. data/app/controllers/components_controller.rb +7 -0
  24. data/app/controllers/concerns/.keep +0 -0
  25. data/app/helpers/application_helper.rb +2 -0
  26. data/app/helpers/components/accordion_helper.rb +5 -0
  27. data/app/helpers/components/alert_dialog_helper.rb +6 -0
  28. data/app/helpers/components/alert_helper.rb +11 -0
  29. data/app/helpers/components/badge_helper.rb +20 -0
  30. data/app/helpers/components/button_helper.rb +20 -0
  31. data/app/helpers/components/card_helper.rb +5 -0
  32. data/app/helpers/components/checkbox_helper.rb +5 -0
  33. data/app/helpers/components/collapsible_helper.rb +6 -0
  34. data/app/helpers/components/dialog_helper.rb +14 -0
  35. data/app/helpers/components/dropdown_menu_helper.rb +23 -0
  36. data/app/helpers/components/hover_card_helper.rb +15 -0
  37. data/app/helpers/components/popover_helper.rb +15 -0
  38. data/app/helpers/components/seperator_helper.rb +6 -0
  39. data/app/helpers/components/textarea_helper.rb +13 -0
  40. data/app/helpers/components/toast_helper.rb +5 -0
  41. data/app/helpers/components/toggle_helper.rb +6 -0
  42. data/app/helpers/components/tooltip_helper.rb +15 -0
  43. data/app/helpers/components_helper.rb +7 -0
  44. data/app/helpers/examples_helper.rb +41 -0
  45. data/app/javascript/application.js +3 -0
  46. data/app/javascript/controllers/application.js +9 -0
  47. data/app/javascript/controllers/hello_controller.js +7 -0
  48. data/app/javascript/controllers/highlight_controller.js +9 -0
  49. data/app/javascript/controllers/index.js +11 -0
  50. data/app/javascript/controllers/tabs_controller.js +72 -0
  51. data/app/javascript/controllers/ui/accordion_controller.js +128 -0
  52. data/app/javascript/controllers/ui/checkbox_controller.js +17 -0
  53. data/app/javascript/controllers/ui/collapsible_controller.js +28 -0
  54. data/app/javascript/controllers/ui/dialog_controller.js +92 -0
  55. data/app/javascript/controllers/ui/dropdown_controller.js +25 -0
  56. data/app/javascript/controllers/ui/hover-card_controller.js +39 -0
  57. data/app/javascript/controllers/ui/popover_controller.js +27 -0
  58. data/app/javascript/controllers/ui/toast_controller.js +43 -0
  59. data/app/javascript/controllers/ui/toggle_controller.js +15 -0
  60. data/app/javascript/controllers/ui/tooltip_controller.js +3 -0
  61. data/app/javascript/controllers/ui/transition_controller.js +8 -0
  62. data/app/jobs/application_job.rb +7 -0
  63. data/app/mailers/application_mailer.rb +4 -0
  64. data/app/models/application_record.rb +3 -0
  65. data/app/models/concerns/.keep +0 -0
  66. data/app/views/application/index.html.erb +0 -0
  67. data/app/views/components/ui/_accordion.html.erb +40 -0
  68. data/app/views/components/ui/_alert.html.erb +55 -0
  69. data/app/views/components/ui/_alert_dialog.html.erb +20 -0
  70. data/app/views/components/ui/_badge.html.erb +1 -0
  71. data/app/views/components/ui/_button.html.erb +11 -0
  72. data/app/views/components/ui/_card.html.erb +13 -0
  73. data/app/views/components/ui/_checkbox.html.erb +37 -0
  74. data/app/views/components/ui/_collapsible.html.erb +38 -0
  75. data/app/views/components/ui/_dialog.html.erb +69 -0
  76. data/app/views/components/ui/_dropdown_menu.html.erb +9 -0
  77. data/app/views/components/ui/_hover_card.html.erb +18 -0
  78. data/app/views/components/ui/_popover.html.erb +19 -0
  79. data/app/views/components/ui/_separator.html.erb +4 -0
  80. data/app/views/components/ui/_textarea.html.erb +9 -0
  81. data/app/views/components/ui/_toast.html.erb +34 -0
  82. data/app/views/components/ui/_toggle.html.erb +3 -0
  83. data/app/views/components/ui/_tooltip.html.erb +18 -0
  84. data/app/views/components/ui/shared/_dialog_background.html.erb +7 -0
  85. data/app/views/components/ui/shared/_menu_item.html.erb +6 -0
  86. data/app/views/examples/authentication/index.html.erb +148 -0
  87. data/app/views/examples/components/accordion.html.erb +17 -0
  88. data/app/views/examples/components/alert-dialog.html.erb +24 -0
  89. data/app/views/examples/components/alert.html.erb +22 -0
  90. data/app/views/examples/components/badge.html.erb +30 -0
  91. data/app/views/examples/components/button.html.erb +33 -0
  92. data/app/views/examples/components/card.html.erb +156 -0
  93. data/app/views/examples/components/checkbox.html.erb +8 -0
  94. data/app/views/examples/components/collapsible.html.erb +24 -0
  95. data/app/views/examples/components/dialog/_usage.html.erb +28 -0
  96. data/app/views/examples/components/dialog/code/form.erb +48 -0
  97. data/app/views/examples/components/dialog/code/notifications.erb +83 -0
  98. data/app/views/examples/components/dialog/code/preview.erb +14 -0
  99. data/app/views/examples/components/dialog/code/usage.erb +8 -0
  100. data/app/views/examples/components/dialog.html.erb +148 -0
  101. data/app/views/examples/components/dropdown-menu.html.erb +26 -0
  102. data/app/views/examples/components/hover-card.html.erb +24 -0
  103. data/app/views/examples/components/popover.html.erb +34 -0
  104. data/app/views/examples/components/separator.html.erb +33 -0
  105. data/app/views/examples/components/textarea.html.erb +12 -0
  106. data/app/views/examples/components/toast.html.erb +15 -0
  107. data/app/views/examples/components/toggle.html.erb +12 -0
  108. data/app/views/examples/components/tooltip.html.erb +23 -0
  109. data/app/views/layouts/_sidebar.html.erb +270 -0
  110. data/app/views/layouts/application.html.erb +33 -0
  111. data/app/views/layouts/component.html.erb +35 -0
  112. data/app/views/layouts/documentation/_breadcrumb.html.erb +17 -0
  113. data/app/views/layouts/documentation/_component_header.html.erb +11 -0
  114. data/app/views/layouts/documentation/_examples.html.erb +80 -0
  115. data/app/views/layouts/documentation/_preview.html.erb +90 -0
  116. data/app/views/layouts/mailer.html.erb +13 -0
  117. data/app/views/layouts/mailer.text.erb +1 -0
  118. data/app/views/layouts/shared/_header.html.erb +164 -0
  119. data/config/application.rb +37 -0
  120. data/config/boot.rb +4 -0
  121. data/config/cable.yml +11 -0
  122. data/config/credentials.yml.enc +1 -0
  123. data/config/database.yml +25 -0
  124. data/config/environment.rb +5 -0
  125. data/config/environments/development.rb +70 -0
  126. data/config/environments/production.rb +93 -0
  127. data/config/environments/test.rb +60 -0
  128. data/config/importmap.rb +13 -0
  129. data/config/initializers/assets.rb +12 -0
  130. data/config/initializers/content_security_policy.rb +25 -0
  131. data/config/initializers/filter_parameter_logging.rb +8 -0
  132. data/config/initializers/inflections.rb +16 -0
  133. data/config/initializers/permissions_policy.rb +11 -0
  134. data/config/locales/en.yml +33 -0
  135. data/config/puma.rb +43 -0
  136. data/config/render.yml +9 -0
  137. data/config/routes.rb +7 -0
  138. data/config/storage.yml +34 -0
  139. data/config/tailwind.config.js +86 -0
  140. data/config.ru +6 -0
  141. data/db/seeds.rb +7 -0
  142. data/lib/assets/.keep +0 -0
  143. data/lib/generators/shadcn_ui_generator.rb +32 -0
  144. data/lib/shadcn-ui/shadcn-ui.rb +8 -0
  145. data/lib/shadcn-ui/version.rb +3 -0
  146. data/lib/tasks/.keep +0 -0
  147. data/log/.keep +0 -0
  148. data/package-lock.json +1014 -0
  149. data/package.json +8 -0
  150. data/public/404.html +67 -0
  151. data/public/422.html +67 -0
  152. data/public/500.html +66 -0
  153. data/public/android-chrome-192x192.png +0 -0
  154. data/public/android-chrome-512x512.png +0 -0
  155. data/public/apple-touch-icon-precomposed.png +0 -0
  156. data/public/apple-touch-icon.png +0 -0
  157. data/public/favicon-16x16.png +0 -0
  158. data/public/favicon-32x32.png +0 -0
  159. data/public/favicon.ico +0 -0
  160. data/public/og.jpg +0 -0
  161. data/public/robots.txt +1 -0
  162. data/sig/shadcn-ui.rbs +4 -0
  163. data/storage/.keep +0 -0
  164. data/tmp/.keep +0 -0
  165. data/tmp/pids/.keep +0 -0
  166. data/tmp/storage/.keep +0 -0
  167. data/vendor/.keep +0 -0
  168. data/vendor/javascript/.keep +0 -0
  169. metadata +214 -0
@@ -0,0 +1,6 @@
1
+ module Components::AlertDialogHelper
2
+ def render_alert_dialog(trigger:, label:, description:, continue:, **options)
3
+ cancel = options[:cancel] || render_button("Cancel", class: "mt-2 sm:mt-0", data: {action: "ui--dialog#close"})
4
+ render "components/ui/alert_dialog", trigger:, label:, description:, continue:, cancel:, **options
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ module Components::AlertHelper
2
+ def render_alert(title:, description:, variant: :default)
3
+ alert_classes = case variant.to_sym
4
+ when :default
5
+ "[&>svg]:text-foreground bg-background text-foreground"
6
+ when :error, :danger, :alert, :destructive
7
+ "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive"
8
+ end
9
+ render "components/ui/alert", title: title, description: description, alert_classes: alert_classes, variant: variant
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ module Components::BadgeHelper
2
+ def render_badge(label = "", data: "", text: "", variant: :default, **options)
3
+ badge_classes = " inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 "
4
+ varianet_classes = case variant.to_sym
5
+ when :default
6
+ ComponentsHelper::PRIMARY_CLASSES
7
+ when :secondary
8
+ ComponentsHelper::SECONDARY_CLASSES
9
+ when :error, :danger, :alert, :destructive
10
+ ComponentsHelper::DESTRUCTIVE_CLASSES
11
+ when :outline
12
+ ComponentsHelper::OUTLINE_CLASSES
13
+ when :ghost
14
+ ComponentsHelper::GHOST_CLASSES
15
+ end
16
+ badge_classes << " #{varianet_classes}"
17
+ text = label if label.present?
18
+ render "components/ui/badge", text:, badge_classes:, data:, **options
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Components::ButtonHelper
2
+ def render_button(label = "", data: "", text: "", variant: :default, as: :button, href: nil, **options)
3
+ button_classes = " inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 h-10 px-4 py-2 "
4
+ varianet_classes = case variant.to_sym
5
+ when :default
6
+ " bg-primary text-primary-foreground hover:bg-primary/90 "
7
+ when :secondary
8
+ " bg-secondary text-secondary-foreground hover:bg-secondary/80 "
9
+ when :error, :danger, :alert, :destructive
10
+ " bg-destructive text-destructive-foreground hover:bg-destructive/90 "
11
+ when :outline
12
+ " border border-input bg-background hover:bg-accent hover:text-accent-foreground"
13
+ when :ghost
14
+ " hover:bg-accent hover:text-accent-foreground "
15
+ end
16
+ button_classes << " #{varianet_classes} #{options[:class]}"
17
+ text = label if label.present?
18
+ render "components/ui/button", text:, button_classes:, as:, href:, data:, **options
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ module Components::CardHelper
2
+ def render_card(footer: nil, title: nil, subtitle: nil, body: nil, **options, &block)
3
+ render "components/ui/card", title: title, subtitle: subtitle, footer: footer, body: (block ? capture(&block) : body), block:, **options
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Components::CheckboxHelper
2
+ def render_checkbox(label:, name:)
3
+ render "components/ui/checkbox", name: name, label: label
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ module Components::CollapsibleHelper
2
+ def render_collapsible(**options, &block)
3
+ content = capture(&block) if block
4
+ render "components/ui/collapsible", content: content, **options
5
+ end
6
+ end
@@ -0,0 +1,14 @@
1
+ module Components::DialogHelper
2
+ def render_dialog(**options, &block)
3
+ content = capture(&block) if block
4
+ render "components/ui/dialog", content: content, **options
5
+ end
6
+
7
+ def dialog_trigger(&block)
8
+ content_for :dialog_trigger, capture(&block), flush: true
9
+ end
10
+
11
+ def dialog_content(&block)
12
+ content_for :dialog_content, capture(&block), flush: true
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ module Components::DropdownMenuHelper
2
+ def render_dropdown_menu(**options, &block)
3
+ content = capture(&block) if block
4
+ render "components/ui/dropdown_menu", content: content, **options
5
+ end
6
+
7
+ def dropdown_menu_trigger(&block)
8
+ content_for :dropdown_menu_trigger, capture(&block), flush: true
9
+ end
10
+
11
+ def dropdown_menu_label(label = nil, &block)
12
+ content_for :dropdown_menu_label, (label || capture(&block)), flush: true
13
+ end
14
+
15
+ def dropdown_menu_content(&block)
16
+ content_for :dropdown_menu_content, capture(&block), flush: true
17
+ end
18
+
19
+ def dropdown_menu_item(label = nil, **options, &block)
20
+ content = (label || capture(&block))
21
+ render "components/ui/shared/menu_item", content: content
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module Components::HoverCardHelper
2
+ def render_hover_card(**options, &block)
3
+ content = capture(&block) if block
4
+ render "components/ui/hover_card", content: content, **options
5
+ end
6
+
7
+ def hover_card_trigger(&block)
8
+ content_for :hover_card_trigger, capture(&block), flush: true
9
+ end
10
+
11
+ def hover_card_content(options = {}, &block)
12
+ content_for :hover_card_content_class, options[:class], flush: true
13
+ content_for :hover_card_content, capture(&block), flush: true
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Components::PopoverHelper
2
+ def render_popover(**options, &block)
3
+ content = capture(&block) if block
4
+ render "components/ui/popover", content: content, **options
5
+ end
6
+
7
+ def popover_trigger(&block)
8
+ content_for :popover_trigger, capture(&block), flush: true
9
+ end
10
+
11
+ def popover_content(options = {}, &block)
12
+ content_for :popover_content_class, options[:class], flush: true
13
+ content_for :popover_content, capture(&block), flush: true
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ module Components::SeperatorHelper
2
+ def render_separator(options = {})
3
+ options = {class: "shrink-0 bg-border h-[1px] w-full #{options[:class]}"}.reverse_merge(options)
4
+ content_tag :div, "", options
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ module Components::TextareaHelper
2
+ def render_textarea(name:, label: false, id: nil, value: nil, **options)
3
+ options.reverse_merge!(rows: 3, required: false, disabled: false,
4
+ readonly: false, class: "", label: false, placeholder: "Type here...")
5
+ render partial: "components/ui/textarea", locals: {
6
+ label:,
7
+ name:,
8
+ value:,
9
+ id:,
10
+ options: options
11
+ }
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module Components::ToastHelper
2
+ def render_toast(header: nil, description: nil, action: nil, class: nil, data: nil, **options, &block)
3
+ render "components/ui/toast", header:, description:, action:, class:, data:, options: options
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ module Components::ToggleHelper
2
+ def render_toggle(label = nil, **options, &block)
3
+ content = label || capture(&block)
4
+ render "components/ui/toggle", content: content, **options
5
+ end
6
+ end
@@ -0,0 +1,15 @@
1
+ module Components::TooltipHelper
2
+ def render_tooltip(**options, &block)
3
+ content = capture(&block) if block
4
+ render "components/ui/tooltip", content: content, **options
5
+ end
6
+
7
+ def tooltip_trigger(&block)
8
+ content_for :tooltip_trigger, capture(&block), flush: true
9
+ end
10
+
11
+ def tooltip_content(options = {}, &block)
12
+ content_for :tooltip_content_class, options[:class], flush: true
13
+ content_for :tooltip_content, capture(&block), flush: true
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module ComponentsHelper
2
+ PRIMARY_CLASSES = " bg-primary text-primary-foreground hover:bg-primary/80 "
3
+ SECONDARY_CLASSES = " bg-secondary text-secondary-foreground hover:bg-secondary/80 "
4
+ OUTLINE_CLASSES = " border border-input bg-background hover:bg-accent hover:text-accent-foreground "
5
+ GHOST_CLASSES = " hover:bg-accent hover:text-accent-foreground "
6
+ DESTRUCTIVE_CLASSES = " bg-destructive text-destructive-foreground hover:bg-destructive/90 "
7
+ end
@@ -0,0 +1,41 @@
1
+ module ExamplesHelper
2
+ def render_component_header(title:, description:)
3
+ render "layouts/documentation/component_header", title:, description:
4
+ end
5
+
6
+ def render_example
7
+ render "layouts/documentation/examples"
8
+ end
9
+
10
+ def render_preview
11
+ render "layouts/documentation/preview"
12
+ end
13
+
14
+ def render_usage(name)
15
+ render "examples/components/#{name}/usage"
16
+ end
17
+
18
+ def code_partial(name, language)
19
+ content_tag :pre, class: "code-sample py-4 px-4", data: {controller: "highlight"} do
20
+ content_tag :code, class: "language-#{language}" do
21
+ html_escape(File.read(Rails.root.join("app", "views", "examples", "components", "#{name}.erb")))
22
+ end
23
+ end
24
+ end
25
+
26
+ def code_sample(content = "", language:, &block)
27
+ content_tag :pre, class: "code-sample px-4 my-2 pb-5", data: {controller: "highlight"} do
28
+ content_tag :code, class: "language-#{language}" do
29
+ content
30
+ yield if block
31
+ end
32
+ end
33
+ end
34
+
35
+ def inline_code(content = nil, &block)
36
+ content_tag :code, class: "relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono font-semibold" do
37
+ content || yield(block)
38
+ end
39
+ end
40
+ alias_method :code, :inline_code
41
+ end
@@ -0,0 +1,3 @@
1
+ // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
2
+ import "@hotwired/turbo-rails"
3
+ import "controllers"
@@ -0,0 +1,9 @@
1
+ import { Application } from "@hotwired/stimulus";
2
+
3
+ const application = Application.start();
4
+
5
+ // Configure Stimulus development experience
6
+ application.debug = false;
7
+ window.Stimulus = application;
8
+
9
+ export { application };
@@ -0,0 +1,7 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ this.element.textContent = "Hello World!"
6
+ }
7
+ }
@@ -0,0 +1,9 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+ import hljs from "highlight.js";
3
+
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log("hi");
7
+ hljs.highlightAll();
8
+ }
9
+ }
@@ -0,0 +1,11 @@
1
+ // Import and register all your controllers from the importmap under controllers/*
2
+
3
+ import { application } from "controllers/application"
4
+
5
+ // Eager load all controllers defined in the import map under controllers/**/*_controller
6
+ import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
7
+ eagerLoadControllersFrom("controllers", application)
8
+
9
+ // Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
10
+ // import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
11
+ // lazyLoadControllersFrom("controllers", application)
@@ -0,0 +1,72 @@
1
+ // https://github.com/excid3/tailwindcss-stimulus-components/blob/master/src/tabs.js
2
+ import { Controller } from "@hotwired/stimulus";
3
+ import "@kanety/stimulus-static-actions";
4
+
5
+ export default class extends Controller {
6
+ static targets = ["tab", "panel"];
7
+ static actions = [["tab", "click->change"]];
8
+
9
+ connect() {
10
+ this.activeTabClasses = (this.data.get("activeTab") || "active").split(" ");
11
+ this.inactiveTabClasses = (this.data.get("inactiveTab") || "inactive").split(" ");
12
+ if (this.anchor) this.index = this.tabTargets.findIndex((tab) => tab.id === this.anchor);
13
+ this.showTab();
14
+ }
15
+
16
+ change(event) {
17
+ // If target specifies an index, use that
18
+ if (event.currentTarget.dataset.index) {
19
+ this.index = event.currentTarget.dataset.index;
20
+
21
+ // If target specifies an id, use that
22
+ } else if (event.currentTarget.dataset.id) {
23
+ this.index = this.tabTargets.findIndex((tab) => tab.id == event.currentTarget.dataset.id);
24
+
25
+ // Otherwise, use the index of the current target
26
+ } else {
27
+ this.index = this.tabTargets.indexOf(event.currentTarget);
28
+ }
29
+
30
+ window.dispatchEvent(new CustomEvent("tsc:tab-change"));
31
+ }
32
+
33
+ showTab() {
34
+ this.tabTargets.forEach((tab, index) => {
35
+ const panel = this.panelTargets[index];
36
+
37
+ if (index === this.index) {
38
+ panel.classList.remove("hidden");
39
+ tab.classList.remove(...this.inactiveTabClasses);
40
+ tab.classList.add(...this.activeTabClasses);
41
+ tab.dataset.state = "active";
42
+ panel.dataset.state = "active";
43
+
44
+ // Update URL with the tab ID if it has one
45
+ // This will be automatically selected on page load
46
+ // - Breaks any other anchors
47
+ // if (tab.id) {
48
+ // location.hash = tab.id;
49
+ // }
50
+ } else {
51
+ panel.classList.add("hidden");
52
+ tab.classList.remove(...this.activeTabClasses);
53
+ tab.classList.add(...this.inactiveTabClasses);
54
+ tab.dataset.state = "inactive";
55
+ panel.dataset.state = "inactive";
56
+ }
57
+ });
58
+ }
59
+
60
+ get index() {
61
+ return parseInt(this.data.get("index") || 0);
62
+ }
63
+
64
+ set index(value) {
65
+ this.data.set("index", value >= 0 ? value : 0);
66
+ this.showTab();
67
+ }
68
+
69
+ get anchor() {
70
+ return document.URL.split("#").length > 1 ? document.URL.split("#")[1] : null;
71
+ }
72
+ }
@@ -0,0 +1,128 @@
1
+ // Inspired by https://github.com/kanety/stimulus-accordion
2
+ import { Controller } from "@hotwired/stimulus";
3
+
4
+ export default class extends Controller {
5
+ get togglers() {
6
+ return this.context.bindingObserver.bindings
7
+ .filter((binding) => binding.action.methodName == "toggle")
8
+ .map((binding) => binding.action.element);
9
+ }
10
+
11
+ get openedTogglers() {
12
+ return this.togglers.filter((toggler) => this.isOpened(toggler));
13
+ }
14
+
15
+ get contents() {
16
+ return this.scope.findAllElements("[data-accordion-id]");
17
+ }
18
+
19
+ connect() {
20
+ this.init();
21
+ }
22
+
23
+ init() {
24
+ this.togglers.forEach((toggler) => {
25
+ let content = this.findContent(toggler);
26
+ if (this.isOpened(toggler)) {
27
+ this.show(toggler, content, false);
28
+ } else {
29
+ this.hide(toggler, content, false);
30
+ }
31
+ });
32
+ }
33
+
34
+ toggle(e) {
35
+ this.togglers.forEach((toggler) => {
36
+ if (toggler.contains(e.target)) {
37
+ if (this.isOpened(toggler)) {
38
+ this.close(toggler);
39
+ } else {
40
+ this.open(toggler);
41
+ }
42
+ } else if (this.isOpened(toggler)) {
43
+ this.close(toggler);
44
+ }
45
+ });
46
+
47
+ e.preventDefault();
48
+ }
49
+
50
+ open(toggler) {
51
+ let content = this.findContent(toggler);
52
+ this.show(toggler, content);
53
+ this.dispatch("opened", { detail: { toggler: toggler, content: content } });
54
+ }
55
+
56
+ close(toggler) {
57
+ let content = this.findContent(toggler);
58
+ this.hide(toggler, content);
59
+ this.dispatch("closed", { detail: { toggler: toggler, content: content } });
60
+ }
61
+
62
+ show(toggler, content, transition = true) {
63
+ if (transition) {
64
+ content.style.height = "0px";
65
+ content.removeEventListener("transitionend", this.transitionEnd);
66
+ content.addEventListener("transitionend", this.transitionEnd);
67
+ setTimeout(() => {
68
+ content.style.height = content.scrollHeight + "px";
69
+ });
70
+ }
71
+
72
+ this.toggleClass(toggler, content, true);
73
+ this.toggleText(toggler, true);
74
+ }
75
+
76
+ hide(toggler, content, transition = true) {
77
+ if (transition) {
78
+ content.style.height = content.scrollHeight + "px";
79
+ content.removeEventListener("transitionend", this.transitionEnd);
80
+ content.addEventListener("transitionend", this.transitionEnd);
81
+ setTimeout(() => {
82
+ content.style.height = "0px";
83
+ });
84
+ }
85
+
86
+ this.toggleClass(toggler, content, false);
87
+ this.toggleText(toggler, false);
88
+ }
89
+
90
+ transitionEnd(e) {
91
+ e.target.style.height = "";
92
+ }
93
+
94
+ toggleClass(toggler, content, opened) {
95
+ if (opened) {
96
+ toggler.classList.add("st-accordion__icon--opened");
97
+ content.classList.add("st-accordion__content--visible");
98
+ toggler.dataset.state = "open";
99
+ } else {
100
+ toggler.classList.remove("st-accordion__icon--opened");
101
+ content.classList.remove("st-accordion__content--visible");
102
+ toggler.dataset.state = "closed";
103
+ }
104
+ }
105
+
106
+ toggleText(toggler, opened) {
107
+ let text;
108
+ if (opened) {
109
+ text = toggler.getAttribute("data-accordion-opened-text-param");
110
+ } else {
111
+ text = toggler.getAttribute("data-accordion-closed-text-param");
112
+ }
113
+ if (text) toggler.innerHTML = text;
114
+ }
115
+
116
+ isOpened(toggler) {
117
+ return toggler.matches(".st-accordion__icon--opened");
118
+ }
119
+
120
+ findContent(toggler) {
121
+ let id = this.getID(toggler);
122
+ return this.scope.findElement(`[data-accordion-id="${id}"]`);
123
+ }
124
+
125
+ getID(toggler) {
126
+ return toggler.getAttribute("href").replace(/^#/, "");
127
+ }
128
+ }
@@ -0,0 +1,17 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+ export default class extends Controller {
3
+ connect() {
4
+ this.button = this.element.querySelector("button");
5
+ this.checkmark = this.button.querySelector("span");
6
+ }
7
+
8
+ toggle() {
9
+ if (this.checkmark.classList.contains("hidden")) {
10
+ this.checkmark.classList.remove("hidden");
11
+ this.button.dataset.state = "checked";
12
+ } else {
13
+ this.checkmark.classList.add("hidden");
14
+ this.button.dataset.state = "unchecked";
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,28 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ static targets = ["item"];
5
+ static classes = ["hidden"];
6
+
7
+ connect() {
8
+ this.class = this.hasHiddenClass ? this.hiddenClass : "hidden";
9
+ }
10
+
11
+ toggle() {
12
+ this.itemTargets.forEach((item) => {
13
+ item.classList.toggle(this.class);
14
+ });
15
+ }
16
+
17
+ show() {
18
+ this.itemTargets.forEach((item) => {
19
+ item.classList.remove(this.class);
20
+ });
21
+ }
22
+
23
+ hide() {
24
+ this.itemTargets.forEach((item) => {
25
+ item.classList.add(this.class);
26
+ });
27
+ }
28
+ }
@@ -0,0 +1,92 @@
1
+ // Inspired by https://github.com/kanety/stimulus-dialog
2
+ import { Controller } from "@hotwired/stimulus";
3
+ import "@kanety/stimulus-static-actions";
4
+
5
+ export default class extends Controller {
6
+ static targets = ["dialog", "modal", "focus", "drag", "backdrop", "closeButton"];
7
+ static actions = [
8
+ ["element", "keydown@window->closeByKey"],
9
+ ["modal", "click->closeByModal"],
10
+ ["closeButton", "click->close"],
11
+ ];
12
+
13
+ initialize() {}
14
+ connect() {}
15
+ open(e) {
16
+ this.openBy(e.target);
17
+ e.preventDefault();
18
+ }
19
+
20
+ close(e) {
21
+ this.closeBy(e.target);
22
+ e.preventDefault();
23
+ }
24
+
25
+ toggle(e) {
26
+ if (this.isVisible()) {
27
+ this.closeBy(e.target);
28
+ } else {
29
+ this.openBy(e.target);
30
+ }
31
+ e.preventDefault();
32
+ }
33
+
34
+ closeByKey(e) {
35
+ if (e.keyCode == 27) {
36
+ this.closeBy(e.target);
37
+ e.preventDefault();
38
+ }
39
+ }
40
+
41
+ closeByModal(e) {
42
+ if (!this.dialogTarget.contains(e.target)) {
43
+ this.closeBy(e.target);
44
+ }
45
+ }
46
+
47
+ isVisible() {
48
+ return this.dialogTarget.classList.contains("st-dialog--visible");
49
+ }
50
+
51
+ openBy(target) {
52
+ this.toggleClass(true);
53
+
54
+ if (this.hasFocusTarget) {
55
+ this.focusTarget.focus();
56
+ }
57
+
58
+ this.dispatch("opened", { detail: { target: target } });
59
+ }
60
+
61
+ closeBy(target) {
62
+ this.toggleClass(false);
63
+
64
+ this.dispatch("closed", { detail: { target: target } });
65
+ }
66
+
67
+ toggleClass(visible) {
68
+ if (visible) {
69
+ this.dialogTarget.classList.remove("hidden");
70
+ this.dialogTarget.dataset.state = "open";
71
+ if (this.hasBackdropTarget) {
72
+ this.backdropTarget.classList.remove("hidden");
73
+ this.backdropTarget.dataset.state = "open";
74
+ }
75
+ if (this.hasModalTarget) {
76
+ this.modalTarget.classList.remove("hidden");
77
+ this.modalTarget.dataset.state = "open";
78
+ }
79
+ } else {
80
+ this.dialogTarget.classList.add("hidden");
81
+ this.dialogTarget.dataset.state = "closed";
82
+ if (this.hasBackdropTarget) {
83
+ this.backdropTarget.classList.add("hidden");
84
+ this.backdropTarget.dataset.state = "closed";
85
+ }
86
+ if (this.hasModalTarget) {
87
+ this.modalTarget.classList.add("hidden");
88
+ this.modalTarget.dataset.state = "closed";
89
+ }
90
+ }
91
+ }
92
+ }