loco_motion-rails 0.0.6 → 0.0.8

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +139 -67
  3. data/app/components/daisy/actions/button_component.rb +112 -8
  4. data/app/components/daisy/actions/dropdown_component.html.haml +5 -5
  5. data/app/components/daisy/actions/dropdown_component.rb +95 -26
  6. data/app/components/daisy/actions/modal_component.html.haml +3 -2
  7. data/app/components/daisy/actions/modal_component.rb +111 -20
  8. data/app/components/daisy/actions/swap_component.rb +117 -6
  9. data/app/components/daisy/actions/theme_controller_component.html.haml +1 -1
  10. data/app/components/daisy/actions/theme_controller_component.rb +37 -2
  11. data/app/components/daisy/data_display/accordion_component.rb +81 -4
  12. data/app/components/daisy/data_display/avatar_component.rb +39 -17
  13. data/app/components/daisy/data_display/badge_component.rb +49 -5
  14. data/app/components/daisy/data_display/card_component.html.haml +5 -13
  15. data/app/components/daisy/data_display/card_component.rb +76 -40
  16. data/app/components/daisy/data_display/carousel_component.rb +39 -1
  17. data/app/components/daisy/data_display/chat_component.rb +42 -15
  18. data/app/components/daisy/data_display/collapse_component.rb +61 -2
  19. data/app/components/daisy/data_display/countdown_component.rb +51 -1
  20. data/app/components/daisy/data_display/diff_component.rb +38 -1
  21. data/app/components/daisy/data_display/figure_component.rb +49 -0
  22. data/app/components/daisy/data_display/kbd_component.rb +64 -3
  23. data/app/components/daisy/data_display/stat_component.rb +67 -7
  24. data/app/components/daisy/data_display/table_component.rb +100 -35
  25. data/app/components/daisy/data_display/timeline_component.rb +46 -1
  26. data/app/components/daisy/data_display/timeline_event_component.rb +40 -2
  27. data/app/components/daisy/feedback/alert_component.rb +47 -2
  28. data/app/components/daisy/feedback/loading_component.rb +50 -0
  29. data/app/components/daisy/feedback/progress_component.rb +58 -0
  30. data/app/components/daisy/feedback/radial_progress_component.rb +72 -0
  31. data/app/components/daisy/feedback/skeleton_component.rb +53 -0
  32. data/app/components/daisy/feedback/toast_component.rb +45 -0
  33. data/app/components/daisy/feedback/tooltip_component.rb +77 -0
  34. data/app/components/daisy/layout/artboard_component.rb +59 -0
  35. data/app/components/daisy/layout/divider_component.rb +72 -0
  36. data/app/components/daisy/layout/drawer_component.html.haml +9 -0
  37. data/app/components/daisy/layout/drawer_component.rb +155 -0
  38. data/app/components/daisy/layout/footer_component.rb +69 -0
  39. data/app/components/daisy/layout/hero_component.html.haml +5 -0
  40. data/app/components/daisy/layout/hero_component.rb +83 -0
  41. data/app/components/daisy/layout/indicator_component.rb +83 -0
  42. data/app/components/daisy/layout/join_component.rb +72 -1
  43. data/app/components/daisy/layout/stack_component.rb +68 -0
  44. data/app/components/daisy/mockup/browser_component.rb +78 -0
  45. data/app/components/daisy/mockup/code_component.rb +144 -0
  46. data/app/components/daisy/mockup/device_component.rb +81 -0
  47. data/app/components/daisy/mockup/frame_component.rb +62 -0
  48. data/app/components/daisy/navigation/bottom_nav_component.rb +83 -4
  49. data/app/components/daisy/navigation/breadcrumbs_component.rb +41 -4
  50. data/app/components/daisy/navigation/link_component.rb +66 -13
  51. data/app/components/daisy/navigation/menu_component.rb +83 -11
  52. data/app/components/daisy/navigation/navbar_component.html.haml +1 -1
  53. data/app/components/daisy/navigation/navbar_component.rb +64 -3
  54. data/app/components/daisy/navigation/steps_component.rb +78 -2
  55. data/app/components/daisy/navigation/tabs_component.rb +112 -9
  56. data/app/components/hero/icon_component.rb +50 -1
  57. data/lib/daisy.rb +18 -3
  58. data/lib/hero.rb +7 -0
  59. data/lib/loco_motion/basic_component.rb +1 -1
  60. data/lib/loco_motion/concerns/tippable_component.rb +26 -0
  61. data/lib/loco_motion/configuration.rb +35 -0
  62. data/lib/loco_motion/helpers.rb +96 -0
  63. data/lib/loco_motion/version.rb +5 -0
  64. data/lib/loco_motion.rb +6 -36
  65. metadata +58 -9
  66. data/app/components/daisy/data_display/badge_component.html.haml +0 -2
  67. data/app/components/daisy/data_display/kbd_component.html.haml +0 -2
  68. data/app/components/daisy/navigation/link_component.html.haml +0 -4
  69. data/lib/daisy/helpers.rb +0 -61
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6cfe2882401b7bdfd08a844df9df854c145e89889bacc1e283102e4aad59d6d3
4
- data.tar.gz: df1222834a5606b7ffa9135bf90fb4d59e1fc699eea8d2bf52686e7f039d0c3f
3
+ metadata.gz: 7d4d1891389f5b0a860f930a6d4e6dbb9053b6a77e349cd0f43b9de22740482b
4
+ data.tar.gz: 2f99a232731636bfaeca166092c0fb4ca51ddae6300e420951d0c0791997e1d7
5
5
  SHA512:
6
- metadata.gz: 3f1ef92f5d9315db44ac50cb7c1be90f0924391c29b247d36930ae1758572dee93edafc0ba9f28ed496a8d29cb583c438ec77b50a08d73807cd79ca77d67aa38
7
- data.tar.gz: 6ba44670ccdd89349da146dc31e15dbeff3e5753f6bf55fc3531b8bbcb4505d72dcbdb895b3abed018cf84ce8c4d44ce173d922d7ab4ea559ca9878863ec23b3
6
+ metadata.gz: ad963fe072e997ad83879704d8a5d9285f2e964371ee9c7418dfe7377db7950b09f43e3ff8555fad25aee3d141b7b6927ba5e70f965684d749057aaa1d6223c8
7
+ data.tar.gz: 367ecb0bf6b3b9d3ff77e6f596b12322fe1b1026bcecc619032c70e59ed94d344f3b18907e8dc8caf63b4d95343e351a808254b50da0db14c8a98b8282cb5a18
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  Crazy fast Rails development with modern tools and components leveraging
5
5
  ViewComponent, TailwindCSS, DaisyUI and more!
6
6
 
7
- ![image](./docs/assets/images/loco-chats.png)
7
+ <img src="//loco-motion-docs.profoundry.us/images/loco-chats.png" width="500px" style="border: 1px solid #bbb; padding: 2px; border-radius: 10px;">
8
8
 
9
9
  _**DISCLAIMER**_
10
10
 
@@ -13,10 +13,12 @@ In particular, new Daisy components are being added frequently and older
13
13
  components are being updated with new features meaning the APIs are very likely
14
14
  to change!
15
15
 
