protos 0.5.0 → 0.7.0

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 (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, &)