protos 0.5.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -0
  3. data/README.md +189 -76
  4. data/examples/list.rb +2 -2
  5. data/examples/navbar.rb +3 -8
  6. data/lib/protos/accordion/item.rb +4 -2
  7. data/lib/protos/accordion.rb +10 -11
  8. data/lib/protos/alert.rb +3 -0
  9. data/lib/protos/attributes.rb +1 -18
  10. data/lib/protos/avatar.rb +10 -10
  11. data/lib/protos/badge.rb +62 -0
  12. data/lib/protos/breadcrumbs.rb +2 -0
  13. data/lib/protos/card.rb +12 -7
  14. data/lib/protos/carousel.rb +13 -10
  15. data/lib/protos/chat_bubble/content.rb +12 -12
  16. data/lib/protos/chat_bubble.rb +11 -6
  17. data/lib/protos/collapse/title.rb +3 -3
  18. data/lib/protos/collapse.rb +10 -7
  19. data/lib/protos/combobox.rb +3 -3
  20. data/lib/protos/command/input.rb +4 -4
  21. data/lib/protos/command.rb +16 -2
  22. data/lib/protos/component.rb +3 -3
  23. data/lib/protos/drawer.rb +7 -3
  24. data/lib/protos/dropdown.rb +10 -6
  25. data/lib/protos/hero.rb +3 -0
  26. data/lib/protos/list.rb +2 -0
  27. data/lib/protos/mix.rb +39 -0
  28. data/lib/protos/modal/close_button.rb +8 -0
  29. data/lib/protos/modal/dialog.rb +4 -6
  30. data/lib/protos/modal.rb +6 -1
  31. data/lib/protos/popover.rb +24 -21
  32. data/lib/protos/stats.rb +7 -0
  33. data/lib/protos/steps.rb +5 -3
  34. data/lib/protos/swap.rb +3 -0
  35. data/lib/protos/table/caption.rb +3 -3
  36. data/lib/protos/table/cell.rb +3 -3
  37. data/lib/protos/table/head.rb +3 -3
  38. data/lib/protos/table.rb +21 -13
  39. data/lib/protos/tabs/tab.rb +4 -4
  40. data/lib/protos/tabs.rb +18 -16
  41. data/lib/protos/theme.rb +8 -7
  42. data/lib/protos/timeline.rb +8 -3
  43. data/lib/protos/toast.rb +5 -3
  44. data/lib/protos/typography/paragraph.rb +3 -3
  45. data/lib/protos/typography.rb +4 -0
  46. data/lib/protos/version.rb +1 -1
  47. data/lib/protos.rb +37 -120
  48. metadata +5 -7
  49. data/lib/protos/command/dialog.rb +0 -40
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protos
4
+ class Badge < Component
5
+ Badges = Types::Coercible::Symbol.enum(
6
+ :default,
7
+ :neutral,
8
+ :success,
9
+ :primary,
10
+ :secondary,
11
+ :info,
12
+ :error,
13
+ :warning,
14
+ :ghost
15
+ )
16
+
17
+ Sizes = Types::Coercible::Symbol.enum(:default, :xs, :sm, :md, :lg)
18
+
19
+ option :type, type: Badges, default: -> { :default }
20
+ option :outline, default: -> { false }
21
+ option :size, type: Sizes, default: -> { :default }
22
+
23
+ def view_template(&)
24
+ span(**attrs, &)
25
+ end
26
+
27
+ private
28
+
29
+ def badge_style
30
+ {
31
+ neutral: "badge-neutral",
32
+ success: "badge-success",
33
+ primary: "badge-primary",
34
+ secondary: "badge-secondary",
35
+ info: "badge-info",
36
+ error: "badge-error",
37
+ warning: "badge-warning",
38
+ ghost: "badge-ghost"
39
+ }
40
+ end
41
+
42
+ def badge_size
43
+ {
44
+ xs: "badge-xs",
45
+ sm: "badge-sm",
46
+ md: "badge-md",
47
+ lg: "badge-lg"
48
+ }
49
+ end
50
+
51
+ def theme
52
+ {
53
+ container: [
54
+ "badge",
55
+ badge_style[type],
56
+ badge_size[size],
57
+ ("badge-outline" if outline)
58
+ ].compact
59
+ }
60
+ end
61
+ end
62
+ end
@@ -5,6 +5,8 @@ module Protos
5
5
  # DOCS: A list of breadcrumbs (e.g links) for navigation
