File tree Expand file tree Collapse file tree 10 files changed +306
-0
lines changed Expand file tree Collapse file tree 10 files changed +306
-0
lines changed Original file line number Diff line number Diff line change @@ -10,6 +10,10 @@ calendar:
10
10
js_packages :
11
11
- " mustache"
12
12
13
+ carousel :
14
+ js_packages :
15
+ - " embla-carousel"
16
+
13
17
chart :
14
18
js_packages :
15
19
- " chart.js"
Original file line number Diff line number Diff line change
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class Carousel < Base
5
+ def initialize ( orientation : :horizontal , options : { } , **user_attrs )
6
+ @orientation = orientation
7
+ @options = options
8
+
9
+ super ( **user_attrs )
10
+ end
11
+
12
+ def view_template ( &)
13
+ div ( **attrs , &)
14
+ end
15
+
16
+ private
17
+
18
+ def default_attrs
19
+ {
20
+ class : [ "relative group" , orientation_classes ] ,
21
+ role : "region" ,
22
+ aria_roledescription : "carousel" ,
23
+ data : {
24
+ controller : "ruby-ui--carousel" ,
25
+ ruby_ui__carousel_options_value : default_options . merge ( @options ) . to_json ,
26
+ action : %w[
27
+ keydown.right->ruby-ui--carousel#scrollNext:prevent
28
+ keydown.left->ruby-ui--carousel#scrollPrev:prevent
29
+ ]
30
+ }
31
+ }
32
+ end
33
+
34
+ def default_options
35
+ {
36
+ axis : ( @orientation == :horizontal ) ? "x" : "y"
37
+ }
38
+ end
39
+
40
+ def orientation_classes
41
+ ( @orientation == :horizontal ) ? "is-horizontal" : "is-vertical"
42
+ end
43
+ end
44
+ end
Original file line number Diff line number Diff line change
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class CarouselContent < Base
5
+ def view_template ( &)
6
+ div ( class : "overflow-hidden" , data : { ruby_ui__carousel_target : "viewport" } ) do
7
+ div ( **attrs , &)
8
+ end
9
+ end
10
+
11
+ private
12
+
13
+ def default_attrs
14
+ {
15
+ class : [
16
+ "flex" ,
17
+ "group-[.is-horizontal]:-ml-4" ,
18
+ "group-[.is-vertical]:-mt-4 group-[.is-vertical]:flex-col"
19
+ ]
20
+ }
21
+ end
22
+ end
23
+ end
Original file line number Diff line number Diff line change
1
+ import { Controller } from "@hotwired/stimulus" ;
2
+ import EmblaCarousel from 'embla-carousel'
3
+
4
+ const DEFAULT_OPTIONS = {
5
+ loop : true
6
+ }
7
+
8
+ export default class extends Controller {
9
+ static values = {
10
+ options : {
11
+ type : Object ,
12
+ default : { } ,
13
+ }
14
+ }
15
+ static targets = [ "viewport" , "nextButton" , "prevButton" ]
16
+
17
+ connect ( ) {
18
+ this . initCarousel ( this . #mergedOptions)
19
+ }
20
+
21
+ disconnect ( ) {
22
+ this . destroyCarousel ( )
23
+ }
24
+
25
+ initCarousel ( options , plugins = [ ] ) {
26
+ this . carousel = EmblaCarousel ( this . viewportTarget , options , plugins )
27
+
28
+ this . carousel . on ( "init" , this . #updateControls. bind ( this ) )
29
+ this . carousel . on ( "reInit" , this . #updateControls. bind ( this ) )
30
+ this . carousel . on ( "select" , this . #updateControls. bind ( this ) )
31
+ }
32
+
33
+ destroyCarousel ( ) {
34
+ this . carousel . destroy ( )
35
+ }
36
+
37
+ scrollNext ( ) {
38
+ this . carousel . scrollNext ( )
39
+ }
40
+
41
+ scrollPrev ( ) {
42
+ this . carousel . scrollPrev ( )
43
+ }
44
+
45
+ #updateControls( ) {
46
+ this . #toggleButtonsDisabledState( this . nextButtonTargets , ! this . carousel . canScrollNext ( ) )
47
+ this . #toggleButtonsDisabledState( this . prevButtonTargets , ! this . carousel . canScrollPrev ( ) )
48
+ }
49
+
50
+ #toggleButtonsDisabledState( buttons , isDisabled ) {
51
+ buttons . forEach ( ( button ) => button . disabled = isDisabled )
52
+ }
53
+
54
+ get #mergedOptions( ) {
55
+ return {
56
+ ...DEFAULT_OPTIONS ,
57
+ ...this . optionsValue
58
+ }
59
+ }
60
+ }
Original file line number Diff line number Diff line change
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class CarouselItem < Base
5
+ def view_template ( &)
6
+ div ( **attrs , &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ role : "group" ,
14
+ aria_roledescription : "slide" ,
15
+ class : [
16
+ "min-w-0 shrink-0 grow-0 basis-full" ,
17
+ "group-[.is-horizontal]:pl-4" ,
18
+ "group-[.is-vertical]:pt-4"
19
+ ]
20
+ }
21
+ end
22
+ end
23
+ end
Original file line number Diff line number Diff line change
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class CarouselNext < Base
5
+ def view_template ( &)
6
+ Button ( **attrs ) do
7
+ icon
8
+ end
9
+ end
10
+
11
+ private
12
+
13
+ def default_attrs
14
+ {
15
+ variant : :outline ,
16
+ icon : true ,
17
+ class : [
18
+ "absolute h-8 w-8 rounded-full" ,
19
+ "group-[.is-horizontal]:-right-12 group-[.is-horizontal]:top-1/2 group-[.is-horizontal]:-translate-y-1/2" ,
20
+ "group-[.is-vertical]:-bottom-12 group-[.is-vertical]:left-1/2 group-[.is-vertical]:-translate-x-1/2 group-[.is-vertical]:rotate-90"
21
+ ] ,
22
+ disabled : true ,
23
+ data : {
24
+ action : "click->ruby-ui--carousel#scrollNext" ,
25
+ ruby_ui__carousel_target : "nextButton"
26
+ }
27
+ }
28
+ end
29
+
30
+ def icon
31
+ svg (
32
+ width : "24" ,
33
+ height : "24" ,
34
+ viewBox : "0 0 24 24" ,
35
+ fill : "none" ,
36
+ stroke : "currentColor" ,
37
+ stroke_width : "2" ,
38
+ stroke_linecap : "round" ,
39
+ stroke_linejoin : "round" ,
40
+ xmlns : "http://www.w3.org/2000/svg" ,
41
+ class : "w-4 h-4"
42
+ ) do |s |
43
+ s . path ( d : "M5 12h14" )
44
+ s . path ( d : "m12 5 7 7-7 7" )
45
+ end
46
+ end
47
+ end
48
+ end
Original file line number Diff line number Diff line change
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class CarouselPrevious < Base
5
+ def view_template ( &)
6
+ Button ( **attrs ) do
7
+ icon
8
+ span ( class : "sr-only" ) { "Next slide" }
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def default_attrs
15
+ {
16
+ variant : :outline ,
17
+ icon : true ,
18
+ class : [
19
+ "absolute h-8 w-8 rounded-full" ,
20
+ "group-[.is-horizontal]:-left-12 group-[.is-horizontal]:top-1/2 group-[.is-horizontal]:-translate-y-1/2" ,
21
+ "group-[.is-vertical]:-top-12 group-[.is-vertical]:left-1/2 group-[.is-vertical]:-translate-x-1/2 group-[.is-vertical]:rotate-90"
22
+ ] ,
23
+ disabled : true ,
24
+ data : {
25
+ action : "click->ruby-ui--carousel#scrollPrev" ,
26
+ ruby_ui__carousel_target : "prevButton"
27
+ }
28
+ }
29
+ end
30
+
31
+ def icon
32
+ svg (
33
+ width : "24" ,
34
+ height : "24" ,
35
+ viewBox : "0 0 24 24" ,
36
+ fill : "none" ,
37
+ stroke : "currentColor" ,
38
+ stroke_width : "2" ,
39
+ stroke_linecap : "round" ,
40
+ stroke_linejoin : "round" ,
41
+ xmlns : "http://www.w3.org/2000/svg" ,
42
+ class : "w-4 h-4"
43
+ ) do |s |
44
+ s . path ( d : "m12 19-7-7 7-7" )
45
+ s . path ( d : "M19 12H5" )
46
+ end
47
+ end
48
+ end
49
+ end
Original file line number Diff line number Diff line change 27
27
"@hotwired/stimulus" : " ^3.2.2" ,
28
28
"chart.js" : " ^4.4.1" ,
29
29
"date-fns" : " ^2.30.0" ,
30
+ "embla-carousel" : " 8.5.2" ,
30
31
"fuse.js" : " ^7.0.0" ,
31
32
"maska" : " ^3.0.3" ,
32
33
"motion" : " ^10.16.4" ,
Original file line number Diff line number Diff line change
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class RubyUI ::CarouselTest < ComponentTest
6
+ def test_render_with_all_items
7
+ output = phlex do
8
+ RubyUI . Carousel do
9
+ RubyUI . CarouselContent do
10
+ RubyUI . CarouselItem { "Item" }
11
+ end
12
+ RubyUI . CarouselPrevious ( )
13
+ RubyUI . CarouselNext ( )
14
+ end
15
+ end
16
+
17
+ assert_match ( /Item/ , output )
18
+ assert_match ( /button/ , output )
19
+ assert_match ( / is-horizontal/ , output )
20
+ end
21
+
22
+ def test_render_with_horizontal_orientation
23
+ output = phlex do
24
+ RubyUI . Carousel ( orientation : :horizontal ) do
25
+ RubyUI . CarouselContent ( ) do
26
+ RubyUI . CarouselItem ( ) { "Item" }
27
+ end
28
+ RubyUI . CarouselPrevious ( )
29
+ RubyUI . CarouselNext ( )
30
+ end
31
+ end
32
+
33
+ assert_match ( / is-horizontal/ , output )
34
+ end
35
+
36
+ def test_render_with_vertical_orientation
37
+ output = phlex do
38
+ RubyUI . Carousel ( orientation : :vertical ) do
39
+ RubyUI . CarouselContent ( ) do
40
+ RubyUI . CarouselItem ( ) { "Item" }
41
+ end
42
+ RubyUI . CarouselPrevious ( )
43
+ RubyUI . CarouselNext ( )
44
+ end
45
+ end
46
+
47
+ assert_match ( / is-vertical/ , output )
48
+ end
49
+ end
Original file line number Diff line number Diff line change @@ -111,6 +111,11 @@ date-fns@^2.30.0:
111
111
dependencies :
112
112
" @babel/runtime" " ^7.21.0"
113
113
114
+
115
+ version "8.5.2"
116
+ resolved "https://registry.yarnpkg.com/embla-carousel/-/embla-carousel-8.5.2.tgz#95eb936d14a1b9a67b9207a0fde1f25259a5d692"
117
+ integrity sha512-xQ9oVLrun/eCG/7ru3R+I5bJ7shsD8fFwLEY7yPe27/+fDHCNj0OT5EoG5ZbFyOxOcG6yTwW8oTz/dWyFnyGpg==
118
+
114
119
fuse.js@^7.0.0 :
115
120
version "7.0.0"
116
121
resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-7.0.0.tgz#6573c9fcd4c8268e403b4fc7d7131ffcf99a9eb2"
You can’t perform that action at this time.
0 commit comments