proscenium 0.19.0.beta10-arm64-darwin → 0.19.0.beta11-arm64-darwin
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.
- checksums.yaml +4 -4
- data/lib/proscenium/bundled_gems.rb +1 -1
- data/lib/proscenium/css_module.rb +0 -5
- data/lib/proscenium/ext/proscenium +0 -0
- data/lib/proscenium/middleware.rb +0 -6
- data/lib/proscenium/phlex.rb +0 -6
- data/lib/proscenium/railtie.rb +0 -25
- data/lib/proscenium/resolver.rb +0 -9
- data/lib/proscenium/version.rb +1 -1
- data/lib/proscenium/view_component.rb +0 -6
- data/lib/proscenium.rb +5 -34
- metadata +24 -132
- data/lib/proscenium/registry/bundled_package.rb +0 -29
- data/lib/proscenium/registry/package.rb +0 -95
- data/lib/proscenium/registry/ruby_gem_package.rb +0 -30
- data/lib/proscenium/registry.rb +0 -29
- data/lib/proscenium/ruby_gems.rb +0 -67
- data/lib/proscenium/ui/breadcrumbs/component.module.css +0 -14
- data/lib/proscenium/ui/breadcrumbs/component.rb +0 -71
- data/lib/proscenium/ui/breadcrumbs/computed_element.rb +0 -69
- data/lib/proscenium/ui/breadcrumbs/control.rb +0 -95
- data/lib/proscenium/ui/breadcrumbs/mixins.css +0 -83
- data/lib/proscenium/ui/breadcrumbs.rb +0 -72
- data/lib/proscenium/ui/component.rb +0 -7
- data/lib/proscenium/ui/custom_element.js +0 -54
- data/lib/proscenium/ui/flash/bun.lock +0 -19
- data/lib/proscenium/ui/flash/index.css +0 -1
- data/lib/proscenium/ui/flash/index.js +0 -77
- data/lib/proscenium/ui/flash/node_modules/dom-mutations/index.d.ts +0 -33
- data/lib/proscenium/ui/flash/node_modules/dom-mutations/index.js +0 -44
- data/lib/proscenium/ui/flash/node_modules/dom-mutations/license +0 -9
- data/lib/proscenium/ui/flash/node_modules/dom-mutations/package.json +0 -59
- data/lib/proscenium/ui/flash/node_modules/dom-mutations/readme.md +0 -125
- data/lib/proscenium/ui/flash/node_modules/sourdough-toast/LICENSE +0 -20
- data/lib/proscenium/ui/flash/node_modules/sourdough-toast/README.md +0 -11
- data/lib/proscenium/ui/flash/node_modules/sourdough-toast/package.json +0 -44
- data/lib/proscenium/ui/flash/node_modules/sourdough-toast/src/sourdough-toast.css +0 -697
- data/lib/proscenium/ui/flash/node_modules/sourdough-toast/src/sourdough-toast.js +0 -537
- data/lib/proscenium/ui/flash/package.json +0 -11
- data/lib/proscenium/ui/flash.rb +0 -15
- data/lib/proscenium/ui/form/field_methods.rb +0 -88
- data/lib/proscenium/ui/form/fields/base.rb +0 -188
- data/lib/proscenium/ui/form/fields/checkbox/index.jsx +0 -48
- data/lib/proscenium/ui/form/fields/checkbox/index.module.css +0 -9
- data/lib/proscenium/ui/form/fields/checkbox/previews/basic.jsx +0 -8
- data/lib/proscenium/ui/form/fields/checkbox.rb +0 -32
- data/lib/proscenium/ui/form/fields/date.module.css +0 -27
- data/lib/proscenium/ui/form/fields/datetime.rb +0 -15
- data/lib/proscenium/ui/form/fields/hidden.rb +0 -9
- data/lib/proscenium/ui/form/fields/input/index.jsx +0 -71
- data/lib/proscenium/ui/form/fields/input/index.module.css +0 -13
- data/lib/proscenium/ui/form/fields/input/previews/basic.jsx +0 -8
- data/lib/proscenium/ui/form/fields/input.rb +0 -14
- data/lib/proscenium/ui/form/fields/radio_group.rb +0 -173
- data/lib/proscenium/ui/form/fields/radio_input/index.jsx +0 -44
- data/lib/proscenium/ui/form/fields/radio_input/index.module.css +0 -13
- data/lib/proscenium/ui/form/fields/radio_input/previews/basic.jsx +0 -8
- data/lib/proscenium/ui/form/fields/radio_input.rb +0 -17
- data/lib/proscenium/ui/form/fields/rich_textarea.css +0 -23
- data/lib/proscenium/ui/form/fields/rich_textarea.js +0 -6
- data/lib/proscenium/ui/form/fields/rich_textarea.rb +0 -18
- data/lib/proscenium/ui/form/fields/select.jsx +0 -47
- data/lib/proscenium/ui/form/fields/select.module.css +0 -46
- data/lib/proscenium/ui/form/fields/select.rb +0 -300
- data/lib/proscenium/ui/form/fields/tel.css +0 -297
- data/lib/proscenium/ui/form/fields/tel.js +0 -83
- data/lib/proscenium/ui/form/fields/tel.rb +0 -54
- data/lib/proscenium/ui/form/fields/textarea/index.jsx +0 -50
- data/lib/proscenium/ui/form/fields/textarea/index.module.css +0 -13
- data/lib/proscenium/ui/form/fields/textarea/previews/basic.jsx +0 -8
- data/lib/proscenium/ui/form/fields/textarea.rb +0 -18
- data/lib/proscenium/ui/form/translation.rb +0 -71
- data/lib/proscenium/ui/form.css +0 -52
- data/lib/proscenium/ui/form.rb +0 -211
- data/lib/proscenium/ui/props.css +0 -7
- data/lib/proscenium/ui/stimulus-loading.js +0 -65
- data/lib/proscenium/ui/test.js +0 -1
- data/lib/proscenium/ui/ujs/class.js +0 -15
- data/lib/proscenium/ui/ujs/data_confirm.js +0 -23
- data/lib/proscenium/ui/ujs/data_disable_with.js +0 -68
- data/lib/proscenium/ui/ujs/index.js +0 -9
- data/lib/proscenium/ui.rb +0 -11
- /data/lib/proscenium/{ui/react-manager → react-manager}/index.jsx +0 -0
- /data/lib/proscenium/{ui/react-manager → react-manager}/react.js +0 -0
| @@ -1,188 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require 'securerandom'
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            module Proscenium::UI
         | 
