phlex-forms 0.2.9 → 0.3.1
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/CHANGELOG.md +25 -0
- data/README.md +2 -2
- data/lib/forms/field.rb +12 -1
- data/lib/forms/file_input.rb +4 -1
- data/lib/forms/form.rb +2 -2
- data/lib/forms/hidden.rb +30 -0
- data/lib/forms/rich_textarea.rb +35 -2
- data/lib/phlex_forms/theme.rb +5 -3
- data/lib/phlex_forms/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9541561e98ecd2afda34daf77d2eeebd725aac0badde75fdbf51401628d081f6
|
|
4
|
+
data.tar.gz: 5d4008e8e6e5748ae12fdbcd12a667d016ab30549da71498dbc2e286fe202d81
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f10fd9155f6ff9841bdae9c34fb2ac89dbbdbc49df33c012af7efad526fa914d21c6379430e1ee66a1aadeff387dcc9bab353d33cb017ce8b07798dd8058dd2c
|
|
7
|
+
data.tar.gz: 7ea1bdaa7fea101bde79b7975759c79b30bc502fb50c2b18e279a5cf4032b294745055e23f2f66ed22cba33c4e43c637c6499ea3c62059f425a3b3aec141ad83
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **`rich_textarea` forwards its block into `<lexxy-editor>`**: Lexxy configures
|
|
13
|
+
an editor through CHILD elements — `<lexxy-prompt>` for @mentions,
|
|
14
|
+
`<lexxy-code-language-picker>` for code blocks — but the component rendered
|
|
15
|
+
the element with no block and `Form#rich_textarea` never forwarded one, so
|
|
16
|
+
`f.rich_textarea(:content) { ... }` silently dropped its content. A host
|
|
17
|
+
could wire @mentions and get an editor that never prompts, with no error
|
|
18
|
+
anywhere (a host app's mention endpoint 500'd for months unnoticed, because
|
|
19
|
+
nothing ever called it).
|
|
20
|
+
- **`rich_textarea` wires Active Storage's direct-upload endpoints**: Lexxy
|
|
21
|
+
uploads attachments through `data-direct-upload-url` /
|
|
22
|
+
`data-blob-url-template` on the element. Lexxy's own Rails tag helper sets
|
|
23
|
+
them; this component built the element itself and did not, so rich text
|
|
24
|
+
editors silently lost image uploads. Set as PATHS (a multi-host app must not
|
|
25
|
+
pin uploads to whichever host rendered the page first), fully guarded — no
|
|
26
|
+
Rails dependency is introduced, and a caller-supplied value always wins.
|
|
27
|
+
|
|
28
|
+
- **`FileInput` multiple uploads submit an array** (Rails `file_field` parity):
|
|
29
|
+
with `multiple:` set, the input name now gets `[]` appended (unless already
|
|
30
|
+
present), for the standalone component, the `Plain` variant, and the form
|
|
31
|
+
builder path. Without it the browser collapsed a multi-file selection into
|
|
32
|
+
ONE scalar param, which a host app's `params.expect(attr: [])` silently
|
|
33
|
+
discarded — uploads no-opped with a success response.
|
|
34
|
+
|
|
10
35
|
### Added
|
|
11
36
|
|
|
12
37
|
- **`checkbox_group` — batched checkbox group for array-valued fields** (the
|
data/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A model-bound form builder for [Phlex](https://www.phlex.fun) — forms as
|
|
|
4
4
|
first-class Phlex classes, types inferred from your model, DaisyUI styling by
|
|
5
5
|
default (and a plain-HTML theme when you want none), and optional
|
|
6
6
|
**server-truth live validation** over
|
|
7
|
-
[phlex-reactive](https://github.com/
|
|
7
|
+
[phlex-reactive](https://github.com/zoolutions/phlex-reactive).
|
|
8
8
|
|
|
9
9
|
```ruby
|
|
10
10
|
class UserForm < Forms::Base
|
|
@@ -158,7 +158,7 @@ Both work on inline forms (`f.row { … }`) and inside `fields_for` builders.
|
|
|
158
158
|
|
|
159
159
|
`as: :tags` renders a polished tag/chip input — label + error/hint chrome and
|
|
160
160
|
daisyUI styling on top of
|
|
161
|
-
[phlex-reactive](https://github.com/
|
|
161
|
+
[phlex-reactive](https://github.com/zoolutions/phlex-reactive)'s client-only tag
|
|
162
162
|
primitives (form state, no server round trips). **Requires phlex-reactive** (the `:tags` role is
|
|
163
163
|
registered only when it's loaded).
|
|
164
164
|
|
data/lib/forms/field.rb
CHANGED
|
@@ -30,6 +30,12 @@ module Forms
|
|
|
30
30
|
# PhlexForms::Theme), so the same field renders daisy or plain.
|
|
31
31
|
|
|
32
32
|
def input(*modifiers, type: :text, **)
|
|
33
|
+
# type: :hidden reroutes to #hidden so EVERY path to a hidden field lands on
|
|
34
|
+
# the bare leaf — `f.Input(:token, :hidden)` and `f.Input(:token, type:
|
|
35
|
+
# :hidden)` would otherwise still emit the styled `input w-full`. Positional
|
|
36
|
+
# modifiers are dropped with it: a hidden field has no visual variants.
|
|
37
|
+
return hidden(**) if type.to_s == "hidden"
|
|
38
|
+
|
|
33
39
|
theme[:input].new(*modifiers, type:, **field_attributes, **)
|
|
34
40
|
end
|
|
35
41
|
|
|
@@ -43,8 +49,13 @@ module Forms
|
|
|
43
49
|
end
|
|
44
50
|
alias rich_text_area rich_textarea
|
|
45
51
|
|
|
52
|
+
# Bare <input type="hidden">, never the styled :input leaf — daisyui's
|
|
53
|
+
# `.input` beats WebKit's non-!important `input[type=hidden] { display: none }`
|
|
54
|
+
# and turns the field into a focusable phantom tab stop in Safari. Built from
|
|
55
|
+
# the explicit accessors (not field_attributes) so the meaningless
|
|
56
|
+
# `error: invalid?` is never introduced.
|
|
46
57
|
def hidden(**)
|
|
47
|
-
theme[:
|
|
58
|
+
theme[:hidden].new(name: field_name, id: field_id, value: field_value, **)
|
|
48
59
|
end
|
|
49
60
|
|
|
50
61
|
# daisyui v5 "icon/text inside the field" wrapper. The block renders the
|
data/lib/forms/file_input.rb
CHANGED
|
@@ -8,7 +8,10 @@ module Forms
|
|
|
8
8
|
def initialize(*modifiers, name: nil, id: nil, multiple: false, accept: nil,
|
|
9
9
|
error: false, disabled: false, required: false, full_width: true, **attributes)
|
|
10
10
|
@modifiers = normalize_modifiers(modifiers)
|
|
11
|
-
|
|
11
|
+
# Rails file_field parity: a multiple input needs an array param name, or
|
|
12
|
+
# the browser collapses the selection into one scalar file — which a host
|
|
13
|
+
# app's `params.expect(attr: [])` then silently discards.
|
|
14
|
+
@name = multiple && name && !name.to_s.end_with?("[]") ? "#{name}[]" : name
|
|
12
15
|
@id = id
|
|
13
16
|
@multiple = multiple
|
|
14
17
|
@accept = accept
|
data/lib/forms/form.rb
CHANGED
|
@@ -78,8 +78,8 @@ module Forms
|
|
|
78
78
|
render theme[:submit].new(*, model: @model, **, &)
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
def rich_textarea(name, *modifiers,
|
|
82
|
-
render field_object(name).rich_textarea(*modifiers, **)
|
|
81
|
+
def rich_textarea(name, *modifiers, **, &)
|
|
82
|
+
render field_object(name).rich_textarea(*modifiers, **), &
|
|
83
83
|
end
|
|
84
84
|
alias rich_text_area rich_textarea
|
|
85
85
|
|
data/lib/forms/hidden.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Forms
|
|
4
|
+
# A model-bound hidden field: a bare <input type="hidden"> carrying name/id/
|
|
5
|
+
# value plus whatever the caller passes through. Deliberately NOT a
|
|
6
|
+
# DelegatedField/DaisyUI::Input like Forms::Input — a hidden field must never
|
|
7
|
+
# carry visual styling. daisyui's `.input { display: inline-flex }` overrides
|
|
8
|
+
# WebKit's *non*-!important UA rule `input[type=hidden] { display: none }`, so a
|
|
9
|
+
# styled hidden field renders as an empty box and joins the keyboard tab order
|
|
10
|
+
# in Safari (Chromium's UA rule is !important, hiding the bug there).
|
|
11
|
+
#
|
|
12
|
+
# Forms::Hidden.new(name: "user[token]", id: "user_token", value: "abc123")
|
|
13
|
+
#
|
|
14
|
+
# Same component under both themes (:hidden role) — there are no styling
|
|
15
|
+
# classes for a Plain twin to strip. It takes no positional variants and no
|
|
16
|
+
# error:: a hidden field has no visual or error state.
|
|
17
|
+
class Hidden < Phlex::HTML
|
|
18
|
+
def initialize(name: nil, id: nil, value: nil, **attributes)
|
|
19
|
+
@name = name
|
|
20
|
+
@id = id
|
|
21
|
+
@value = value
|
|
22
|
+
@attributes = attributes
|
|
23
|
+
super()
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def view_template
|
|
27
|
+
input(type: "hidden", name: @name, id: @id, value: @value.to_s, **@attributes)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/forms/rich_textarea.rb
CHANGED
|
@@ -14,21 +14,54 @@ module Forms
|
|
|
14
14
|
@id = id || name.to_s.gsub(/[\[\]]/, "_").gsub(/_+$/, "")
|
|
15
15
|
@value = value
|
|
16
16
|
@options = options
|
|
17
|
+
apply_direct_upload_defaults
|
|
17
18
|
super()
|
|
18
19
|
end
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
# Lexxy configures the editor through CHILD elements — `<lexxy-prompt>` for
|
|
22
|
+
# @mentions, `<lexxy-code-language-picker>` for code blocks — so the block
|
|
23
|
+
# has to reach the element, not be dropped.
|
|
24
|
+
def view_template(&)
|
|
21
25
|
lexxy_editor(
|
|
22
26
|
name: @name,
|
|
23
27
|
id: @id,
|
|
24
28
|
value: formatted_value,
|
|
25
29
|
class: editor_classes,
|
|
26
|
-
**@options.except(:class, :error)
|
|
30
|
+
**@options.except(:class, :error),
|
|
31
|
+
&
|
|
27
32
|
)
|
|
28
33
|
end
|
|
29
34
|
|
|
30
35
|
private
|
|
31
36
|
|
|
37
|
+
# Lexxy uploads attachments through Active Storage's direct-upload
|
|
38
|
+
# endpoints, read off the element. Lexxy's own Rails tag helper sets them;
|
|
39
|
+
# this component builds the element itself, so without these an editor
|
|
40
|
+
# silently loses image uploads. Paths, not URLs: a multi-host app must not
|
|
41
|
+
# pin uploads to whichever host rendered the page first.
|
|
42
|
+
#
|
|
43
|
+
# Fully guarded — the gem has no Rails dependency, and a host without
|
|
44
|
+
# Active Storage (or with its own values) is left alone.
|
|
45
|
+
def apply_direct_upload_defaults
|
|
46
|
+
helpers = rails_url_helpers or return
|
|
47
|
+
|
|
48
|
+
data = (@options[:data] ||= {})
|
|
49
|
+
data[:direct_upload_url] ||= helpers.rails_direct_uploads_path
|
|
50
|
+
data[:blob_url_template] ||= helpers.rails_service_blob_path(":signed_id", ":filename")
|
|
51
|
+
rescue StandardError
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def rails_url_helpers
|
|
56
|
+
return unless defined?(Rails) && Rails.respond_to?(:application)
|
|
57
|
+
|
|
58
|
+
helpers = Rails.application&.routes&.url_helpers
|
|
59
|
+
return unless helpers.respond_to?(:rails_direct_uploads_path)
|
|
60
|
+
return unless helpers.respond_to?(:rails_service_blob_path)
|
|
61
|
+
|
|
62
|
+
helpers
|
|
63
|
+
end
|
|
64
|
+
|
|
32
65
|
def formatted_value
|
|
33
66
|
return nil if @value.nil? || (@value.respond_to?(:blank?) && @value.blank?)
|
|
34
67
|
|
data/lib/phlex_forms/theme.rb
CHANGED
|
@@ -4,7 +4,9 @@ module PhlexForms
|
|
|
4
4
|
# A theme maps component roles (:input, :select, :control, ...) to component
|
|
5
5
|
# classes. The binding contract — the leaf initializer signatures
|
|
6
6
|
# (*modifiers, name:, id:, value:, error:, required:, ...) — is the stable
|
|
7
|
-
# interface, so the same form class renders under any theme.
|
|
7
|
+
# interface, so the same form class renders under any theme. The one exception
|
|
8
|
+
# is :hidden, which takes name:/id:/value: only — a hidden field has neither a
|
|
9
|
+
# visual variant nor an error state.
|
|
8
10
|
#
|
|
9
11
|
# Built-ins:
|
|
10
12
|
# Theme.daisy — the DaisyUI-delegating Forms::* leaves (default when the
|
|
@@ -56,7 +58,7 @@ module PhlexForms
|
|
|
56
58
|
textarea: Forms::Textarea, rich_textarea: Forms::RichTextarea,
|
|
57
59
|
checkbox: Forms::Checkbox, toggle: Forms::Toggle, radio: Forms::Radio,
|
|
58
60
|
checkbox_group: Forms::CheckboxGroup,
|
|
59
|
-
file: Forms::FileInput, wrapped_input: Forms::WrappedInput,
|
|
61
|
+
file: Forms::FileInput, wrapped_input: Forms::WrappedInput, hidden: Forms::Hidden,
|
|
60
62
|
control: Forms::FormControl, label: Forms::Label,
|
|
61
63
|
field_error: Forms::FieldError, field_hint: Forms::FieldHint,
|
|
62
64
|
submit: Forms::Submit, row: Forms::Row, group: Forms::Group,
|
|
@@ -74,7 +76,7 @@ module PhlexForms
|
|
|
74
76
|
textarea: Forms::Plain::Textarea, rich_textarea: Forms::Plain::Textarea,
|
|
75
77
|
checkbox: Forms::Plain::Checkbox, toggle: Forms::Plain::Checkbox, radio: Forms::Plain::Radio,
|
|
76
78
|
checkbox_group: Forms::Plain::CheckboxGroup,
|
|
77
|
-
file: Forms::Plain::FileInput, wrapped_input: Forms::Plain::WrappedInput,
|
|
79
|
+
file: Forms::Plain::FileInput, wrapped_input: Forms::Plain::WrappedInput, hidden: Forms::Hidden,
|
|
78
80
|
control: Forms::Plain::Control, label: Forms::Plain::Label,
|
|
79
81
|
field_error: Forms::Plain::FieldError, field_hint: Forms::Plain::FieldHint,
|
|
80
82
|
submit: Forms::Plain::Submit, row: Forms::Plain::Row, group: Forms::Plain::Group,
|
data/lib/phlex_forms/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: phlex-forms
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mikael Henriksson
|
|
@@ -128,6 +128,7 @@ files:
|
|
|
128
128
|
- lib/forms/form.rb
|
|
129
129
|
- lib/forms/form_control.rb
|
|
130
130
|
- lib/forms/group.rb
|
|
131
|
+
- lib/forms/hidden.rb
|
|
131
132
|
- lib/forms/input.rb
|
|
132
133
|
- lib/forms/label.rb
|
|
133
134
|
- lib/forms/live.rb
|
|
@@ -178,13 +179,13 @@ files:
|
|
|
178
179
|
- lib/phlex_forms/version.rb
|
|
179
180
|
- lib/rubocop/phlex_forms/cop/legacy_form_method.rb
|
|
180
181
|
- lib/rubocop/phlex_forms/cop/raw_form.rb
|
|
181
|
-
homepage: https://github.com/
|
|
182
|
+
homepage: https://github.com/zoolutions/phlex-forms
|
|
182
183
|
licenses:
|
|
183
184
|
- MIT
|
|
184
185
|
metadata:
|
|
185
|
-
source_code_uri: https://github.com/
|
|
186
|
-
changelog_uri: https://github.com/
|
|
187
|
-
bug_tracker_uri: https://github.com/
|
|
186
|
+
source_code_uri: https://github.com/zoolutions/phlex-forms
|
|
187
|
+
changelog_uri: https://github.com/zoolutions/phlex-forms/blob/main/CHANGELOG.md
|
|
188
|
+
bug_tracker_uri: https://github.com/zoolutions/phlex-forms/issues
|
|
188
189
|
rubygems_mfa_required: 'true'
|
|
189
190
|
rdoc_options: []
|
|
190
191
|
require_paths:
|