protos 0.7.0 → 1.0.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.
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protos
4
+ class Diff < Component
5
+ autoload :Item, "protos/diff/item"
6
+ autoload :Resizer, "protos/diff/resizer"
7
+
8
+ def view_template(&)
9
+ figure(**attrs, &)
10
+ end
11
+
12
+ def item_one(*, **, &) = render Item.new(*, order: :one, **, &)
13
+ def item_two(*, **, &) = render Item.new(*, order: :two, **, &)
14
+ def resizer(...) = render Resizer.new(...)
15
+
16
+ private
17
+
18
+ def default_attrs
19
+ {
20
+ tabindex: 0
21
+ }
22
+ end
23
+
24
+ def theme
25
+ {
26
+ container: "diff"
27
+ }
28
+ end
29
+ end
30
+ end
@@ -8,8 +8,8 @@ module Protos
8
8
  # dropdowns comes from there.
9
9
 
10
10
  def view_template(&block)
11
- template_tag(**template_attrs) do
12
- ul(**attrs, &block)
11
+ template(**template_attrs) do
12
+ render ::Protos::Menu.new(**attrs, &block)
13
13
  end
14
14
  end
15
15
 
@@ -18,11 +18,8 @@ module Protos
18
18
  def theme
19
19
  {
20
20
  container: %w[
21
- menu
22
21
  dropdown-content
23
22
  z-10
24
- bg-base-100
25
- rounded-box
26
23
  ]
27
24
  }
28
25
  end
@@ -7,6 +7,9 @@ module Protos
7
7
  # work for list items, including border radius. E.g. only the first and
8
8
  # last items will have border radius on the top and bottom.
9
9
 
10
+ option :wrap, Types::Bool, default: -> { false }, reader: :private
11
+ option :grow, Types::Bool, default: -> { false }, reader: :private
12
+
10
13
  def view_template(&)
11
14
  li(**attrs, &)
12
15
  end
@@ -15,9 +18,10 @@ module Protos
15
18
 
16
19
  def theme