| 6 | 
            -
              module Form::Fields
         | 
| 7 | 
            -
                #
         | 
| 8 | 
            -
                # Abstract class to provide basic rendering of an <input>. All field classes inherit this.
         | 
| 9 | 
            -
                #
         | 
| 10 | 
            -
                class Base < Component
         | 
| 11 | 
            -
                  attr_reader :attribute, :model, :form, :attributes
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                  register_element :pui_field
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                  # In most cases we want to use the main form component stylesheet. Override this method if
         | 
| 16 | 
            -
                  # you want to use a different stylesheet.
         | 
| 17 | 
            -
                  # def self.css_module_path
         | 
| 18 | 
            -
                  #   source_path.join('../index.module.css')
         | 
| 19 | 
            -
                  # end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                  # @param attribute [Array]
         | 
| 22 | 
            -
                  # @param model [*]
         | 
| 23 | 
            -
                  # @param form [Proscenium::UI::Form]
         | 
| 24 | 
            -
                  # @param type [Symbol] input type, eg. 'text', 'select'
         | 
| 25 | 
            -
                  # @param error [ActiveModel::Error, String] error message for the attribute.
         | 
| 26 | 
            -
                  # @param attributes [Hash] HTML attributes to pass to the input.
         | 
| 27 | 
            -
                  def initialize(attribute, model, form, type: nil, error: nil, **attributes) # rubocop:disable Lint/MissingSuper,Metrics/ParameterLists
         | 
| 28 | 
            -
                    if attribute.count > 2
         | 
| 29 | 
            -
                      raise ArgumentError, 'attribute cannot be nested more than 2 levels deep'
         | 
| 30 | 
            -
                    end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                    @attribute = attribute
         | 
| 33 | 
            -
                    @model = model
         | 
| 34 | 
            -
                    @form = form
         | 
| 35 | 
            -
                    @field_type = type
         | 
| 36 | 
            -
                    @error = error
         | 
| 37 | 
            -
                    @attributes = attributes
         | 
| 38 | 
            -
                  end
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                  private
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                  # @return [String] The error message for the attribute.
         | 
| 43 | 
            -
                  def error_message
         | 
| 44 | 
            -
                    @error_message ||= case @error
         | 
| 45 | 
            -
                                       when ActiveModel::Error
         | 
| 46 | 
            -
                                         @error.message
         | 
| 47 | 
            -
                                       when String
         | 
| 48 | 
            -
                                         @error
         | 
| 49 | 
            -
                                       else
         | 
| 50 | 
            -
                                         if model.errors.include?(attribute.join('.'))
         | 
| 51 | 
            -
                                           model.errors.where(attribute.join('.')).first&.message
         | 
| 52 | 
            -
                                         elsif model.errors.include?(attribute.first)
         | 
| 53 | 
            -
                                           model.errors.where(attribute.first).first&.message
         | 
| 54 | 
            -
                                         end
         | 
| 55 | 
            -
                                       end
         | 
| 56 | 
            -
                  end
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                  def error?
         | 
| 59 | 
            -
                    error_message.present?
         | 
| 60 | 
            -
                  end
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                  # The main wrapper for the field. This is where the label, input, and error message are
         | 
| 63 | 
            -
                  # rendered.
         | 
| 64 | 
            -
                  #
         | 
| 65 | 
            -
                  # @param tag_name: [Symbol] HTML tag name to use for the wrapper.
         | 
| 66 | 
            -
                  # @param ** [Hash] Additional HTML attributes to pass to the wrapper.
         | 
| 67 | 
            -
                  # @param [Proc] The block to render the field.
         | 
| 68 | 
            -
                  def field(tag_name = :pui_field, **rest, &)
         | 
| 69 | 
            -
                    classes = []
         | 