16
- We plan to publish the docs site to a publicly available URL soon, but until
17
- then, you can run the docs by cloning the repository and running `make all` (or
18
- `make all-quick` if you've already run `make all` or `make rebuild` previously)
19
- and visiting http://localhost:3000/ in your browser.
16
+ We expect to settle on and purchase a real domain name in the near future, but
17
+ for the time being, the latest documentation is available at the links below.
18
+
19
+ - [Docs / Demo (Latest Release)][1]
20
+ - [API Docs (Latest Release)][2]
21
+ - [Docs / Demo (Main Branch / Staging)][3]
20
22
 
21
23
  Please reach out by opening an
22
24
  [Issue](https://github.com/profoundry-us/loco_motion/issues) if you've found a
@@ -31,18 +33,19 @@ your solution is aligned with our goals.
31
33
  - [About](#about)
32
34
  - [Getting Started](#getting-started)
33
35
  - [Installing / Setting up Rails](#installing--setting-up-rails)
36
+ - [Using UUIDs by Default](#using-uuids-by-default)
34
37
  - [Install HAML (Optional)](#install-haml-optional)
35
38
  - [Install DaisyUI (Optional)](#install-daisyui-optional)
36
39
  - [Try Out Your Application](#try-out-your-application)
37
40
  - [Debugging](#debugging)
38
41
  - [Testing](#testing)
42
+ - [Services / Service Objects](#services--service-objects)
39
43
  - [Authentication](#authentication)
40
44
  - [Web Console](#web-console)
41
45
  - [BetterErrors (Optional)](#bettererrors-optional)
42
46
  - [LocoMotion Components](#locomotion-components)
43
47
  - [Install](#install)
44
48
  - [Using Components](#using-components)
45
- - [Setting a Base Component Class](#setting-a-base-component-class)
46
49
  - [Developing](#developing)
47
50
  - [Tooling](#tooling)
48
51
  - [TODO / Next Steps](#todo--next-steps)
@@ -202,6 +205,20 @@ Congratulations!
202
205
  You can now visit [http://localhost:3000](http://localhost:3000) in your web
203
206
  browser and see your running Rails application!
204
207
 
208
+ ### Using UUIDs by Default
209
+
210
+ We believe strongly in migrating all of your primary keys to UUIDs to increase
211
+ security as well as avoiding potential scaling issues in the future.
212
+
213
+ To enable this by default, create the following file:
214
+
215
+ ```ruby
216
+ # config/initializers/generators.rb
217
+ Rails.application.config.generators do |generator|
218
+ generator.orm :active_record, primary_key_type: :uuid
219
+ end
220
+ ```
221
+
205
222
  ### Install HAML (Optional)
206
223
 
207
224
  While you can use the default ERB templating system that comes with Rails, we
@@ -460,16 +477,45 @@ recommned Rspec with [factory_bot](https://github.com/thoughtbot/factory_bot)
460
477
  and [Shoulda Matchers](https://github.com/thoughtbot/shoulda-matchers).
461
478
 
462
479
  Finally, although both libraries offer some functionality for testing your user
463
- interface, we recommend utilizing [Cypress](https://www.cypress.io/) instead as
464
- it more closely mimics the real user experience in a browser and it allows you
465
- to see in real-time what is happening, including in-browser debugging!
480
+ interface, we recommend utilizing [Playwright](https://playwright.dev/) instead
481
+ as it more closely mimics the real user experience in a browser and it allows
482
+ you to see in real-time what is happening, including in-browser debugging!
483
+
484
+ Although the common setup is to write your specs in JavaScript or TypeScript,
485
+ you can actually write your End to End tests in Ruby / Rspec by utilizing the
486
+ [playwright-ruby-client](https://playwright-ruby-client.vercel.app/)!
487
+
488
+ We'll have some guides and examples for this coming soon!
466
489
 
467
490
  > [!NOTE]
468
- > One thing to note about Cypress, however, is that it is Javascript-based and
469
- > thus requires you to write tests in Javascript. If you are only famililar with
470
- > Ruby, you might want to stick with Rspec or Minitest when you first start your
471
- > project, and expand into using Cypress once you are comfortable learning a new
472
- > lanugage / framework.
491
+ > We used to recommend [Cypress](https://www.cypress.io) for End-to-End tests,
492
+ > but it's reliance on JavaScript and sometimes flakey tests caused us to search
493
+ > out a new solution / recommendation.
494
+ >
495
+ > We plan to have a writeup soon (an ADR specifically) on exactly why we made
496
+ > the switch.
497
+
498
+ ## Services / Service Objects
499
+
500
+ It is best practice to separate your logic into Service Objects rather than
501
+ shoving all of it into your Controllers and Models.
502
+
503
+ One solution we really like is
504
+ [ActiveInteraction](https://github.com/AaronLasseigne/active_interaction).
505
+
506
+ It is very stable, has wonderful documentation, and gives you a clean way to
507
+ build your service objects with support for things like composed interactions
508
+ and even ActiveModel validations.
509
+
510
+ Add `gem 'active_interaction', '~> 5.3'` to your `Gemfile` and create a new
511
+ class called `ApplicationInteraction` if you want to give it a try!
512
+
513
+ ```
514
+ # app/interactions/application_interaction.rb
515
+ class ApplicationInteraction < ActiveInteraction::Base
516
+ # Your interactions will inherit from this class!
517
+ end
518
+ ```
473
519
 
474
520
  ## Authentication
475
521
 
@@ -670,9 +716,9 @@ a full set of UI components to help you build robust and full-featured apps.
670
716
 
671
717
  > [!CAUTION]
672
718
  > The LocoMotion components are being actively developed and are NOT ready for
673
- > production / public use (currently they are just some example components while
674
- > I get everything setup). I'm mainly adding the docs here so that I remember
675
- > how to set them up properly when they are ready for release.
719
+ > production / public use! We have finished basic versions of the DaisyUI
720
+ > Actions, DataDisplay, Navigation, and Feedback components, but we expect these
721
+ > to change (possibly quite a bit) as we begin to use them in projects.
676
722
 
677
723
  ### Install
678
724
 
@@ -685,7 +731,7 @@ gem "loco_motion", github: "profoundry-us/loco_motion", branch: "main", require:
685
731
 
686
732
  # or
687
733
 
688
- gem "loco_motion-rails", "0.0.6", require: "loco_motion"
734
+ gem "loco_motion-rails", "0.0.7", require: "loco_motion"
689
735
  ```
690
736
 
691
737
  Next add the following lines to the `contents` section of your
@@ -707,8 +753,8 @@ Next add the following lines to the `contents` section of your
707
753
 
708
754
  > [!WARNING]
709
755
  > Note that this will not output anything if it fails to find the right
710
- > directory, so your CSS may stop working if you update the gem and forget to
711
- > update this setting.
756
+ > directory, so your CSS may not compile properly if this command fails or finds
757
+ > the wrong gem or an older gem.
712
758
 
713
759
  Next, if you're using any of the components that require JavaScript (like the
714
760
  Countdown component), you'll need to add the library as a dependency and include
@@ -762,57 +808,35 @@ the following code and refresh your page.
762
808
  You should see a few buttons and the user info that we saved from OmniAuth
763
809
  represented as a Ruby hash! Any other content you have will be rendered below.
764
810
 
765
- ### Setting a Base Component Class
766
-
767
- Sometimes, you may want to override the way that LocoMotion handles things, or
768
- provide some functionality yourself in a sub-class of our components. Since you
769
- can't have a class inherit from two classes, we give you a way to override the
770
- base class that all of our components inherit from.
771
-
772
- This allows you to define a class that inherits from `LocoMotion::BaseComponent`
773
- and then adds any special methods or overrides to our default components.
774
-
775
- Create a file called `app/components/application_component.rb` with the following
776
- contents:
777
-
778
- ```ruby
779
- class ApplicationComponent < LocoMotion::BaseComponent
780
- end
781
- ```
782
-
783
- Then add the following to `config/initializers/loco_motion.rb`.
784
-
785
-
786
- ```ruby
787
- LocoMotion.configure do |config|
788
-
789
- # Override the base component class to inherit from our ApplicationComponent
790
- # so that we can add our own overrides / methods.
791
- Rails.application.config.after_initialize do
792
- config.base_component_class = ApplicationComponent
793
- end
794
-
795
- end
796
- ```
797
-
798
- > [!NOTE]
799
- > It doesn't have to inherit from `ApplicationComponent`, you can use any class
800
- > you want, so you could create a separate `CustomizedLocoMotionComponent` class
801
- > so that you don't have any conflicts with your `ApplicationComponent`.
802
-
803
811
  ## Developing
804
812
 
805
813
  To work on LocoMotion, first clone the repository and make sure you have Docker
806
814
  installed and running on your machine.
807
815
 
816
+ Next, create a `.env.local` file with the following contents, making sure to
817
+ replace the Unsplash keys with real ones (you can create your own account or ask
818
+ Topher for his keys).
819
+
820
+ ```.env
821
+ # .env.local
822
+ UNSPLASH_ACCESS_KEY="<< INSERT ACCESS KEY >>"
823
+ UNSPLASH_SECRET_KEY="<< INSERT SECRET KEY >>"
824
+ ```
825
+
808
826
  You should then be able to run `make rebuild` in the project directory and then
809
827
  `make all-quick` to start the services.
810
828
 
811
829
  > [!NOTE]
812
830
  >
813
- > We use `npm link` within the `docs/demo/bin/dev` script to enable quick
814
- > editing of the JavaScript library files so you don't have to publish a new
815
- > package during testing.
831
+ > We use `yarn link` in the `docs/demo/bin/setup` script to enable quick editing
832
+ > of the Javascript files so you don't have to publish new packages during
833
+ > testing.
834
+ >
835
+ > For the Ruby gem, we point directly to it via the `:path` option in the
836
+ > `Gemfile`. This means that we have a custom Heroku buildpack when we publish
837
+ > the demo site to move the files into the appropriate places.
838
+ >
839
+ > See https://github.com/profoundry-us/loco_motion-buildpack for more info.
816
840
 
817
841
  From here, you can access the demo site at http://localhost:3000 and the YARD
818
842
  docs at http://localhost:8808/docs/yard
@@ -854,6 +878,37 @@ TailwindCSS Intellisense working properly.
854
878
  ],
855
879
  ```
856
880
 
881
+ And because whitespace is important when developing inline components, you
882
+ should also add the following which prevents VSCode from adding a newline to the
883
+ bottom of your HAML files. This helps ensure that inline components don't have
884
+ trailing whitespace when using something like the `succeed` helper.
885
+
886
+ ```json
887
+ "[haml]": {
888
+ "editor.formatOnSave": false
889
+ }
890
+ ```
891
+
892
+ Alternatively, if your component is simple enough, moving the template inside
893
+ the `_component.rb` file's `call` method can also alleviate this problem.
894
+
895
+ So instead of
896
+
897
+ ```haml
898
+ - # This file has a newline at the bottom which can cause problems
899
+ = part(:component) do
900
+ = content
901
+
902
+ ```
903
+
904
+ you could do something like this:
905
+
906
+ ```ruby
907
+ def call
908
+ part(:component) { content }
909
+ end
910
+ ```
911
+
857
912
  ## TODO / Next Steps
858
913
 
859
914
  There is a LOT left to be done. We're not currently seeking assistance, but if
@@ -863,18 +918,35 @@ the GitHub Discussions feature and let us know!
863
918
  - [x] Basic versions of DaisyUI Actions
864
919
  - [x] Basic versions of DaisyUI Data Display
865
920
  - [x] Basic versions of DaisyUI Navigation
866
- - [ ] Basic versions of DaisyUI Feedback
921
+ - [x] Basic versions of DaisyUI Feedback
867
922
  - [ ] Basic versions of DaisyUI Data Input
868
923
  - [ ] Basic versions of DaisyUI Layout
869
924
  - [ ] Basic versions of DaisyUI Mockup
870
- - [ ] Get YARD docs rendering with (better) Markdown
925
+ - [x] ~~Get YARD docs rendering with (better) Markdown~~ _**Working for now**_
871
926
  - [x] Extract relevant pieces into a yard-loco_motion plugin
872
- - [ ] Publish Gem
927
+ - [x] Publish Gem
873
928
  - [x] Publish NPM package
874
- - [ ] Update YARD plugin to add `@part`s
929
+ - [x] Update YARD plugin to add `@part`s
930
+ - [x] Update YARD plugin to add `@loco_example`s with language support
875
931
  - [x] Extract doc callouts into a doc component (and / or the Daisy component)
876
- - [ ] Choose and recommend / document a pagination gem
932
+ - [ ] Choose, recommend, and document a pagination gem
877
933
  - [ ] Discuss caching techniques / setup
934
+ - [x] Create / publish a staging version of the demo site ([Demo Staging][2])
935
+ - [ ] Create / publish a staging version of the docs site
878
936
  - [ ] Create / publish a production version of the demo site
879
937
  - [ ] Create / publish a production version of the docs site
880
- - [ ] Update demo site to allow for a different docs site using ENV var
938
+ - [x] Update demo site to allow for a different docs site using ENV var
939
+ - [x] Update README to suggest Playwright
940
+ - [ ] Build some have docs / guides / examples for using playwright-ruby-client
941
+ - [x] See if we can build a `Tippable` concern that relevant components can
942
+ include to automatically add the tooltip param and classes where possible
943
+ - [x] Rename `tail` methods to `end` since we use that in other places
944
+ - [x] Update CardComponent Figure to be a proper class like other components
945
+ - [x] Create a GitHub pull request template to standardize PR submissions
946
+ - [ ] See if we can update the Join component to auto-add the `join-item` CSS
947
+ under certain conditions
948
+ - [ ] Add title and description content_for blocks to all examples for SEO purposes
949
+
950
+ [1]: https://loco-motion.profoundry.us/
951
+ [2]: https://loco-motion-demo-staging.profoundry.us/
952
+ [3]: https://loco-motion-demo-staging.profoundry.us/api-docs
@@ -1,10 +1,97 @@
1
- # Here are the Button docs!
2
- class Daisy::Actions::ButtonComponent < LocoMotion.configuration.base_component_class
3
- set_component_name :btn
1
+ #
2
+ # The Button component can be used to render HTML `<button>` or `<a>` elements
3
+ # that are styled to look like a clickable element.
4
+ #
5
+ # Note that we do **not** use component parts for the icons since we're calling
6
+ # `heroicon_tag` within the component. But we **do** provide custom CSS & HTML
7
+ # options to allow overriding / customization.
8
+ #
9
+ # Includes the {LocoMotion::Concerns::TippableComponent} module to enable easy
10
+ # tooltip addition.
11
+ #
12
+ # @loco_example Basic Usage
13
+ # = daisy_button("Click Me")
14
+ #
15
+ # = daisy_button do
16
+ # Click Me Too
17
+ #
18
+ # = daisy_button(icon: "heart", tip: "Love")
19
+ #
20
+ # = daisy_button(title: "Button with Two Icons", left_icon: "heart", right_icon: "plus")
21
+ #
22
+ class Daisy::Actions::ButtonComponent < LocoMotion::BaseComponent
23
+ prepend LocoMotion::Concerns::TippableComponent
4
24
 
5
- def initialize(*args, **kws, &block)
25
+ #
26
+ # Instantiate a new Button component.
27
+ #
28
+ # @param title [String] The title of the button. Defaults to "Submit" if none
29
+ # of title, left icon, or right icon is provided. Will be considered the
30
+ # `action` parameter if **both** the title and a block are provided.
31
+ #
32
+ # @param action [String] The Stimulus action that should fire when the button
33
+ # is clicked.
34
+ #
35
+ # @param kws [Hash] The keyword arguments for the component.
36
+ #
37
+ # @option kws title [String] The title of the button. You can also
38
+ # pass the title, icons, or any other HTML content as a block.
39
+ #
40
+ # @option kws action [String] The Stimulus action that should fire
41
+ # when the button is clicked.
42
+ #
43
+ # > **Note:** _You should use either the `action` or the `href` option, but
44
+ # not both._
45
+ #
46
+ # @option kws href [String] A path or URL to which the user will be
47
+ # directed when the button is clicked. Forces the Button to use an `<a>`
48
+ # tag.
49
+ #
50
+ # > **Note:** _You should use either the `action` or the `href` option, but
51
+ # not both._
52
+ #
53
+ # @option kws target [String] The HTML `target` of for the `<a>` tag
54
+ # (`_blank`, `_parent`, or a specific tab / window / iframe, etc).
55
+ #
56
+ # @option kws icon [String] The name of Hero icon to render inside
57
+ # the button. This is an alias of `left_icon`.
58
+ #
59
+ # @option kws icon_css [String] The CSS classes to apply to the icon.
60
+ # This is an alias of `left_icon_css`.
61
+ #
62
+ # @option kws icon_html [Hash] Additional HTML attributes to apply to
63
+ # the icon. This is an alias of `left_icon_html`.
64
+ #
65
+ # @option kws left_icon [String] The name of Hero icon to render inside
66
+ # the button to the left of the text.
67
+ #
68
+ # @option kws left_icon_css [String] The CSS classes to apply to the left
69
+ # icon.
70
+ #
71
+ # @option kws left_icon_html [Hash] Additional HTML attributes to apply to
72
+ # the left icon.
73
+ #
74
+ # @option kws right_icon [String] The name of Hero icon to render inside
75
+ # the button to the right of the text.
76
+ #
77
+ # @option kws right_icon_css [String] The CSS classes to apply to the right
78
+ # icon.
79
+ #
80
+ # @option kws right_icon_html [Hash] Additional HTML attributes to apply to
81
+ # the right icon.
82
+ #
83
+ def initialize(title = nil, action = nil, **kws, &block)
6
84
  super
7
85
 
86
+ # If both a title and a block are provided, assume the title is the action
87
+ action = title if title && block_given?
88
+
89
+ # Force the title to be nil if a block is given so we don't accidentally
90
+ # render two titles
91
+ title = nil if block_given?
92
+
93
+ @action = config_option(:action, action)
94
+
8
95
  @href = config_option(:href)
9
96
  @target = config_option(:target)
10
97
 
@@ -20,15 +107,22 @@ class Daisy::Actions::ButtonComponent < LocoMotion.configuration.base_component_
20
107
  @right_icon_css = config_option(:right_icon_css, @icon_css)
21
108
  @right_icon_html = config_option(:right_icon_html, @icon_html)
22
109
 
23
- @simple_title = config_option(:title, @left_icon || @right_icon ? nil : "Submit")
110
+ default_title = @left_icon || @right_icon ? nil : "Submit"
111
+ @simple_title = config_option(:title, title || default_title)
24
112
  end
25
113
 
114
+ #
115
+ # Calls the {setup_component} method before rendering the component.
116
+ #
26
117
  def before_render
27
118
  setup_component
28
119
  end
29
120
 
30
- private
31
-
121
+ #
122
+ # Sets the tagname to `<a>` if an `href` is provided, otherwise sets it to
123
+ # `<button>`. Adds the `btn` CSS class to the component. Also adds
124
+ # `items-center` and `gap-2` CSS classes if an icon is present.
125
+ #
32
126
  def setup_component
33
127
  if @href
34
128
  set_tag_name(:component, :a)
@@ -39,13 +133,23 @@ class Daisy::Actions::ButtonComponent < LocoMotion.configuration.base_component_
39
133
 
40
134
  add_css(:component, "btn")
41
135
 
42
- add_css(:component, "items-center gap-2") if @icon
136
+ if @icon || @left_icon || @right_icon
137
+ add_css(:component, "[:where(&)]:items-center [:where(&)]:gap-2")
138
+ end
139
+
140
+ add_html(:component, { "data-action": @action }) if @action
43
141
  end
44
142
 
143
+ #
144
+ # Returns the HTML attributes for the left icon.
145
+ #
45
146
  def left_icon_html
46
147
  { class: @left_icon_css }.merge(@left_icon_html)
47
148
  end
48
149
 
150
+ #
151
+ # Returns the HTML attributes for the right icon.
152
+ #
49
153
  def right_icon_html
50
154
  { class: @right_icon_css }.merge(@right_icon_html)
51
155
  end
@@ -1,13 +1,13 @@
1
1
  = part(:component) do
2
- - if title?
3
- = title
2
+ - if activator?
3
+ = activator
4
4
  - else
5
- = part(:title) do
6
- = @simple_title
5
+ = button
7
6
 
8
7
  - if items.any?
9
8
  = part(:menu) do
10
9
  - items.each do |item|
11
- = item
10
+ = part(:menu_item) do
11
+ = item
12
12
  - else
13
13
  = content
@@ -1,48 +1,117 @@
1
- # Here are the Button docs!
2
- class Daisy::Actions::DropdownComponent < LocoMotion.configuration.base_component_class
1
+ #
2
+ # The Dropdown component shows a Button, or any other component you wish, with a
3
+ # hovering menu that opens on click (or hover). It provides a flexible way to
4
+ # create dropdown menus with customizable triggers and content.
5
+ #
6
+ # Note that the dropdown uses slots for both the activator and menu items,
7
+ # allowing for maximum flexibility in how the dropdown is triggered and what
8
+ # content it displays.
9
+ #
10
+ # @part menu The default / styled menu rendered by the dropdown. Contains all
11
+ # menu items and provides the dropdown's positioning and animation.
12
+ # @part menu_item The styles for every item in the dropdown. Provides consistent
13
+ # spacing and hover states.
14
+ #
15
+ # @slot button The button that triggers the dropdown. This is the default trigger
16
+ # and is styled automatically.
17
+ # @slot activator A custom (i.e. non-button) activator for the dropdown.
18
+ # Automatically adds the `role="button"` and `tabindex="0"` attributes.
19
+ # @slot item+ The items in the dropdown. Each item will be styled consistently
20
+ # with proper spacing and hover states.
21
+ #
22
+ # @loco_example Basic Usage
23
+ # = daisy_dropdown do |dropdown|
24
+ # - dropdown.with_button do
25
+ # Click me!
26
+ # - dropdown.with_item do
27
+ # Item 1
28
+ # - dropdown.with_item do
29
+ # Item 2
30
+ #
31
+ # @loco_example Custom Activator
32
+ # = daisy_dropdown do |dropdown|
33
+ # - dropdown.with_activator do
34
+ # = heroicon_tag "bars-3", css: "size-6"
35
+ # - dropdown.with_item do
36
+ # Menu Item 1
37
+ # - dropdown.with_item do
38
+ # Menu Item 2
39
+ #
40
+ # @loco_example Complex Items
41
+ # = daisy_dropdown do |dropdown|
42
+ # - dropdown.with_button do
43
+ # User Settings
44
+ # - dropdown.with_item do
45
+ # .flex.gap-2.items-center
46
+ # = heroicon_tag "user-circle"
47
+ # Profile
48
+ # - dropdown.with_item do
49
+ # .flex.gap-2.items-center
50
+ # = heroicon_tag "cog-6-tooth"
51
+ # Settings
52
+ # - dropdown.with_item do
53
+ # .flex.gap-2.items-center.text-error
54
+ # = heroicon_tag "arrow-right-on-rectangle"
55
+ # Logout
56
+ #
57
+ class Daisy::Actions::DropdownComponent < LocoMotion::BaseComponent
3
58
 
4
- TitleComponent = LocoMotion::BasicComponent.build do
5
- def before_render
6
- add_html(:component, { role: "button", tabindex: 0 })
7
- end
8
- end
9
-
10
- ItemComponent = LocoMotion::BasicComponent.build do
11
- def before_render
12
- set_tag_name(:component, :li)
13
- end
14
- end
59
+ include ViewComponent::SlotableDefault
15
60
 
16
- define_parts :title, :menu
61
+ define_parts :menu, :menu_item
17
62
 
18
- renders_one :title, TitleComponent
19
- renders_many :items, ItemComponent
63
+ renders_one :activator, LocoMotion::BasicComponent.build(html: { role: "button", tabindex: 0 })
64
+ renders_one :button, Daisy::Actions::ButtonComponent
65
+ renders_many :items
20
66
 
21
- def initialize(*args, **kws, &block)
67
+ #
68
+ # Creates a new instance of the DropdownComponent.
69
+ #
70
+ # @param title [String] The title of the dropdown. Will be used as the button
71
+ # text if no custom button or activator is provided.
72
+ #
73
+ # @param kws [Hash] The keyword arguments for the component.
74
+ #
75
+ # @option kws title [String] The title of the dropdown. You can also pass this
76
+ # as the first argument.
77
+ #
78
+ def initialize(title = nil, **kws, &block)
22
79
  super
23
80
 
24
- @simple_title = config_option(:title, "Submit")
81
+ @simple_title = config_option(:title, title)
25
82
  end
26
83
 
84
+ #
85
+ # Adds the relevant Daisy classes to the component.
86
+ #
27
87
  def before_render
28
88
  setup_component
29
- setup_title
30
89
  setup_menu
31
90
  end
32
91
 
92
+ #
93
+ # Add the `dropdown` CSS class to the component.
94
+ #
33
95
  def setup_component
34
96
  add_css(:component, "dropdown")
35
97
  end
36
98
 
37
- def setup_title
38
- set_tag_name(:title, :div)
39
- add_css(:title, "btn")
40
- add_html(:title, { role: "button", tabindex: 0 })
41
- end
42
-
99
+ #
100
+ # Make the menu a `<ul> / <li>` element and add the relevant Daisy classes.
101
+ #
43
102
  def setup_menu
103
+ # Setup menu itself
44
104
  set_tag_name(:menu, :ul)
45
105
  add_css(:menu, "dropdown-content menu bg-base-100 rounded-box shadow w-52 p-2 z-[1]")
46
- add_html(:menu, { role: "menu", tabindex: 0 })
106
+
107
+ # Setup menu items
108
+ set_tag_name(:menu_item, :li)
109
+ end
110
+
111
+ #
112
+ # Provides a default button if no button or custom activator is provided.
113
+ #
114
+ def default_button
115
+ Daisy::Actions::ButtonComponent.new(title: @simple_title)
47
116
  end
48
117
  end
@@ -1,6 +1,7 @@
1
1
  - if activator?
2
- = part(:activator) do
3
- = activator
2
+ = activator
3
+ - else
4
+ = button
4
5
 
5
6
  = part(:component) do
6
7
  = part(:box) do