6
6
  # https://daisyui.com/components/breadcrumbs/
7
7
 
8
+ autoload :Crumb, "protos/breadcrumbs/crumb"
9
+
8
10
  def view_template(&block)
9
11
  nav(**attrs) do
10
12
  ul(class: css[:list], &block)
data/lib/protos/card.rb CHANGED
@@ -5,6 +5,11 @@ module Protos
5
5
  # DOCS: A card component
6
6
  # https://daisyui.com/components/card/
7
7
 
8
+ autoload :Body, "protos/card/body"
9
+ autoload :Title, "protos/card/title"
10
+ autoload :Actions, "protos/card/actions"
11
+ autoload :Image, "protos/card/image"
12
+
8
13
  ImageDisplays = Types::Coercible::Symbol.enum(:default, :overlay, :side)
9
14
 
10
15
  IMAGE_DISPLAYS = {
@@ -16,9 +21,9 @@ module Protos
16
21
  option :border, type: Types::Bool, default: -> { true }, reader: :private
17
22
  option :compact, type: Types::Bool, default: -> { false }, reader: :private
18
23
  option :image_display,
19
- ImageDisplays,
20
- default: -> { :default },
21
- reader: false
24
+ ImageDisplays,
25
+ default: -> { :default },
26
+ reader: false
22
27
 
23
28
  def view_template(&)
24
29
  article(**attrs, &)
@@ -40,12 +45,12 @@ module Protos
40
45
 
41
46
  def theme
42
47
  {
43
- container: tokens(
48
+ container: [
44
49
  "card",
45
50
  image_display,
46
- border: "card-bordered",
47
- compact: "card-compact"
48
- )
51
+ ("card-bordered" if border),
52
+ ("card-compact" if compact)
53
+ ]
49
54
  }
50
55
  end
51
56
  end
@@ -6,6 +6,9 @@ module Protos
6
6
  # through in a mobile friendly manner.
7
7
  # https://daisyui.com/components/carousel/
8
8
 
9
+ autoload :Item, "protos/carousel/item"
10
+ autoload :Actions, "protos/carousel/actions"
11
+
9
12
  SNAP_POINTS = {
10
13
  none: "",
11
14
  center: "carousel-center",
@@ -14,13 +17,13 @@ module Protos
14
17
 
15
18
  option :vertical, type: Types::Bool, default: -> { false }
16
19
  option :snap_to,
17
- default: -> { :none },
18
- reader: false,
19
- type: Types::Coercible::Symbol.enum(
20
- :none,
21
- :center,
22
- :end
23
- )
20
+ default: -> { :none },
21
+ reader: false,
22
+ type: Types::Coercible::Symbol.enum(
23
+ :none,
24
+ :center,
25
+ :end
26
+ )
24
27
 
25
28
  def view_template(&)
26
29
  div(**attrs, &)
@@ -38,11 +41,11 @@ module Protos
38
41
 
39
42
  def theme
40
43
  {
41
- container: tokens(
44
+ container: [
42
45
  "carousel",
43
46
  snap_to,
44
- vertical: "carousel-vertical"
45
- )
47
+ ("carousel-vertical" if vertical)
48
+ ]
46
49
  }
47
50
  end
48
51
  end
@@ -18,18 +18,18 @@ module Protos
18
18
  }.freeze
19
19
 
20
20
  option :type,
21
- default: -> { :none },
22
- reader: false,
23
- type: Types::Coercible::Symbol.enum(
24
- :none,
25
- :primary,
26
- :secondary,
27
- :accent,
28
- :info,
29
- :success,
30
- :warning,
31
- :error
32
- )
21
+ default: -> { :none },
22
+ reader: false,
23
+ type: Types::Coercible::Symbol.enum(
24
+ :none,
25
+ :primary,
26
+ :secondary,
27
+ :accent,
28
+ :info,
29
+ :success,
30
+ :warning,
31
+ :error
32
+ )
33
33
 
34
34
  def view_template(&)
35
35
  div(**attrs, &)
@@ -7,18 +7,23 @@ module Protos
7
7
  # in a larger chat history.
8
8
  # https://daisyui.com/components/chat/
9
9
 
10
+ autoload :Content, "protos/chat_bubble/content"
11
+ autoload :Image, "protos/chat_bubble/image"
12
+ autoload :Header, "protos/chat_bubble/header"
13
+ autoload :Footer, "protos/chat_bubble/footer"
14
+
10
15
  ALIGNMENTS = {
11
16
  start: "chat-start",
12
17
  end: "chat-end"
13
18
  }.freeze
14
19
 
15
20
  option :align,
16
- default: -> { :start },
17
- reader: false,
18
- type: Types::Coercible::Symbol.enum(
19
- :start,
20
- :end
21
- )
21
+ default: -> { :start },
22
+ reader: false,
23
+ type: Types::Coercible::Symbol.enum(
24
+ :start,
25
+ :end
26
+ )
22
27
 
23
28
  def view_template(&)
24
29
  div(**attrs, &)
@@ -7,9 +7,9 @@ module Protos
7
7
  # visible and is used to toggle the collapse.
8
8
 
9
9
  option :input_id,
10
- type: Types::String | Types::Integer | Types::Nil,
11
- reader: false,
12
- default: -> { }
10
+ type: Types::String | Types::Integer | Types::Nil,
11
+ reader: false,
12
+ default: -> { }
13
13
 
14
14
  def view_template(&)
15
15
  if @input_id
@@ -6,19 +6,22 @@ module Protos
6
6
  # is visible at all times, and the content is only visible when expanded.
7
7
  # https://daisyui.com/components/collapse/
8
8
 
9
+ autoload :Title, "protos/collapse/title"
10
+ autoload :Content, "protos/collapse/content"
11
+
9
12
  option :input_type, default: -> { :checkbox }, reader: false
10
- option :input_id,
11
- reader: false,
12
- default: -> { "collapse-#{SecureRandom.hex(4)}" },
13
- type: Types::String
13
+ option :input_name,
14
+ reader: false,
15
+ default: -> { "collapse-#{SecureRandom.hex(4)}" },
16
+ type: Types::String | Types::Integer
14
17
 
15
18
  def view_template
16
19
  div(**attrs) do
17
20
  if @input_type
18
21
  input(
19
22
  type: @input_type,
20
- id: @input_id,
21
- name: @input_id,
23
+ id: @input_name,
24
+ name: @input_name,
22
25
  autocomplete: :off,
23
26
  # form: "" prevents the radio button from being submitted if its
24
27
  # within a form
@@ -29,7 +32,7 @@ module Protos
29
32
  end
30
33
  end
31
34
 
32
- def title(*, **, &) = render Title.new(*, input_id: @input_id, **, &)
35
+ def title(*, **, &) = render Title.new(*, input_id: @input_name, **, &)
33
36
 
34
37
  def content(...) = render Content.new(...)
35
38
 
@@ -7,9 +7,9 @@ module Protos
7
7
  # Comboboxes use popovers and command to create the list of options.
8
8
 
9
9
  option :trigger,
10
- default: -> { :click },
11
- reader: false,
12
- type: Popover::Triggers | Types::Array.of(Popover::Triggers)
10
+ default: -> { :click },
11
+ reader: false,
12
+ type: Popover::Triggers | Types::Array.of(Popover::Triggers)
13
13
 
14
14
  def trigger(...) = render Popover::Trigger.new(...)
15
15
 
@@ -6,10 +6,10 @@ module Protos
6
6
  # DOCS: The search input for the command palette
7
7
 
8
8
  option :placeholder,
9
- reader: :private,
10
- default: -> {
11
- "Type a command or search..."
12
- }
9
+ reader: :private,
10
+ default: -> {
11
+ "Type a command or search..."
12
+ }
13
13
 
14
14
  def view_template(&block)
15
15
  li(**attrs) do
@@ -6,6 +6,15 @@ module Protos
6
6
  # filterable list of commands. Command modals are by default closable by
7
7
  # clicking the overlay rather than a specific close button.
8
8
 
9
+ autoload :Input, "protos/command/input"
10
+ autoload :Dialog, "protos/command/dialog"
11
+ autoload :Group, "protos/command/group"
12
+ autoload :List, "protos/command/list"
13
+ autoload :Trigger, "protos/command/trigger"
14
+ autoload :Title, "protos/command/title"
15
+ autoload :Item, "protos/command/item"
16
+ autoload :Empty, "protos/command/empty"
17
+
9
18
  def view_template(&)
10
19
  div(**attrs, &)
11
20
  end
@@ -16,7 +25,9 @@ module Protos
16
25
 
17
26
  def trigger(...) = render Command::Trigger.new(...)
18
27
 
19
- def dialog(...) = render Command::Dialog.new(...)
28
+ def dialog(...) = render Modal::Dialog.new(...)
29
+
30
+ def close_button(...) = render Modal::CloseButton.new(...)
20
31
 
21
32
  def title(...) = render Command::Title.new(...)
22
33
 
@@ -30,7 +41,10 @@ module Protos
30
41
 
31
42
  def default_attrs
32
43
  {
33
- data: { controller: "protos--modal" }
44
+ data: {
45
+ controller: "protos--modal",
46
+ action: "click->protos--modal#backdropClose"
47
+ }
34
48
  }
35
49
  end
36
50
  end
@@ -10,7 +10,7 @@ module Protos
10
10
  # make configuring each class much easier. It also enables gathering up all
11
11
  # undefined options and adding them to the html_options hash.
12
12
 
13
- extend Dry::Initializer
13
+ extend Dry::Initializer[undefined: false]
14
14
  extend Dry::Core::ClassAttributes
15
15
 
16
16
  # Define methods for css and attrs. Each is expected to return a hash
@@ -27,14 +27,14 @@ module Protos
27
27
  option :html_options, default: -> { {} }, reader: false
28
28
 
29
29
  # Adds non-defined options to the html_options hash
30
- def initialize(*args, **kwargs, &)
30
+ def initialize(*, **kwargs, &)
31
31
  defined_keys = self.class.dry_initializer.definitions.keys
32
32
  defined, undefined =
33
33
  kwargs
34
34
  .partition { |key, _| defined_keys.include?(key) }
35
35
  .map!(&:to_h)
36
36
 
37
- super(*args, html_options: undefined, **defined, &)
37
+ super(*, html_options: undefined, **defined, &)
38
38
  end
39
39
 
40
40
  private
data/lib/protos/drawer.rb CHANGED
@@ -7,10 +7,14 @@ module Protos
7
7
  # trigger is clicked.
8
8
  # https://daisyui.com/components/drawer/
9
9
 
10
+ autoload :Side, "protos/drawer/side"
11
+ autoload :Trigger, "protos/drawer/trigger"
12
+ autoload :Content, "protos/drawer/content"
13
+
10
14
  option :id,
11
- reader: false,
12
- type: Types::Coercible::String,
13
- default: -> { "drawer-#{SecureRandom.hex(4)}" }
15
+ reader: false,
16
+ type: Types::Coercible::String,
17
+ default: -> { "drawer-#{SecureRandom.hex(4)}" }
14
18
 
15
19
  def view_template
16
20
  div(**attrs) do
@@ -10,14 +10,18 @@ module Protos
10
10
  # rather than pure CSS for accessibility. The layout of pure CSS was too
11
11
  # tricky to get right and we felt the dependency tradeoff was worthwhile.
12
12
 
13
+ autoload :Item, "protos/dropdown/item"
14
+ autoload :Menu, "protos/dropdown/menu"
15
+ autoload :Trigger, "protos/dropdown/trigger"
16
+
13
17
  option :position,
14
- type: Popover::Positions,
15
- default: -> { :bottom },
16
- reader: false
18
+ type: Popover::Positions,
19
+ default: -> { :bottom },
20
+ reader: false
17
21
  option :trigger,
18
- default: -> { :click },
19
- reader: false,
20
- type: Popover::Triggers | Types::Array.of(Popover::Triggers)
22
+ default: -> { :click },
23
+ reader: false,
24
+ type: Popover::Triggers | Types::Array.of(Popover::Triggers)
21
25
 
22
26
  def item(...) = render Item.new(...)
23
27
 
data/lib/protos/hero.rb CHANGED
@@ -6,6 +6,9 @@ module Protos
6
6
  # optionally layout an image for a responsive layout.
7
7
  # https://daisyui.com/components/hero/
8
8
 
9
+ autoload :Content, "protos/hero/content"
10
+ autoload :Overlay, "protos/hero/overlay"
11
+
9
12
  def view_template(&)
10
13
  div(**attrs, &)
11
14
  end
data/lib/protos/list.rb CHANGED
@@ -5,6 +5,8 @@ module Protos
5
5
  # DOCS: A list of items that are joined together for easier styling with
6
6
  # borders, border radius, etc.
7
7
 
8
+ autoload :Item, "protos/list/item"
9
+
8
10
  option :ordered, Types::Bool, default: -> { false }, reader: false
9
11
 
10
12
  def view_template(&)
data/lib/protos/mix.rb ADDED
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protos
4
+ class Mix
5
+ # DOCS: This class is responsible for safely merging in both user supplied
6
+ # and default attributes. When a user adds { data: { controller: "foo" }} to
7
+ # their component. This will merge the value in so that any default
8
+ # controllers do not get overridden.
9
+
10
+ MERGEABLE_ATTRIBUTES = Set.new(%i[class data]).freeze
11
+
12
+ def self.call(...) = new.call(...)
13
+
14
+ def call(old_hash, *hashes)
15
+ hashes
16
+ .compact
17
+ .each_with_object(old_hash) do |new_hash, result|
18
+ merge(result, new_hash, top_level: true)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def merge(old_hash, new_hash, top_level: false) # rubocop:disable Metrics/PerceivedComplexity
25
+ old_hash.merge!(new_hash) do |key, old, new|
26
+ next old unless new
27
+ next old if old == new
28
+ next new if top_level && !MERGEABLE_ATTRIBUTES.include?(key)
29
+
30
+ case [old, new]
31
+ in String, String then "#{old} #{new}"
32
+ in Array, Array then old + new
33
+ in Hash, Hash then merge(old, new)
34
+ else new
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -10,6 +10,14 @@ module Protos
10
10
  button(**attrs, &block)
11
11
  end
12
12
  end
13
+
14
+ private
15
+
16
+ def default_attrs
17
+ {
18
+ data: { action: "protos--modal#close" }
19
+ }
20
+ end
13
21
  end
14
22
  end
15
23
  end
@@ -14,12 +14,10 @@ module Protos
14
14
 
15
15
  private
16
16
 
17
- def attrs
18
- @attrs ||= build_attrs(
19
- {
20
- data: { "protos--modal-target": "modal" }
21
- }
22
- )
17
+ def default_attrs
18
+ {
19
+ data: { "protos--modal-target": "dialog" }
20
+ }
23
21
  end
24
22
 
25
23
  def theme
data/lib/protos/modal.rb CHANGED
@@ -5,6 +5,10 @@ module Protos
5
5
  # DOCS: A modal component that can be triggered by a button or a link and
6
6
  # will open a fullscreen modal, usually with a close button.
7
7
 
8
+ autoload :CloseButton, "protos/modal/close_button"
9
+ autoload :Dialog, "protos/modal/dialog"
10
+ autoload :Trigger, "protos/modal/trigger"
11
+
8
12
  def view_template(&)
9
13
  div(**attrs, class: css[:container], &)
10
14
  end
@@ -20,7 +24,8 @@ module Protos
20
24
  def default_attrs
21
25
  {
22
26
  data: {
23
- controller: "protos--modal"
27
+ controller: "protos--modal",
28
+ action: "click->protos--modal#backdropClose"
24
29
  }
25
30
  }
26
31
  end
@@ -12,6 +12,9 @@ module Protos
12
12
  # Tippy.js options can be passed in via the `options` attribute or, more
13
13
  # conveniently by the typed options listed below.
14
14
 
15
+ autoload :Trigger, "protos/popover/trigger"
16
+ autoload :Content, "protos/popover/content"
17
+
15
18
  Positions = Types::Coercible::Symbol.enum(
16
19
  :top,
17
20
  :top_start,
@@ -52,33 +55,33 @@ module Protos
52
55
  )
53
56
 
54
57
  option :position,
55
- type: Positions,
56
- default: -> { :top },
57
- reader: false
58
+ type: Positions,
59
+ default: -> { :top },
60
+ reader: false
58
61
  option :animation,
59
- type: Animations,
60
- default: -> { :fade },
61
- reader: false
62
+ type: Animations,
63
+ default: -> { :fade },
64
+ reader: false
62
65
  option :duration,
63
- type: Types::Integer | Types::Array.of(Types::Integer),
64
- default: -> { [300, 250] },
65
- reader: false
66
+ type: Types::Integer | Types::Array.of(Types::Integer),
67
+ default: -> { [300, 250] },
68
+ reader: false
66
69
  option :hide_on_click,
67
- type: Types::Bool | Types.Value(:toggle),
68
- default: -> { true },
69
- reader: false
70
+ type: Types::Bool | Types.Value(:toggle),
71
+ default: -> { true },
72
+ reader: false
70
73
  option :z_index,
71
- type: Types::Integer,
72
- default: -> { 9999 },
73
- reader: false
74
+ type: Types::Integer,
75
+ default: -> { 9999 },
76
+ reader: false
74
77
  option :options,
75
- default: -> { {} },
76
- reader: false,
77
- type: Types::Hash
78
+ default: -> { {} },
79
+ reader: false,
80
+ type: Types::Hash
78
81
  option :trigger,
79
- default: -> { %i[mouseenter focus] },
80
- reader: false,
81
- type: Triggers | Types::Array.of(Triggers)
82
+ default: -> { %i[mouseenter focus] },
83
+ reader: false,
84
+ type: Triggers | Types::Array.of(Triggers)
82
85
 
83
86
  def view_template(&)
84
87
  div(**attrs, &)
data/lib/protos/stats.rb CHANGED
@@ -5,6 +5,13 @@ module Protos
5
5
  # DOCS: Stats component that contains a collection of stats
6
6
  # https://daisyui.com/components/stat/
7
7
 
8
+ autoload :Actions, "protos/stats/actions"
9
+ autoload :Description, "protos/stats/description"
10
+ autoload :Figure, "protos/stats/figure"
11
+ autoload :Stat, "protos/stats/stat"
12
+ autoload :Title, "protos/stats/title"
13
+ autoload :Value, "protos/stats/value"
14
+
8
15
  def view_template(&)
9
16
  div(**attrs, &)
10
17
  end
data/lib/protos/steps.rb CHANGED
@@ -5,6 +5,8 @@ module Protos
5
5
  # DOCS: Steps can be used to show a list of steps in a process.
6
6
  # https://daisyui.com/components/steps/
7
7
 
8
+ autoload :Step, "protos/steps/step"
9
+
8
10
  option :vertical, type: Types::Bool, default: -> { false }
9
11
 
10
12
  def view_template(&)
@@ -17,10 +19,10 @@ module Protos
17
19
 
18
20
  def theme
19
21
  {
20
- container: tokens(
22
+ container: [
21
23
  "steps",
22
- vertical: "steps-vertical"
23
- )
24
+ ("steps-vertical" if vertical)
25
+ ]
24
26
  }
25
27
  end
26
28
  end
data/lib/protos/swap.rb CHANGED
@@ -6,6 +6,9 @@ module Protos
6
6
  # display different content.
7
7
  # https://daisyui.com/components/swap/
8
8
 
9
+ autoload :On, "protos/swap/on"
10
+ autoload :Off, "protos/swap/off"
11
+
9
12
  def view_template
10
13
  label(**attrs) do
11
14
  input(
@@ -11,9 +11,9 @@ module Protos
11
11
  }.freeze
12
12
 
13
13
  option :side,
14
- reader: false,
15
- type: Types::Coercible::Symbol.enum(:bottom, :top),
16
- default: -> { :bottom }
14
+ reader: false,
15
+ type: Types::Coercible::Symbol.enum(:bottom, :top),
16
+ default: -> { :bottom }
17
17
 
18
18
  def view_template(&)
19
19
  caption(**attrs, &)