| 70 | 
            -
                    classes << rest.delete(:class) if rest.key?(:class)
         | 
| 71 | 
            -
                    classes << attributes.delete(:class) if attributes.key?(:class)
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                    send(tag_name, class: classes, data: { field_error: error? }, **rest, &)
         | 
| 74 | 
            -
                  end
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                  # Builds the template for the label, along with any error message for the attribute.
         | 
| 77 | 
            -
                  #
         | 
| 78 | 
            -
                  # By default, the translated attribute name will be used as the content for the label. You can
         | 
| 79 | 
            -
                  # overide this by providing the `:label` keyword argument in `@arguments`. Passing false as
         | 
| 80 | 
            -
                  # the value to `:label` will omit the label.
         | 
| 81 | 
            -
                  #
         | 
| 82 | 
            -
                  # If a block is given, it will be yielded with the label content, and after the label and
         | 
| 83 | 
            -
                  # error message.
         | 
| 84 | 
            -
                  def label(**kwargs, &block)
         | 
| 85 | 
            -
                    content = attributes.delete(:label)
         | 
| 86 | 
            -
             | 
| 87 | 
            -
                    super do
         | 
| 88 | 
            -
                      captured = capture do
         | 
| 89 | 
            -
                        div do
         | 
| 90 | 
            -
                          span { content || translate_label } if content != false
         | 
| 91 | 
            -
                          error? && span(part: :error) { error_message }
         | 
| 92 | 
            -
                        end
         | 
| 93 | 
            -
                      end
         | 
| 94 | 
            -
             | 
| 95 | 
            -
                      if !block
         | 
| 96 | 
            -
                        yield_content_with_no_args { captured }
         | 
| 97 | 
            -
                      elsif block.arity == 1
         | 
| 98 | 
            -
                        yield captured
         | 
| 99 | 
            -
                      else
         | 
| 100 | 
            -
                        yield_content_with_no_args { captured }
         | 
| 101 | 
            -
                        yield
         | 
| 102 | 
            -
                      end
         | 
| 103 | 
            -
                    end
         | 
| 104 | 
            -
                  end
         | 
| 105 | 
            -
             | 
| 106 | 
            -
                  def hint(content = nil)
         | 
| 107 | 
            -
                    content ||= attributes.delete(:hint)
         | 
| 108 | 
            -
             | 
| 109 | 
            -
                    return if content == false
         | 
| 110 | 
            -
             | 
| 111 | 
            -
                    content ||= translate(:hints)
         | 
| 112 | 
            -
                    content.present? && div(part: :hint) { unsafe_raw content }
         | 
| 113 | 
            -
                  end
         | 
| 114 | 
            -
             | 
| 115 | 
            -
                  def field_type
         | 
| 116 | 
            -
                    @field_type ||= self.class.name.demodulize.underscore
         | 
| 117 | 
            -
                  end
         | 
| 118 | 
            -
             | 
| 119 | 
            -
                  def field_name(*names, multiple: false)
         | 
| 120 | 
            -
                    names.prepend attribute.last
         | 
| 121 | 
            -
             | 
| 122 | 
            -
                    if nested?
         | 
| 123 | 
            -
                      if nested_attributes_association?
         | 
| 124 | 
            -
                        names.prepend "#{attribute.first}_attributes"
         | 
| 125 | 
            -
                      else
         | 
| 126 | 
            -
                        names.prepend attribute.first
         | 
| 127 | 
            -
                      end
         | 
| 128 | 
            -
                    elsif names.count == 1 && names.first.is_a?(String)
         | 
| 129 | 
            -
                      return names.first
         | 
| 130 | 
            -
                    end
         | 
| 131 | 
            -
             | 
| 132 | 
            -
                    form.field_name(*names, multiple:)
         | 
| 133 | 
            -
                  end
         | 
| 134 | 
            -
             | 
| 135 | 
            -
                  def field_id(*)
         | 
| 136 | 
            -
                    @field_uid ||= SecureRandom.alphanumeric(10)
         | 
| 137 | 
            -
                    form.field_id(*attribute, @field_uid, *)
         | 
| 138 | 
            -
                  end
         | 
| 139 | 
            -
             | 
| 140 | 
            -
                  def translate(namespace, postfix: nil, default: '')
         | 
| 141 | 
            -
                    form.translate namespace, attribute, postfix:, default:
         | 
| 142 | 
            -
                  end
         | 
| 143 | 
            -
             | 
| 144 | 
            -
                  def translate_label(default: nil)
         | 
| 145 | 
            -
                    form.translate_label attribute, default:
         | 
| 146 | 
            -
                  end
         | 
| 147 | 
            -
             | 
| 148 | 
            -
                  def build_attributes(**attrs)
         | 
| 149 | 
            -
                    attributes.merge(attrs).tap do |x|
         | 
| 150 | 
            -
                      x[:value] ||= value.to_s
         | 
| 151 | 
            -
                    end
         | 
| 152 | 
            -
                  end
         | 
| 153 | 
            -
             | 
| 154 | 
            -
                  def value
         | 
| 155 | 
            -
                    attr = attribute.last
         | 
| 156 | 
            -
                    if actual_model.respond_to?(attr)
         | 
