stimulus_plumbers 0.2.8 → 0.3.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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +52 -0
  3. data/README.md +8 -4
  4. data/app/assets/javascripts/stimulus-plumbers/stimulus-plumbers-controllers.es.js +450 -436
  5. data/app/assets/javascripts/stimulus-plumbers/stimulus-plumbers-controllers.umd.js +1 -1
  6. data/lib/stimulus_plumbers/components/action_list/item.rb +27 -0
  7. data/lib/stimulus_plumbers/components/action_list/section.rb +21 -0
  8. data/lib/stimulus_plumbers/components/action_list.rb +23 -0
  9. data/lib/stimulus_plumbers/components/avatar.rb +73 -0
  10. data/lib/stimulus_plumbers/components/button/group.rb +17 -0
  11. data/lib/stimulus_plumbers/components/button.rb +27 -0
  12. data/lib/stimulus_plumbers/components/calendar/month/turbo/days_of_month.rb +60 -41
  13. data/lib/stimulus_plumbers/components/calendar/month/turbo/days_of_week.rb +15 -12
  14. data/lib/stimulus_plumbers/components/calendar/month/turbo.rb +55 -0
  15. data/lib/stimulus_plumbers/components/calendar.rb +56 -0
  16. data/lib/stimulus_plumbers/components/card/section.rb +25 -0
  17. data/lib/stimulus_plumbers/components/card.rb +27 -0
  18. data/lib/stimulus_plumbers/components/combobox/autocomplete.rb +30 -34
  19. data/lib/stimulus_plumbers/components/combobox/date.rb +16 -18
  20. data/lib/stimulus_plumbers/components/combobox/dropdown.rb +13 -16
  21. data/lib/stimulus_plumbers/components/combobox/options/option.rb +34 -0
  22. data/lib/stimulus_plumbers/components/combobox/options/option_group.rb +29 -0
  23. data/lib/stimulus_plumbers/components/combobox/options.rb +59 -0
  24. data/lib/stimulus_plumbers/components/combobox/popover.rb +20 -0
  25. data/lib/stimulus_plumbers/components/combobox/time/drum.rb +37 -0
  26. data/lib/stimulus_plumbers/components/combobox/time.rb +32 -15
  27. data/lib/stimulus_plumbers/components/combobox/trigger.rb +38 -0
  28. data/lib/stimulus_plumbers/components/combobox.rb +59 -0
  29. data/lib/stimulus_plumbers/components/date_picker/navigation.rb +14 -22
  30. data/lib/stimulus_plumbers/components/date_picker/navigator.rb +1 -1
  31. data/lib/stimulus_plumbers/components/icon.rb +43 -0
  32. data/lib/stimulus_plumbers/components/popover/builder.rb +25 -0
  33. data/lib/stimulus_plumbers/components/popover.rb +31 -0
  34. data/lib/stimulus_plumbers/configuration.rb +3 -18
  35. data/lib/stimulus_plumbers/engine.rb +2 -2
  36. data/lib/stimulus_plumbers/form/builder.rb +8 -6
  37. data/lib/stimulus_plumbers/form/{field_component.rb → field.rb} +1 -1
  38. data/lib/stimulus_plumbers/form/fields/combobox.rb +7 -4
  39. data/lib/stimulus_plumbers/form/fields/error.rb +14 -0
  40. data/lib/stimulus_plumbers/form/fields/group.rb +14 -0
  41. data/lib/stimulus_plumbers/form/fields/hint.rb +14 -0
  42. data/lib/stimulus_plumbers/form/fields/label.rb +21 -0
  43. data/lib/stimulus_plumbers/form/fields/renderer.rb +20 -21
  44. data/lib/stimulus_plumbers/form/fields/search.rb +23 -9
  45. data/lib/stimulus_plumbers/form/fields/submit.rb +23 -0
  46. data/lib/stimulus_plumbers/helpers/action_list_helper.rb +2 -2
  47. data/lib/stimulus_plumbers/helpers/avatar_helper.rb +2 -2
  48. data/lib/stimulus_plumbers/helpers/button_helper.rb +2 -2
  49. data/lib/stimulus_plumbers/helpers/calendar_helper.rb +1 -1
  50. data/lib/stimulus_plumbers/helpers/calendar_turbo_helper.rb +1 -1
  51. data/lib/stimulus_plumbers/helpers/card_helper.rb +2 -2
  52. data/lib/stimulus_plumbers/helpers/combobox_helper.rb +5 -5
  53. data/lib/stimulus_plumbers/helpers/popover_helper.rb +2 -2
  54. data/lib/stimulus_plumbers/plumber/base.rb +20 -0
  55. data/lib/stimulus_plumbers/plumber/dispatcher/callable_inspector.rb +19 -0
  56. data/lib/stimulus_plumbers/plumber/dispatcher/instance_exec.rb +35 -0
  57. data/lib/stimulus_plumbers/plumber/dispatcher/klass_proxy.rb +34 -0
  58. data/lib/stimulus_plumbers/plumber/dispatcher/method_call.rb +36 -0
  59. data/lib/stimulus_plumbers/plumber/dispatcher.rb +28 -0
  60. data/lib/stimulus_plumbers/plumber/html_options.rb +52 -0
  61. data/lib/stimulus_plumbers/plumber/renderer.rb +89 -0
  62. data/lib/stimulus_plumbers/themes/base.rb +34 -20
  63. data/lib/stimulus_plumbers/themes/configuration.rb +38 -0
  64. data/lib/stimulus_plumbers/themes/schema/form/ranges.rb +14 -0
  65. data/lib/stimulus_plumbers/themes/schema/icon.rb +32 -0
  66. data/lib/stimulus_plumbers/themes/schema/ranges.rb +5 -5
  67. data/lib/stimulus_plumbers/themes/schema.rb +103 -0
  68. data/lib/stimulus_plumbers/version.rb +1 -1
  69. data/lib/stimulus_plumbers.rb +29 -19
  70. metadata +40 -34
  71. data/lib/stimulus_plumbers/components/action_list/renderer.rb +0 -47
  72. data/lib/stimulus_plumbers/components/avatar/renderer.rb +0 -74
  73. data/lib/stimulus_plumbers/components/button/renderer.rb +0 -33
  74. data/lib/stimulus_plumbers/components/calendar/month/turbo/renderer.rb +0 -57
  75. data/lib/stimulus_plumbers/components/calendar/renderer.rb +0 -35
  76. data/lib/stimulus_plumbers/components/card/renderer.rb +0 -41
  77. data/lib/stimulus_plumbers/components/combobox/option.rb +0 -27
  78. data/lib/stimulus_plumbers/components/combobox/option_group.rb +0 -52
  79. data/lib/stimulus_plumbers/components/combobox/renderer.rb +0 -78
  80. data/lib/stimulus_plumbers/components/icon/renderer.rb +0 -51
  81. data/lib/stimulus_plumbers/components/plumber/base.rb +0 -22
  82. data/lib/stimulus_plumbers/components/plumber/dispatcher.rb +0 -113
  83. data/lib/stimulus_plumbers/components/plumber/html_options.rb +0 -53
  84. data/lib/stimulus_plumbers/components/plumber/renderer.rb +0 -91
  85. data/lib/stimulus_plumbers/components/popover/renderer.rb +0 -46
  86. data/lib/stimulus_plumbers/components/time_picker/renderer.rb +0 -38
  87. data/lib/stimulus_plumbers/themes/base/action_list.rb +0 -14
  88. data/lib/stimulus_plumbers/themes/base/avatar.rb +0 -14
  89. data/lib/stimulus_plumbers/themes/base/button.rb +0 -18
  90. data/lib/stimulus_plumbers/themes/base/calendar.rb +0 -15
  91. data/lib/stimulus_plumbers/themes/base/card.rb +0 -12
  92. data/lib/stimulus_plumbers/themes/base/form.rb +0 -34
  93. data/lib/stimulus_plumbers/themes/base/layout.rb +0 -12
  94. data/lib/stimulus_plumbers/themes/tailwind/action_list.rb +0 -33
  95. data/lib/stimulus_plumbers/themes/tailwind/avatar.rb +0 -52
  96. data/lib/stimulus_plumbers/themes/tailwind/button.rb +0 -89
  97. data/lib/stimulus_plumbers/themes/tailwind/calendar.rb +0 -34
  98. data/lib/stimulus_plumbers/themes/tailwind/card.rb +0 -24
  99. data/lib/stimulus_plumbers/themes/tailwind/form.rb +0 -108
  100. data/lib/stimulus_plumbers/themes/tailwind/layout.rb +0 -25
  101. data/lib/stimulus_plumbers/themes/tailwind_theme.rb +0 -29
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Plumber
5
+ class Base
6
+ include HtmlOptions
7
+ include Renderer
8
+
9
+ attr_reader :template
10
+
11
+ def initialize(template)
12
+ @template = template
13
+ end
14
+
15
+ def theme
16
+ StimulusPlumbers.config.theme.current
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Plumber
5
+ module Dispatcher
6
+ module CallableInspector
7
+ private
8
+
9
+ def args_for(callable)
10
+ callable.arity.negative? ? args : args.take(callable.arity)
11
+ end
12
+
13
+ def accepts_kwargs?(callable)
14
+ callable.parameters.any? { |type, _| %i[key keyreq keyrest].include?(type) }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Plumber
5
+ module Dispatcher
6
+ class InstanceExec
7
+ include CallableInspector
8
+
9
+ attr_reader :block, :args, :kwargs
10
+
11
+ def initialize(block, *args, **kwargs)
12
+ @block = block
13
+ @args = args
14
+ @kwargs = kwargs
15
+ validate!
16
+ end
17
+
18
+ def call(target)
19
+ dispatched = args_for(block)
20
+ if accepts_kwargs?(block)
21
+ target.instance_exec(*dispatched, **kwargs, &block)
22
+ else
23
+ target.instance_exec(*dispatched, &block)
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def validate!
30
+ raise ArgumentError, "invalid block: #{block.inspect}" unless block.is_a?(Proc)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Plumber
5
+ module Dispatcher
6
+ class KlassProxy
7
+ attr_reader :klass, :method_name, :args, :kwargs, :init_args, :init_kwargs
8
+
9
+ def initialize(klass, method_name, *args, init_args: [], init_kwargs: {}, **kwargs)
10
+ @klass = klass
11
+ @method_name = method_name
12
+ @args = args
13
+ @kwargs = kwargs
14
+ @init_args = init_args
15
+ @init_kwargs = init_kwargs
16
+ validate!
17
+ end
18
+
19
+ def call(_target)
20
+ klass.new(*init_args, **init_kwargs).public_send(method_name, *args, **kwargs)
21
+ end
22
+
23
+ private
24
+
25
+ def validate!
26
+ raise ArgumentError, "invalid class: #{klass.inspect}" unless klass.is_a?(Module)
27
+ return if method_name.is_a?(String) || method_name.is_a?(Symbol)
28
+
29
+ raise ArgumentError, "invalid method name: #{method_name.inspect}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Plumber
5
+ module Dispatcher
6
+ class MethodCall
7
+ include CallableInspector
8
+
9
+ attr_reader :method_name, :args, :kwargs
10
+
11
+ def initialize(method_name, *args, **kwargs)
12
+ @method_name = method_name
13
+ @args = args
14
+ @kwargs = kwargs
15
+ validate!
16
+ end
17
+
18
+ def call(target)
19
+ raise NotImplementedError, "#{method_name.inspect} not implemented" unless target.respond_to?(method_name, true)
20
+
21
+ method_call = target.method(method_name)
22
+ dispatched = args_for(method_call)
23
+ accepts_kwargs?(method_call) ? method_call.call(*dispatched, **kwargs) : method_call.call(*dispatched)
24
+ end
25
+
26
+ private
27
+
28
+ def validate!
29
+ return if method_name.is_a?(String) || method_name.is_a?(Symbol)
30
+
31
+ raise ArgumentError, "invalid method name: #{method_name.inspect}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "dispatcher/callable_inspector"
4
+ require_relative "dispatcher/method_call"
5
+ require_relative "dispatcher/instance_exec"
6
+ require_relative "dispatcher/klass_proxy"
7
+
8
+ module StimulusPlumbers
9
+ module Plumber
10
+ module Dispatcher
11
+ def self.build(callable, *args, method_name: nil, init_args: [], init_kwargs: {}, **kwargs)
12
+ case callable
13
+ when Symbol
14
+ MethodCall.new(callable, *args, **kwargs)
15
+ when Proc
16
+ InstanceExec.new(callable, *args, **kwargs)
17
+ when Module
18
+ KlassProxy.new(callable, method_name, *args, init_args: init_args, init_kwargs: init_kwargs, **kwargs)
19
+ when String
20
+ klass = callable.safe_constantize
21
+ raise ArgumentError, "could not resolve class from: #{callable.inspect}" unless klass
22
+
23
+ KlassProxy.new(klass, method_name, *args, init_args: init_args, init_kwargs: init_kwargs, **kwargs)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module StimulusPlumbers
6
+ module Plumber
7
+ module HtmlOptions
8
+ extend ActiveSupport::Concern
9
+
10
+ def merge_html_options(*hashes)
11
+ class_value = merge_string_option(*extract_classes(*hashes)).presence
12
+ merged_data = merge_data_options(*hashes.map { |h| h[:data] || {} })
13
+ rest = hashes.map { |h| h.except(:class, :classes, :data) }.reduce({}, :deep_merge)
14
+
15
+ result = class_value ? rest.merge(class: class_value) : rest
16
+ merged_data.present? ? result.merge(data: merged_data) : result
17
+ end
18
+
19
+ def extract_classes(*hashes)
20
+ hashes.flat_map { |h| [h[:class], h[:classes]] }
21
+ end
22
+
23
+ STIMULUS_SPACEJOIN_KEYS = %i[controller action].freeze
24
+
25
+ def merge_data_options(*hashes, spacejoin: STIMULUS_SPACEJOIN_KEYS)
26
+ hashes.reduce({}) do |acc, d|
27
+ acc.merge(d) do |key, old_val, new_val|
28
+ if spacejoin.include?(key.to_sym)
29
+ merge_string_option(old_val, new_val).presence || new_val
30
+ else
31
+ new_val
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def merge_string_option(*parts, delimiter: " ")
38
+ tokens = parts.flat_map { |part| normalize_part(part, delimiter) }
39
+ tokens.compact.uniq.join(delimiter)
40
+ end
41
+
42
+ def normalize_part(value, delimiter)
43
+ case value
44
+ when String then value.present? ? value.split(delimiter) : []
45
+ when Hash then value.filter_map { |key, val| key if val }
46
+ when Array then [merge_string_option(*value).presence]
47
+ else []
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module StimulusPlumbers
6
+ module Plumber
7
+ module Renderer
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ class_attribute :renderers, instance_writer: false, default: {}
12
+ end
13
+
14
+ module ClassMethods
15
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
16
+ def renders(method_name, with: nil, &block)
17
+ raise ArgumentError, "method_name must be Symbol" unless method_name.is_a?(Symbol)
18
+ raise ArgumentError, "provide either with: or a block" if !with.nil? && block_given?
19
+
20
+ with = block if block_given?
21
+
22
+ with_proc_or_symbol = with.is_a?(Proc) || with.is_a?(Symbol)
23
+ with_klazz = with.is_a?(Module) || with.is_a?(String)
24
+ raise ArgumentError, "with: must be a Symbol/Proc/Class" unless with_proc_or_symbol || with_klazz
25
+
26
+ self.renderers = renderers.merge(method_name => with)
27
+ ActiveSupport.version >= "7.2" ? generate_renderer_method(method_name) : eval_renderer_method(method_name)
28
+ end
29
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
30
+
31
+ private
32
+
33
+ def generated_renderer_methods
34
+ @generated_renderer_methods ||= Module.new.tap { |mod| prepend mod }
35
+ end
36
+
37
+ def eval_renderer_method(method_name)
38
+ generated_renderer_methods.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
39
+ # def method_name(*args, **kwargs)
40
+ # renderer = renderers.fetch(:method_name, {})
41
+ #
42
+ # unless renderer.present?
43
+ # raise ArgumentError, "#method_name not found in renderer" unless defined?(super)
44
+ # super
45
+ # end
46
+ #
47
+ # dispatcher = StimulusPlumbers::Plumber::Dispatcher.build(
48
+ # renderer, *args, method_name: :#{method_name}, init_args: [template], **kwargs
49
+ # )
50
+ # raise ArgumentError, "invalid renderer, got: \#{renderer.inspect}" unless dispatcher
51
+ #
52
+ # dispatcher.call(self)
53
+ # end
54
+ #{renderer_method_template(method_name)}
55
+ RUBY
56
+ end
57
+
58
+ def generate_renderer_method(method_name)
59
+ require "active_support/code_generator"
60
+ ActiveSupport::CodeGenerator.batch(generated_renderer_methods, __FILE__, __LINE__) do |owner|
61
+ owner.define_cached_method(method_name, namespace: :plumber_renderers) do |batch|
62
+ batch << renderer_method_template(method_name)
63
+ end
64
+ end
65
+ end
66
+
67
+ def renderer_method_template(method_name)
68
+ <<-RUBY
69
+ def #{method_name}(*args, **kwargs)
70
+ renderer = renderers.fetch(:#{method_name}, {})
71
+
72
+ unless renderer.present?
73
+ raise ArgumentError, "##{method_name} not found in renderer" unless defined?(super)
74
+ super
75
+ end
76
+
77
+ dispatcher = StimulusPlumbers::Plumber::Dispatcher.build(
78
+ renderer, *args, method_name: :#{method_name}, init_args: [template], **kwargs
79
+ )
80
+ raise ArgumentError, "invalid renderer, got: \#{renderer.inspect}" unless dispatcher
81
+
82
+ dispatcher.call(self)
83
+ end
84
+ RUBY
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -1,31 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "schema/ranges"
4
- require_relative "base/action_list"
5
- require_relative "base/avatar"
6
- require_relative "base/button"
7
- require_relative "base/calendar"
8
- require_relative "base/card"
9
- require_relative "base/form"
10
- require_relative "base/layout"
3
+ require_relative "schema"
11
4
 
12
5
  module StimulusPlumbers
13
6
  module Themes
14
7
  class Base
15
8
  SCHEMA = {
16
- **ActionList::SCHEMA,
17
- **Avatar::SCHEMA,
18
- **Button::SCHEMA,
19
- **Calendar::SCHEMA,
20
- **Card::SCHEMA,
21
- **Form::SCHEMA,
22
- **Layout::SCHEMA
9
+ **Schema::ACTION_LIST,
10
+ **Schema::AVATAR,
11
+ **Schema::BUTTON,
12
+ **Schema::CALENDAR,
13
+ **Schema::CARD,
14
+ **Schema::COMBOBOX,
15
+ **Schema::FORM,
16
+ **Schema::LAYOUT
23
17
  }.freeze
24
18
 
25
19
  def name
26
20
  @name ||= self.class.name.demodulize.delete_suffix("Theme")
27
21
  end
28
22
 
23
+ def avatar_colors
24
+ {}
25
+ end
26
+
27
+ def avatar_color_range
28
+ []
29
+ end
30
+
31
+ def icons
32
+ {}
33
+ end
34
+
35
+ def icon_range
36
+ icons.keys
37
+ end
38
+
29
39
  def attribute_names(component)
30
40
  SCHEMA.fetch(component, {}).keys
31
41
  end
@@ -55,11 +65,7 @@ module StimulusPlumbers
55
65
  def coerce_arg(component, key, value, schema)
56
66
  return value unless schema
57
67
 
58
- range = if schema[:range].is_a?(Symbol)
59
- respond_to?(schema[:range], true) ? send(schema[:range]) : []
60
- else
61
- schema[:range]
62
- end
68
+ range = range_for(schema)
63
69
  return value if range.empty? || range.include?(value)
64
70
 
65
71
  StimulusPlumbers::Logger.warn(
@@ -68,6 +74,14 @@ module StimulusPlumbers
68
74
  )
69
75
  schema[:default]
70
76
  end
77
+
78
+ def range_for(schema)
79
+ if schema[:range].is_a?(Symbol)
80
+ respond_to?(schema[:range], true) ? send(schema[:range]) : []
81
+ else
82
+ schema[:range]
83
+ end
84
+ end
71
85
  end
72
86
  end
73
87
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ class Configuration
6
+ def register(name, klass)
7
+ raise ArgumentError, "#{klass} must be a subclass of Themes::Base" unless klass <= Base
8
+
9
+ registry[name.to_sym] = klass
10
+ self
11
+ end
12
+
13
+ def use(name_or_instance)
14
+ @current = resolve(name_or_instance)
15
+ self
16
+ end
17
+
18
+ def current
19
+ @current ||= Base.new
20
+ end
21
+
22
+ def registry
23
+ @registry ||= {}
24
+ end
25
+
26
+ private
27
+
28
+ def resolve(value)
29
+ return value if value.is_a?(Base)
30
+
31
+ klass = registry[value.to_sym]
32
+ raise ArgumentError, "Unknown theme #{value.inspect}. Registered: #{registry.keys.inspect}" unless klass
33
+
34
+ klass.new
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Schema
6
+ module Form
7
+ module Ranges
8
+ LAYOUT = %i[stacked inline].freeze
9
+ SUBMIT_VARIANT = %i[default button].freeze
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Schema
6
+ module Icon
7
+ DEFAULTS = {
8
+ fill: "none",
9
+ view_box: "0 0 24 24",
10
+ width: "24",
11
+ height: "24",
12
+ stroke: "currentColor",
13
+ stroke_width: 1.5,
14
+ stroke_linecap: :round,
15
+ stroke_linejoin: :round
16
+ }.freeze
17
+
18
+ ATTRS = ([:d] + DEFAULTS.keys).freeze
19
+
20
+ def self.resolve(icon_data)
21
+ return unless icon_data.is_a?(Hash)
22
+
23
+ merged = DEFAULTS.merge(icon_data.slice(*ATTRS)).transform_values(&:to_s)
24
+ return merged if merged[:d].present?
25
+
26
+ StimulusPlumbers::Logger.warn("Icon missing required :d attribute")
27
+ nil
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -4,11 +4,11 @@ module StimulusPlumbers
4
4
  module Themes
5
5
  module Schema
6
6
  module Ranges
7
- BOOL_RANGE = [true, false].freeze
8
- SIZE_RANGE = %i[sm md lg].freeze
9
- ALIGN_RANGE = %i[left center right top bottom].freeze
10
- DIR_RANGE = %i[row col].freeze
11
- LAYOUT_RANGE = %i[stacked inline].freeze
7
+ BOOL = [true, false].freeze
8
+ SIZE = %i[sm md lg].freeze
9
+ FLEX_ALIGN = %i[left center right top bottom].freeze
10
+ FLEX_DIRECTION = %i[row col].freeze
11
+ BUTTON_VARIANT = %i[primary secondary outline destructive ghost link].freeze
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "schema/ranges"
4
+ require_relative "schema/form/ranges"
5
+ require_relative "schema/icon"
6
+
7
+ module StimulusPlumbers
8
+ module Themes
9
+ module Schema
10
+ ACTION_LIST = {
11
+ action_list_item: {
12
+ active: { default: false, range: Ranges::BOOL }
13
+ }.freeze,
14
+ action_list: {}.freeze
15
+ }.freeze
16
+
17
+ AVATAR = {
18
+ avatar: {
19
+ size: { default: :md, range: Ranges::SIZE },
20
+ color: { default: nil, range: :avatar_color_range }
21
+ }.freeze
22
+ }.freeze
23
+
24
+ BUTTON = {
25
+ button: {
26
+ variant: { default: :primary, range: Ranges::BUTTON_VARIANT },
27
+ size: { default: :md, range: Ranges::SIZE }
28
+ }.freeze,
29
+ button_group: {
30
+ alignment: { default: :left, range: Ranges::FLEX_ALIGN },
31
+ direction: { default: :row, range: Ranges::FLEX_DIRECTION }
32
+ }.freeze
33
+ }.freeze
34
+
35
+ CALENDAR = {
36
+ calendar: {}.freeze,
37
+ calendar_days_of_week: {}.freeze,
38
+ calendar_week: {}.freeze,
39
+ calendar_days_of_month: {}.freeze,
40
+ calendar_day: {
41
+ today: { default: false, range: Ranges::BOOL },
42
+ selected: { default: false, range: Ranges::BOOL },
43
+ outside: { default: false, range: Ranges::BOOL }
44
+ }.freeze,
45
+ calendar_navigation: {}.freeze,
46
+ calendar_navigation_navigator: {}.freeze,
47
+ calendar_navigation_navigator_icon: {
48
+ name: { default: "arrow-left", range: :icon_range }
49
+ }.freeze
50
+ }.freeze
51
+
52
+ CARD = {
53
+ card: {}.freeze,
54
+ card_section: {}.freeze
55
+ }.freeze
56
+
57
+ COMBOBOX = {
58
+ combobox_trigger: {}.freeze,
59
+ combobox_option: {
60
+ selected: { default: false, range: Ranges::BOOL },
61
+ disabled: { default: false, range: Ranges::BOOL }
62
+ }.freeze,
63
+ combobox_option_group: {}.freeze,
64
+ combobox_listbox: {}.freeze,
65
+ combobox_autocomplete_loading: {}.freeze,
66
+ combobox_autocomplete_empty: {}.freeze,
67
+ combobox_time: {}.freeze
68
+ }.freeze
69
+
70
+ FORM = {
71
+ form_group: {
72
+ layout: { default: :stacked, range: Form::Ranges::LAYOUT },
73
+ error: { default: false, range: Ranges::BOOL }
74
+ }.freeze,
75
+ form_label: {
76
+ required: { default: false, range: Ranges::BOOL },
77
+ hidden: { default: false, range: Ranges::BOOL }
78
+ }.freeze,
79
+ form_required_mark: {}.freeze,
80
+ form_details: {}.freeze,
81
+ form_error: {}.freeze,
82
+ form_input: { error: { default: false, range: Ranges::BOOL } }.freeze,
83
+ form_textarea: { error: { default: false, range: Ranges::BOOL } }.freeze,
84
+ form_file: { error: { default: false, range: Ranges::BOOL } }.freeze,
85
+ form_select: { error: { default: false, range: Ranges::BOOL } }.freeze,
86
+ form_checkbox: { error: { default: false, range: Ranges::BOOL } }.freeze,
87
+ form_radio: { error: { default: false, range: Ranges::BOOL } }.freeze,
88
+ form_input_group: { error: { default: false, range: Ranges::BOOL } }.freeze,
89
+ form_combobox: { error: { default: false, range: Ranges::BOOL } }.freeze,
90
+ form_input_reveal: {}.freeze,
91
+ form_button_reveal: {}.freeze,
92
+ form_submit: {
93
+ variant: { default: :default, range: Form::Ranges::SUBMIT_VARIANT }
94
+ }.freeze
95
+ }.freeze
96
+
97
+ LAYOUT = {
98
+ divider: {}.freeze,
99
+ popover: {}.freeze
100
+ }.freeze
101
+ end
102
+ end
103
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StimulusPlumbers
4
- VERSION = "0.2.8"
4
+ VERSION = "0.3.0"
5
5
  end