17
20
  {
18
- container: %w[
19
- join-item
20
- [&:not(:first-child)]:border-t-0
21
+ container: [
22
+ "list-row",
23
+ ("list-col-wrap" if wrap),
24
+ ("list-col-grow" if grow)
21
25
  ]
22
26
  }
23
27
  end
data/lib/protos/list.rb CHANGED
@@ -19,7 +19,7 @@ module Protos
19
19
 
20
20
  def theme
21
21
  {
22
- container: "join join-vertical"
22
+ container: "list"
23
23
  }
24
24
  end
25
25
 
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protos
4
+ class Menu
5
+ class Item < Component
6
+ option :title, type: Types::Bool, default: -> { false }
7
+
8
+ def view_template(&)
9
+ li(**attrs, &)
10
+ end
11
+
12
+ private
13
+
14
+ def theme
15
+ {
16
+ container: [
17
+ ("menu-title" if title)
18
+ ]
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protos
4
+ class Menu < Component
5
+ # DOCS: A menu of links or actions.
6
+ # https://daisyui.com/components/menu/
7
+
8
+ Directions = Types::Coercible::Symbol.enum(:vertical, :horizontal)
9
+ Sizes = Types::Coercible::Symbol.enum(:xs, :sm, :md, :lg, :xl)
10
+
11
+ DIRECTIONS = {
12
+ vertical: "",
13
+ horizontal: "menu-horizontal"
14
+ }.freeze
15
+
16
+ SIZES = {
17
+ xs: "menu-xs",
18
+ sm: "menu-sm",
19
+ md: "menu-md",
20
+ lg: "menu-lg",
21
+ xl: "menu-xl"
22
+ }.freeze
23
+
24
+ autoload :Item, "protos/menu/item"
25
+
26
+ option :size,
27
+ type: Sizes,
28
+ default: -> { :md },
29
+ reader: :private
30
+
31
+ option :direction,
32
+ type: Directions,
33
+ default: -> { :vertical },
34
+ reader: :private
35
+
36
+ def view_template(&)
37
+ ul(**attrs, &)
38
+ end
39
+
40
+ def item(...)
41
+ render Item.new(...)
42
+ end
43
+
44
+ private
45
+
46
+ def theme
47
+ {
48
+ container: [
49
+ "menu",
50
+ DIRECTIONS[direction],
51
+ SIZES[size]
52
+ ]
53
+ }
54
+ end
55
+ end
56
+ end
data/lib/protos/mix.rb CHANGED
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Protos
4
- class Mix
4
+ module Mix
5
5
  # DOCS: This class is responsible for safely merging in both user supplied
6
6
  # and default attributes. When a user adds { data: { controller: "foo" }} to
7
7
  # their component. This will merge the value in so that any default
8
8
  # controllers do not get overridden.
9
9
 
10
- MERGEABLE_ATTRIBUTES = Set.new(%i[class data]).freeze
10
+ module_function
11
11
 
12
- def self.call(...) = new.call(...)
12
+ MERGEABLE_ATTRIBUTES = Set.new(%i[class data]).freeze
13
13
 
14
14
  def call(old_hash, *hashes)
15
15
  hashes
@@ -19,8 +19,6 @@ module Protos
19
19
  end
20
20
  end
21
21
 
22
- private
23
-
24
22
  def merge(old_hash, new_hash, top_level: false) # rubocop:disable Metrics/PerceivedComplexity
25
23
  old_hash.merge!(new_hash) do |key, old, new|
26
24
  next old unless new
@@ -11,7 +11,7 @@ module Protos
11
11
  # TODO: Move away from using template
12
12
 
13
13
  def view_template(&block)
14
- template_tag(**template_attrs) do
14
+ template(**template_attrs) do
15
15
  div(**attrs, &block)
16
16
  end
17
17
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protos
4
+ class Status < Component
5
+ STYLES = {
6
+ default: "",
7
+ accent: "status-accent",
8
+ error: "status-error",
9
+ info: "status-info",
10
+ neutral: "status-neutral",
11
+ primary: "status-primary",
12
+ secondary: "status-secondary",
13
+ success: "status-success",
14
+ warning: "status-warning"
15
+ }.freeze
16
+
17
+ Sizes = Types::Coercible::Symbol.enum(:xs, :sm, :md, :lg, :xl)
18
+
19
+ SIZES = {
20
+ xs: "status-xs",
21
+ sm: "status-sm",
22
+ md: "status-md",
23
+ lg: "status-lg",
24
+ xl: "status-xl"
25
+ }.freeze
26
+
27
+ option :type, type: Types::Styles, default: -> { :primary }
28
+ option :size, type: Sizes, default: -> { :md }
29
+
30
+ def view_template(&)
31
+ div(**attrs, &)
32
+ end
33
+
34
+ private
35
+
36
+ def theme
37
+ {
38
+ container: [
39
+ "status",
40
+ STYLES.fetch(@type),
41
+ SIZES.fetch(@size)
42
+ ]
43
+ }
44
+ end
45
+ end
46
+ end
@@ -5,17 +5,6 @@ module Protos
5
5
  class Step < Protos::Component
6
6
  # DOCS: Step component that contains a single step in a list of steps
7
7
 
8
- Styles = Types::Coercible::Symbol.enum(
9
- :default,
10
- :primary,
11
- :secondary,
12
- :accent,
13
- :info,
14
- :success,
15
- :warning,
16
- :error
17
- )
18
-
19
8
  STYLES = {
20
9
  default: "",
21
10
  primary: "step-primary",
@@ -27,7 +16,7 @@ module Protos
27
16
  error: "step-error"
28
17
  }.freeze
29
18
 
30
- option :type, reader: false, type: Styles, default: -> { :default }
19
+ option :type, reader: false, type: Types::Styles, default: -> { :default }
31
20
 
32
21
  def view_template(&)
33
22
  li(**attrs, &)
@@ -5,6 +5,8 @@ module Protos
5
5
  class Caption < Component
6
6
  # DOCS: The caption of a table
7
7
 
8
+ Sides = Types::Coercible::Symbol.enum(:bottom, :top)
9
+
8
10
  SIDES = {
9
11
  bottom: "caption-bottom",
10
12
  top: "caption-top"
@@ -12,7 +14,7 @@ module Protos
12
14
 
13
15
  option :side,
14
16
  reader: false,
15
- type: Types::Coercible::Symbol.enum(:bottom, :top),
17
+ type: Sides,
16
18
  default: -> { :bottom }
17
19
 
18
20
  def view_template(&)
data/lib/protos/table.rb CHANGED
@@ -13,6 +13,13 @@ module Protos
13
13
  autoload :Row, "protos/table/row"
14
14
  autoload :Cell, "protos/table/cell"
15
15
 
16
+ Sizes = Types::Coercible::Symbol.enum(
17
+ :xs,
18
+ :sm,
19
+ :md,
20
+ :lg
21
+ )
22
+
16
23
  SIZES = {
17
24
  xs: "table-xs",
18
25
  sm: "table-sm",
@@ -26,12 +33,7 @@ module Protos
26
33
  option :size,
27
34
  default: -> { :md },
28
35
  reader: false,
29
- type: Types::Coercible::Symbol.enum(
30
- :xs,
31
- :sm,
32
- :md,
33
- :lg
34
- )
36
+ type: Sizes
35
37
 
36
38
  def view_template(&block)
37
39
  div(**attrs) do
data/lib/protos/tabs.rb CHANGED
@@ -7,6 +7,27 @@ module Protos
7
7
 
8
8
  autoload :Tab, "protos/tabs/tab"
9
9
 
10
+ Styles = Types::Coercible::Symbol.enum(
11
+ :default,
12
+ :boxed,
13
+ :bordered,
14
+ :lifted
15
+ )
16
+
17
+ Sizes = Types::Coercible::Symbol.enum(
18
+ :xs,
19
+ :sm,
20
+ :md,
21
+ :lg
22
+ )
23
+
24
+ STYLES = {
25
+ default: "",
26
+ bordered: "tabs-bordered",
27
+ boxed: "tabs-boxed",
28
+ lifted: "tabs-lifted"
29
+ }.freeze
30
+
10
31
  SIZES = {
11
32
  xs: "tabs-xs",
12
33
  sm: "tabs-sm",
@@ -17,21 +38,11 @@ module Protos
17
38
  option :type,
18
39
  default: -> { :default },
19
40
  reader: false,
20
- type: Types::Coercible::Symbol.enum(
21
- :default,
22
- :boxed,
23
- :bordered,
24
- :lifted
25
- )
41
+ type: Styles
26
42
  option :size,
27
43
  default: -> { :md },
28
44
  reader: false,
29
- type: Types::Coercible::Symbol.enum(
30
- :xs,
31
- :sm,
32
- :md,
33
- :lg
34
- )
45
+ type: Sizes
35
46
 
36
47
  def view_template(&)
37
48
  div(**attrs, &)
@@ -46,12 +57,7 @@ module Protos
46
57
  end
47
58
 
48
59
  def type
49
- {
50
- bordered: "tabs-bordered",
51
- boxed: "tabs-boxed",
52
- lifted: "tabs-lifted",
53
- default: ""
54
- }.fetch(@type)
60
+ STYLES.fetch(@type)
55
61
  end
56
62
 
57
63
  def default_attrs
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protos
4
+ class TailwindMerge
5
+ DEFAULTS = ::TailwindMerge::Config::DEFAULTS
6
+ DAISY_CLASS_GROUPS = {
7
+ alert: [
8
+ alert: Protos::Alert::Styles.values.map(&:to_s)
9
+ ],
10
+ mask: [
11
+ mask: Protos::Avatar::MaskShapes.values.map(&:to_s)
12
+ ],
13
+ avatar: [
14
+ avatar: Protos::Avatar::Indicators.values.map(&:to_s)
15
+ ],
16
+ badge: [
17
+ badge: Protos::Badge::Styles.values.map(&:to_s)
18
+ ],
19
+ card: [
20
+ card: Protos::Card::Sizes.values.map(&:to_s)
21
+ ],
22
+ carousel: [
23
+ carousel: Protos::Carousel::Positions.values.map(&:to_s)
24
+ ],
25
+ "chat-bubble": [
26
+ { "chat-bubble": Protos::ChatBubble::Positions.values.map(&:to_s) },
27
+ {
28
+ "chat-bubble": Types::Styles.values.map(&:to_s)
29
+ }
30
+ ],
31
+ menu: [
32
+ menu: Protos::Menu::Sizes.values.map(&:to_s)
33
+ ],
34
+ table: [
35
+ table: Protos::Table::Sizes.values.map(&:to_s)
36
+ ],
37
+ tab: [
38
+ tab: Protos::Tabs::Sizes.values.map(&:to_s)
39
+ ],
40
+ caption: [
41
+ caption: Protos::Table::Caption::Sides.values.map(&:to_s)
42
+ ],
43
+ swap: [
44
+ swap: %w[on off]
45
+ ],
46
+ step: [
47
+ step: Types::Styles.values.map(&:to_s)
48
+ ]
49
+ }.freeze
50
+
51
+ def initialize
52
+ @merger = ::TailwindMerge::Merger.new(
53
+ config: DEFAULTS.merge(
54
+ ignore_empty_cache: true,
55
+ cache_size: 500,
56
+ class_groups: DEFAULTS[:class_groups].merge(DAISY_CLASS_GROUPS)
57
+ )
58
+ )
59
+ end
60
+
61
+ def merge(...)
62
+ @merger.merge(...)
63
+ end
64
+ end
65
+ end
data/lib/protos/theme.rb CHANGED
@@ -9,29 +9,38 @@ module Protos
9
9
 
10
10
  class << self
11
11
  def merger
12
- @merger ||= TailwindMerge::Merger.new.freeze
12
+ # This could be a class variable to save memory for subclasses being
13
+ # used along side this class, but seeing as how its an
14
+ # internal class I don't see much benefit at the moment.
15
+ @merger ||= TailwindMerge.new
13
16
  end
14
17
  end
15
18
 
16
19
  def initialize(theme = {}, tailwind_merge: true, **kwargs)
17
- @tailwind_merge = tailwind_merge
20
+ @should_merge = tailwind_merge
18
21
 
19
22
  @theme = Hash.new do |hash, key|
20
23
  hash[key] = TokenList.new
21
24
  end
22
25
 
26
+ return if kwargs.empty? && theme.empty?
27
+
23
28
  theme.merge!(kwargs).each do |key, value|
24
29
  @theme[key].add(value)
25
30
  end
26
31
  end
27
32
 
33
+ # Key can be a symbol or string, they will be merged together for the final
34
+ # css class.
35
+ # - A symbol will be used to fetch a `TokenList` from the theme at that key.
36
+ # - A string is used as a plain css value
28
37
  def [](*keys)
29
- symbols, strings = keys.partition { |key| key.is_a?(Symbol) }
30
- values = @theme.values_at(*symbols).join(" ")
31
- values += " #{strings.join(" ")}" unless strings.empty?
38
+ symbols, strings = keys.partition { |key| key.instance_of?(Symbol) }
39
+ values = @theme.values_at(*symbols).map!(&:to_s).reject(&:empty?)
40
+ values.concat(strings) unless strings.empty?
32
41
 
33
42
  return nil if values.empty?
34
- return values unless @tailwind_merge
43
+ return values unless @should_merge
35
44
 
36
45
  self.class.merger.merge(values)
37
46
  end
@@ -47,42 +56,34 @@ module Protos
47
56
  end
48
57
 
49
58
  def remove(key, value)
50
- @theme[key].remove(value)
51
- @theme.delete(key) if @theme[key].empty?
59
+ token_list = @theme[key].remove(value)
60
+ @theme.delete(key) if token_list.empty?
52
61
  end
53
62
 
54
63
  def set(key, value)
55
64
  return if value.nil?
56
65
 
57
- @theme[key].clear.add(value)
66
+ if @theme.key?(key)
67
+ @theme[key].clear.add(value)
68
+ else
69
+ @theme[key].add(value)
70
+ end
58
71
  end
59
72
 
60
73
  def merge(hash)
61
74
  return self unless hash
62
75
 
63
76
  hash.each do |key, value|
64
- if key?(key)
65
- add(key, value)
66
- elsif negation?(key)
67
- remove(key[1..].to_sym, value)
68
- elsif override?(key)
69
- set(key[..-2].to_sym, value)
70
- else
71
- set(key, value)
72
- end
77
+ next add(key, value) if key?(key.to_sym)
78
+ # Handle negation
79
+ next remove(key[1..].to_sym, value) if key.start_with?("!")
80
+ # handle override
81
+ next set(key[..-2].to_sym, value) if key.end_with?("!")
82
+
83
+ set(key.to_sym, value)
73
84
  end
74
85
 
75
86
  self
76
87
  end
77
-
78
- private
79
-
80
- def negation?(key)
81
- key.start_with?("!")
82
- end
83
-
84
- def override?(key)
85
- key.end_with?("!")
86
- end
87
88
  end
88
89
  end
data/lib/protos/types.rb CHANGED
@@ -3,5 +3,16 @@
3
3
  module Protos
4
4
  module Types
5
5
  include Dry.Types()
6
+
7
+ Styles = Types::Coercible::Symbol.enum(
8
+ :default,
9
+ :primary,
10
+ :secondary,
11
+ :accent,
12
+ :info,
13
+ :success,
14
+ :warning,
15
+ :error
16
+ )
6
17
  end
7
18
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Protos
4
- VERSION = "0.7.0"
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/protos.rb CHANGED
@@ -16,6 +16,7 @@ module Protos
16
16
  autoload :Theme, "protos/theme"
17
17
  autoload :Mix, "protos/mix"
18
18
  autoload :Attributes, "protos/attributes"
19
+ autoload :TailwindMerge, "protos/tailwind_merge"
19
20
 
20
21
  # Components
21
22
  autoload :Accordion, "protos/accordion"
@@ -28,13 +29,16 @@ module Protos
28
29
  autoload :ChatBubble, "protos/chat_bubble"
29
30
  autoload :Collapse, "protos/collapse"
30
31
  autoload :Command, "protos/command"
32
+ autoload :Diff, "protos/diff"
31
33
  autoload :Drawer, "protos/drawer"
32
34
  autoload :Hero, "protos/hero"
33
35
  autoload :List, "protos/list"
36
+ autoload :Menu, "protos/menu"
34
37
  autoload :Modal, "protos/modal"
35
38
  autoload :Popover, "protos/popover"
36
39
  autoload :Stats, "protos/stats"
37
40
  autoload :Steps, "protos/steps"
41
+ autoload :Status, "protos/status"
38
42
  autoload :Swap, "protos/swap"
39
43
  autoload :Tabs, "protos/tabs"
40
44
  autoload :Table, "protos/table"
data/protos.gemspec CHANGED
@@ -46,11 +46,10 @@ Gem::Specification.new do |spec|
46
46
  spec.require_paths = ["lib"]
47
47
 
48
48
  # Uncomment to register a new dependency of your gem
49
- spec.add_dependency "dry-core", "~> 1.0"
50
- spec.add_dependency "dry-initializer", "~> 3.1"
51
- spec.add_dependency "dry-types", "~> 1.7"
52
- spec.add_dependency "phlex", "~> 1.10"
53
- spec.add_dependency "tailwind_merge", "~> 0.10"
49
+ spec.add_dependency "dry-initializer", "~> 3.2"
50
+ spec.add_dependency "dry-types", "~> 1.8"
51
+ spec.add_dependency "phlex", "~> 2"
52
+ spec.add_dependency "tailwind_merge", "~> 1"
54
53
 
55
54
  # For more information and examples about making a new gem, check out our
56
55
  # guide at: https://bundler.io/guides/creating_gem.html