| 157 | 
            -
                      actual_model.public_send(attribute.last)
         | 
| 158 | 
            -
                    else
         | 
| 159 | 
            -
                      ''
         | 
| 160 | 
            -
                    end
         | 
| 161 | 
            -
                  end
         | 
| 162 | 
            -
             | 
| 163 | 
            -
                  # @return [Boolean] true if the attribute is nested, otherwise false.
         | 
| 164 | 
            -
                  def nested?
         | 
| 165 | 
            -
                    attribute.count > 1
         | 
| 166 | 
            -
                  end
         | 
| 167 | 
            -
             | 
| 168 | 
            -
                  def nested_attributes_association?
         | 
| 169 | 
            -
                    parent_model.respond_to?(:"#{attribute.first}_attributes=")
         | 
| 170 | 
            -
                  end
         | 
| 171 | 
            -
             | 
| 172 | 
            -
                  # @return the nested model if nested, otherwise nil.
         | 
| 173 | 
            -
                  def nested_model
         | 
| 174 | 
            -
                    @nested_model ||= nested? ? model.public_send(attribute.first) : nil
         | 
| 175 | 
            -
                  end
         | 
| 176 | 
            -
             | 
| 177 | 
            -
                  def actual_model
         | 
| 178 | 
            -
                    @actual_model ||= nested_model || model
         | 
| 179 | 
            -
                  end
         | 
| 180 | 
            -
             | 
| 181 | 
            -
                  alias parent_model model
         | 
| 182 | 
            -
             | 
| 183 | 
            -
                  def virtual_path
         | 
| 184 | 
            -
                    @virtual_path ||= Proscenium::Resolver.resolve self.class.source_path.sub_ext('.jsx').to_s
         | 
| 185 | 
            -
                  end
         | 
| 186 | 
            -
                end
         | 
| 187 | 
            -
              end
         | 
| 188 | 
            -
            end
         | 
| @@ -1,48 +0,0 @@ | |
| 1 | 
            -
            import clsx from 'clsx'
         | 
| 2 | 
            -
            import PropTypes from 'prop-types'
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            import dsx from '/hue/lib/hue/utils/dsx'
         | 
| 5 | 
            -
            import { useFormError } from '../../hooks'
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            import styles from './index.module.css'
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            const Component = ({ label, hint, className, errorAttrName, ...props }) => {
         | 
| 10 | 
            -
              const [error, hasError] = useFormError(errorAttrName || props.name)
         | 
| 11 | 
            -
             | 
| 12 | 
            -
              return (
         | 
| 13 | 
            -
                <div className={clsx(styles.fieldWrapper, className)} {...dsx({ fieldError: hasError })}>
         | 
| 14 | 
            -
                  <label>
         | 
| 15 | 
            -
                    <input type="hidden" value="0" name={props.name} />
         | 
| 16 | 
            -
                    <input type="checkbox" value="1" {...props} />
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                    <span>
         | 
| 19 | 
            -
                      {label ? <span>{label}</span> : null}
         | 
| 20 | 
            -
                      {hasError ? <span>{error}</span> : null}
         | 
| 21 | 
            -
                    </span>
         | 
| 22 | 
            -
                  </label>
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                  {hint ? <div className={styles.hint}>{hint}</div> : null}
         | 
| 25 | 
            -
                </div>
         | 
| 26 | 
            -
              )
         | 
| 27 | 
            -
            }
         | 
| 28 | 
            -
             | 
| 29 | 
            -
            Component.displayName = 'Hue.Form.Fields.Checkbox'
         | 
| 30 | 
            -
            Component.propTypes = {
         | 
| 31 | 
            -
              name: PropTypes.string.isRequired,
         | 
| 32 | 
            -
             | 
| 33 | 
            -
              label: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.element]),
         | 
| 34 | 
            -
             | 
| 35 | 
            -
              // Custom class name. This will be appended to the default class.
         | 
| 36 | 
            -
              className: PropTypes.string,
         | 
| 37 | 
            -
             | 
| 38 | 
            -
              // The name of the attribute to use for the error message. Default: 'props.name'.
         | 
| 39 | 
            -
              errorAttrName: PropTypes.string,
         | 
| 40 | 
            -
             | 
| 41 | 
            -
              id: PropTypes.string,
         | 
| 42 | 
            -
              hint: PropTypes.string,
         | 
| 43 | 
            -
              disabled: PropTypes.bool
         | 
| 44 | 
            -
             | 
| 45 | 
            -
              // All remaining non-descript props will be forwarded to the <input> element.
         | 
| 46 | 
            -
            }
         | 
| 47 | 
            -
             | 
| 48 | 
            -
            export default Component
         | 
| @@ -1,32 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module Proscenium::UI::Form::Fields
         | 
| 4 | 
            -
              # Renders a checkbox field similar to how Rails handles it.
         | 
| 5 | 
            -
              #
         | 
| 6 | 
            -
              # A predicate attribute name can be given:
         | 
| 7 | 
            -
              #
         | 
| 8 | 
            -
              #   checkbox_field :active?
         | 
| 9 | 
            -
              #
         | 
| 10 | 
            -
              class Checkbox < Base
         | 
| 11 | 
            -
                register_element :pui_checkbox
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                def view_template
         | 
| 14 | 
            -
                  checked = ActiveModel::Type::Boolean.new.cast(value.nil? ? false : value)
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                  checked_value = attributes.delete(:checked_value) || '1'
         | 
| 17 | 
            -
                  unchecked_value = attributes.delete(:unchecked_value) || '0'
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                  # TODO: use component
         | 
| 20 | 
            -
                  # render Proscenium::UI::Fields::Checkbox::Component.new field_name, checked:
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                  field :pui_checkbox do
         | 
| 23 | 
            -
                    label do |content|
         | 
| 24 | 
            -
                      input(name: field_name, type: :hidden, value: unchecked_value, **attributes)
         | 
| 25 | 
            -
                      input(name: field_name, type: :checkbox, value: checked_value, checked:, **attributes)
         | 
| 26 | 
            -
                      yield_content_with_no_args { content }
         | 
| 27 | 
            -
                    end
         | 
| 28 | 
            -
                    hint
         | 
| 29 | 
            -
                  end
         | 
| 30 | 
            -
                end
         | 
| 31 | 
            -
              end
         | 
| 32 | 
            -
            end
         | 
| @@ -1,27 +0,0 @@ | |
| 1 | 
            -
            @layer hue-component {
         | 
| 2 | 
            -
              .field_wrapper {
         | 
| 3 | 
            -
                @mixin fieldWrapper from url('/hue/lib/hue/mixins/form.mixin.css');
         | 
| 4 | 
            -
              }
         | 
| 5 | 
            -
             | 
| 6 | 
            -
              .inputs {
         | 
| 7 | 
            -
                display: flex;
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                & div {
         | 
| 10 | 
            -
                  padding-right: 10px;
         | 
| 11 | 
            -
                }
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                & label > span {
         | 
| 14 | 
            -
                  color: var(--gray6);
         | 
| 15 | 
            -
                  font-size: var(--12px);
         | 
| 16 | 
            -
                  margin: 0 0 0.2em 0.2em;
         | 
| 17 | 
            -
                }
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                > div {
         | 
| 20 | 
            -
                  width: 7em;
         | 
| 21 | 
            -
                }
         | 
| 22 | 
            -
              }
         | 
| 23 | 
            -
             | 
| 24 | 
            -
              .hint {
         | 
| 25 | 
            -
                @mixin fieldHint from url('/hue/lib/hue/mixins/field.mixin.css');
         | 
| 26 | 
            -
              }
         | 
| 27 | 
            -
            }
         | 
| @@ -1,71 +0,0 @@ | |
| 1 | 
            -
            import clsx from 'clsx'
         | 
| 2 | 
            -
            import PropTypes from 'prop-types'
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            import dsx from '/hue/lib/hue/utils/dsx'
         | 
| 5 | 
            -
            import { useFormError } from '../../hooks'
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            import styles from './index.module.css'
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            const Input = ({
         | 
| 10 | 
            -
              label,
         | 
| 11 | 
            -
              hint,
         | 
| 12 | 
            -
              className,
         | 
| 13 | 
            -
              inputClassName,
         | 
| 14 | 
            -
              errorAttrName,
         | 
| 15 | 
            -
              inputRef,
         | 
| 16 | 
            -
              children,
         | 
| 17 | 
            -
              ...props
         | 
| 18 | 
            -
            }) => {
         | 
| 19 | 
            -
              const [error, hasError] = useFormError(errorAttrName || props.name)
         | 
| 20 | 
            -
             | 
| 21 | 
            -
              return (
         | 
| 22 | 
            -
                <div className={clsx(styles.fieldWrapper, className)} {...dsx({ fieldError: hasError })}>
         | 
| 23 | 
            -
                  <label>
         | 
| 24 | 
            -
                    <span>
         | 
| 25 | 
            -
                      {label ? <span>{label}</span> : null}
         | 
| 26 | 
            -
                      {hasError ? <span>{error}</span> : null}
         | 
| 27 | 
            -
                    </span>
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                    {children || <input className={inputClassName || styles.input} {...props} ref={inputRef} />}
         | 
| 30 | 
            -
                  </label>
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                  {hint ? <div className={styles.hint}>{hint}</div> : null}
         | 
| 33 | 
            -
                </div>
         | 
| 34 | 
            -
              )
         | 
| 35 | 
            -
            }
         | 
| 36 | 
            -
            Input.displayName = 'Hue.Form.Fields.Input'
         | 
| 37 | 
            -
            Input.propTypes = {
         | 
| 38 | 
            -
              name: PropTypes.string.isRequired,
         | 
| 39 | 
            -
             | 
| 40 | 
            -
              label: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.element]),
         | 
| 41 | 
            -
             | 
| 42 | 
            -
              // Input `type` attribute. Default: 'text'.
         | 
| 43 | 
            -
              type: PropTypes.string,
         | 
| 44 | 
            -
             | 
| 45 | 
            -
              // Custom class name. This will be appended to the default class.
         | 
| 46 | 
            -
              className: PropTypes.string,
         | 
| 47 | 
            -
             | 
| 48 | 
            -
              // Custom class name for the actual input element. This will replace the default class.
         | 
| 49 | 
            -
              inputClassName: PropTypes.string,
         | 
| 50 | 
            -
             | 
| 51 | 
            -
              // The name of the attribute to use for the error message. Default: 'props.name'.
         | 
| 52 | 
            -
              errorAttrName: PropTypes.string,
         | 
| 53 | 
            -
             | 
| 54 | 
            -
              children: PropTypes.node,
         | 
| 55 | 
            -
             | 
| 56 | 
            -
              inputRef: PropTypes.oneOfType([
         | 
| 57 | 
            -
                PropTypes.func,
         | 
| 58 | 
            -
                PropTypes.shape({ current: PropTypes.instanceOf(Element) })
         | 
| 59 | 
            -
              ]),
         | 
| 60 | 
            -
             | 
| 61 | 
            -
              id: PropTypes.string,
         | 
| 62 | 
            -
              hint: PropTypes.string,
         | 
| 63 | 
            -
              disabled: PropTypes.bool
         | 
| 64 | 
            -
             | 
| 65 | 
            -
              // All remaining non-descript props will be forwarded to the <input> element.
         | 
| 66 | 
            -
            }
         | 
| 67 | 
            -
            Input.defaultProps = {
         | 
| 68 | 
            -
              type: 'text'
         | 
| 69 | 
            -
            }
         | 
| 70 | 
            -
             | 
| 71 | 
            -
            export default Input
         | 
| @@ -1,13 +0,0 @@ | |
| 1 | 
            -
            @layer hue-component {
         | 
| 2 | 
            -
              .fieldWrapper {
         | 
| 3 | 
            -
                @mixin fieldWrapper from url('/hue/lib/hue/mixins/form.mixin.css');
         | 
| 4 | 
            -
              }
         | 
| 5 | 
            -
             | 
| 6 | 
            -
              .input {
         | 
| 7 | 
            -
                @mixin input from url('/hue/lib/hue/mixins/input.mixin.css');
         | 
| 8 | 
            -
              }
         | 
| 9 | 
            -
             | 
| 10 | 
            -
              .hint {
         | 
| 11 | 
            -
                @mixin fieldHint from url('/hue/lib/hue/mixins/field.mixin.css');
         | 
| 12 | 
            -
              }
         | 
| 13 | 
            -
            }
         | 
| @@ -1,173 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module Proscenium::UI::Form::Fields
         | 
| 4 | 
            -
              # Render a group of <radio> inputs for the given model attribute. It supports ActiveRecord
         | 
| 5 | 
            -
              # associations and enums.
         | 
| 6 | 
            -
              #
         | 
| 7 | 
            -
              # ## Supported options
         | 
| 8 | 
            -
              #
         | 
| 9 | 
            -
              # - options [Array] a list of options where each will render a radio input. If this is given, the
         | 
| 10 | 
            -
              #     automatic detection of options will be disabled. A flat array of strings will be used for
         | 
| 11 | 
            -
              #     both the label and value. While an Array of nested two-level arrays will be used.
         | 
| 12 | 
            -
              class RadioGroup < Base
         | 
| 13 | 
            -
                register_element :pui_radio_group
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                def before_template
         | 
| 16 | 
            -
                  @options_from_attributes = attributes.delete(:options)
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                  super
         | 
| 19 | 
            -
                end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                def view_template
         | 
| 22 | 
            -
                  field :pui_radio_group do
         | 
| 23 | 
            -
                    label
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                    div part: :radio_group_inputs do
         | 
| 26 | 
            -
                      options.each do |opt|
         | 
| 27 | 
            -
                        form.radio_input(*attribute, name: field_name, value: opt[:value], label: opt[:label],
         | 
| 28 | 
            -
                                                     checked: opt[:checked], **attributes)
         | 
| 29 | 
            -
                      end
         | 
| 30 | 
            -
                    end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                    hint
         | 
| 33 | 
            -
                  end
         | 
| 34 | 
            -
                end
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                private
         | 
| 37 | 
            -
             | 
| 38 | 
            -
                def field_name(*names, multiple: false)
         | 
| 39 | 
            -
                  names.prepend association_attribute? ? association_attribute : attribute.last
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                  if nested?
         | 
| 42 | 
            -
                    if nested_attributes_association?
         | 
| 43 | 
            -
                      names.prepend "#{attribute.first}_attributes"
         | 
| 44 | 
            -
                    else
         | 
| 45 | 
            -
                      names.prepend attribute.first
         | 
| 46 | 
            -
                    end
         | 
| 47 | 
            -
                  elsif names.count == 1 && names.first.is_a?(String)
         | 
| 48 | 
            -
                    return names.first
         | 
| 49 | 
            -
                  end
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                  form.field_name(*names, multiple:)
         | 
| 52 | 
            -
                end
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                def options
         | 
| 55 | 
            -
                  if @options_from_attributes
         | 
| 56 | 
            -
                    @options_from_attributes.map do |x|
         | 
| 57 | 
            -
                      if x.is_a?(Array)
         | 
| 58 | 
            -
                        { value: x.first, label: x.last, checked: checked?(x.first) }
         | 
| 59 | 
            -
                      else
         | 
| 60 | 
            -
                        { value: x, label: x, checked: checked?(x) }
         | 
| 61 | 
            -
                      end
         | 
| 62 | 
            -
                    end
         | 
| 63 | 
            -
                  elsif enum_attribute?
         | 
| 64 | 
            -
                    fetch_enum_collection.map do |x|
         | 
| 65 | 
            -
                      {
         | 
| 66 | 
            -
                        value: x,
         | 
| 67 | 
            -
                        label: model_class.human_attribute_name("#{attribute.last}.#{x}"),
         | 
| 68 | 
            -
                        checked: checked?(x)
         | 
| 69 | 
            -
                      }
         | 
| 70 | 
            -
                    end
         | 
| 71 | 
            -
                  elsif association_attribute?
         | 
| 72 | 
            -
                    fetch_association_collection.map do |x|
         | 
| 73 | 
            -
                      {
         | 
| 74 | 
            -
                        value: x.id,
         | 
| 75 | 
            -
                        label: x.to_s,
         | 
| 76 | 
            -
                        checked: checked?(x)
         | 
| 77 | 
            -
                      }
         | 
| 78 | 
            -
                    end
         | 
| 79 | 
            -
                  end
         | 
| 80 | 
            -
                end
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                def value
         | 
| 83 | 
            -
                  if actual_model.respond_to?(model_attribute)
         | 
| 84 | 
            -
                    actual_model.public_send(model_attribute)
         | 
| 85 | 
            -
                  else
         | 
| 86 | 
            -
                    ''
         | 
| 87 | 
            -
                  end
         | 
| 88 | 
            -
                end
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                # Is the given `option` the current value (checked)?
         | 
| 91 | 
            -
                def checked?(option)
         | 
| 92 | 
            -
                  if !option.is_a?(String) && !option.is_a?(Integer) && association_attribute?
         | 
| 93 | 
            -
                    reflection = association_reflection
         | 
| 94 | 
            -
                    key = if reflection.respond_to?(:options) && reflection.options[:primary_key]
         | 
| 95 | 
            -
                            reflection.options[:primary_key]
         | 
| 96 | 
            -
                          else
         | 
| 97 | 
            -
                            option.class.primary_key.to_s
         | 
| 98 | 
            -
                          end
         | 
| 99 | 
            -
                    option.attributes[key] == value
         | 
| 100 | 
            -
                  else
         | 
| 101 | 
            -
                    option.to_s == value.to_s
         | 
| 102 | 
            -
                  end
         | 
| 103 | 
            -
                end
         | 
| 104 | 
            -
             | 
| 105 | 
            -
                def model_attribute
         | 
| 106 | 
            -
                  @model_attribute ||= association_attribute? ? association_attribute : attribute.last
         | 
| 107 | 
            -
                end
         | 
| 108 | 
            -
             | 
| 109 | 
            -
                def enum_attribute?
         | 
| 110 | 
            -
                  model_class.defined_enums.key?(attribute.last.to_s)
         | 
| 111 | 
            -
                end
         | 
| 112 | 
            -
             | 
| 113 | 
            -
                def association_attribute?
         | 
| 114 | 
            -
                  association_reflection.present?
         | 
| 115 | 
            -
                end
         | 
| 116 | 
            -
             | 
| 117 | 
            -
                def association_attribute
         | 
| 118 | 
            -
                  @association_attribute ||= begin
         | 
| 119 | 
            -
                    reflection = association_reflection
         | 
| 120 | 
            -
             | 
| 121 | 
            -
                    case reflection.macro
         | 
| 122 | 
            -
                    when :belongs_to
         | 
| 123 | 
            -
                      (reflection.respond_to?(:options) && reflection.options[:foreign_key]&.to_sym) ||
         | 
| 124 | 
            -
                        :"#{reflection.name}_id"
         | 
| 125 | 
            -
                    else
         | 
| 126 | 
            -
                      # Force the association to be preloaded for performance.
         | 
| 127 | 
            -
                      if actual_model.respond_to?(attribute.last)
         | 
| 128 | 
            -
                        target = actual_model.send(attribute.last)
         | 
| 129 | 
            -
                        target.to_a if target.respond_to?(:to_a)
         | 
| 130 | 
            -
                      end
         | 
| 131 | 
            -
             | 
| 132 | 
            -
                      :"#{reflection.name.to_s.singularize}_ids"
         | 
| 133 | 
            -
                    end
         | 
| 134 | 
            -
                  end
         | 
| 135 | 
            -
                end
         | 
| 136 | 
            -
             | 
| 137 | 
            -
                def association_reflection
         | 
| 138 | 
            -
                  @association_reflection ||= model_class.try :reflect_on_association, attribute.last
         | 
| 139 | 
            -
                end
         | 
| 140 | 
            -
             | 
| 141 | 
            -
                def fetch_association_collection
         | 
| 142 | 
            -
                  relation = association_reflection.klass.all
         | 
| 143 | 
            -
             | 
| 144 | 
            -
                  # association_reflection.macro == :has_many
         | 
| 145 | 
            -
             | 
| 146 | 
            -
                  if association_reflection.respond_to?(:scope) && association_reflection.scope
         | 
| 147 | 
            -
                    relation = if association_reflection.scope.parameters.any?
         | 
| 148 | 
            -
                                 association_reflection.klass.instance_exec(actual_model,
         | 
| 149 | 
            -
                                                                            &association_reflection.scope)
         | 
| 150 | 
            -
                               else
         | 
| 151 | 
            -
                                 association_reflection.klass.instance_exec(&association_reflection.scope)
         | 
| 152 | 
            -
                               end
         | 
| 153 | 
            -
                  else
         | 
| 154 | 
            -
                    order = association_reflection.options[:order]
         | 
| 155 | 
            -
                    conditions = association_reflection.options[:conditions]
         | 
| 156 | 
            -
                    conditions = actual_model.instance_exec(&conditions) if conditions.respond_to?(:call)
         | 
| 157 | 
            -
             | 
| 158 | 
            -
                    relation = relation.where(conditions) if relation.respond_to?(:where) && conditions.present?
         | 
| 159 | 
            -
                    relation = relation.order(order) if relation.respond_to?(:order)
         | 
| 160 | 
            -
                  end
         | 
| 161 | 
            -
             | 
| 162 | 
            -
                  relation
         | 
| 163 | 
            -
                end
         | 
| 164 | 
            -
             | 
| 165 | 
            -
                def fetch_enum_collection
         | 
| 166 | 
            -
                  actual_model.defined_enums[attribute.last.to_s].keys
         | 
| 167 | 
            -
                end
         | 
| 168 | 
            -
             | 
| 169 | 
            -
                def model_class
         | 
| 170 | 
            -
                  @model_class ||= actual_model.class
         | 
| 171 | 
            -
                end
         | 
| 172 | 
            -
              end
         | 
| 173 | 
            -
            end
         | 
| @@ -1,44 +0,0 @@ | |
| 1 | 
            -
            import clsx from 'clsx'
         | 
| 2 | 
            -
            import PropTypes from 'prop-types'
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            import dsx from '/hue/lib/hue/utils/dsx'
         | 
| 5 | 
            -
            import { useFormError } from '../../hooks'
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            import styles from './index.module.css'
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            const Component = ({ label, hint, className, errorAttrName, ...props }) => {
         | 
| 10 | 
            -
              const [error, hasError] = useFormError(errorAttrName || props.name)
         | 
| 11 | 
            -
             | 
| 12 | 
            -
              return (
         | 
| 13 | 
            -
                <div className={clsx(styles.fieldWrapper, className)} {...dsx({ fieldError: hasError })}>
         | 
| 14 | 
            -
                  <label>
         | 
| 15 | 
            -
                    <input type="radio" {...props} />
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                    <span>{label}</span>
         | 
| 18 | 
            -
                  </label>
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                  {hasError ? <div className={styles.error}>{error}</div> : null}
         | 
| 21 | 
            -
                  {hint ? <div className={styles.hint}>{hint}</div> : null}
         | 
| 22 | 
            -
                </div>
         | 
| 23 | 
            -
              )
         | 
| 24 | 
            -
            }
         | 
| 25 | 
            -
             | 
| 26 | 
            -
            Component.displayName = 'Hue.Form.Fields.RadioInput'
         | 
| 27 | 
            -
            Component.propTypes = {
         | 
| 28 | 
            -
              name: PropTypes.string.isRequired,
         | 
| 29 | 
            -
              label: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.element]).isRequired,
         | 
| 30 | 
            -
             | 
| 31 | 
            -
              // Custom class name. This will be appended to the default class.
         | 
| 32 | 
            -
              className: PropTypes.string,
         | 
| 33 | 
            -
             | 
| 34 | 
            -
              // The name of the attribute to use for the error message. Default: 'props.name'.
         | 
| 35 | 
            -
              errorAttrName: PropTypes.string,
         | 
| 36 | 
            -
             | 
| 37 | 
            -
              id: PropTypes.string,
         | 
| 38 | 
            -
              hint: PropTypes.string,
         | 
| 39 | 
            -
              disabled: PropTypes.bool
         | 
| 40 | 
            -
             | 
| 41 | 
            -
              // All remaining non-descript props will be forwarded to the <input> element.
         | 
| 42 | 
            -
            }
         | 
| 43 | 
            -
             | 
| 44 | 
            -
            export default Component
         | 
| @@ -1,13 +0,0 @@ | |
| 1 | 
            -
            @layer hue-component {
         | 
| 2 | 
            -
              .fieldWrapper {
         | 
| 3 | 
            -
                @mixin radio from url('/hue/lib/hue/mixins/radio.mixin.css');
         | 
| 4 | 
            -
              }
         | 
| 5 | 
            -
             | 
| 6 | 
            -
              .hint {
         | 
| 7 | 
            -
                @mixin fieldHint from url('/hue/lib/hue/mixins/field.mixin.css');
         | 
| 8 | 
            -
              }
         | 
| 9 | 
            -
             | 
| 10 | 
            -
              .error {
         | 
| 11 | 
            -
                @mixin fieldError from url('/hue/lib/hue/mixins/field.mixin.css');
         | 
| 12 | 
            -
              }
         | 
| 13 | 
            -
            }
         |