@@ -164,6 +164,90 @@ defmodule Backpex.HTML.Form do
164
164
"""
165
165
end
166
166
167
+ @ doc """
168
+ Renders a masked input.
169
+
170
+ A `Phoenix.HTML.FormField` may be passed as argument, which is used to retrieve the input name, id, and values.
171
+ Otherwise all attributes may be passed explicitly.
172
+
173
+ ## Examples
174
+
175
+ <.masked_input field={@form[:amount]} unit="€" />
176
+ <.masked_input id="amount-input" name="amount" value="20" unit="€" readonly />
177
+ """
178
+ attr :id , :any , default: nil
179
+ attr :name , :any
180
+ attr :label , :string , default: nil
181
+ attr :help_text , :string , default: nil
182
+ attr :value , :any
183
+
184
+ attr :field , Phoenix.HTML.FormField , doc: "a form field struct retrieved from the form, for example: @form[:email]"
185
+
186
+ attr :errors , :list , default: [ ]
187
+
188
+ attr :class , :any , default: nil , doc: "additional classes for the container element"
189
+
190
+ attr :input_class , :any ,
191
+ default: nil ,
192
+ doc: "the input class to use over defaults, note that this is applied to a wrapper span element
193
+ to allow for proper styling of the masked input"
194
+
195
+ attr :error_class , :any , default: nil , doc: "the input error class to use over defaults"
196
+
197
+ attr :translate_error_fun , :any , default: & Function . identity / 1 , doc: "a custom function to map form errors"
198
+ attr :hide_errors , :boolean , default: false , doc: "if errors should be hidden"
199
+
200
+ attr :unit , :string , default: nil
201
+ attr :radix , :string , default: "."
202
+ attr :thousands_separator , :string , default: ","
203
+
204
+ attr :rest , :global , include: ~w( accept autocomplete capture cols disabled form list max maxlength min minlength
205
+ multiple pattern placeholder readonly required rows size step)
206
+
207
+ def masked_input ( % { field: % Phoenix.HTML.FormField { } = field } = assigns ) do
208
+ errors = if Phoenix.Component . used_input? ( field ) , do: field . errors , else: [ ]
209
+
210
+ assigns
211
+ |> assign ( field: nil , id: assigns . id || field . id )
212
+ |> assign ( :errors , translate_form_errors ( errors , assigns . translate_error_fun ) )
213
+ |> assign_new ( :name , fn -> field . name end )
214
+ |> assign_new ( :value , fn -> field . value end )
215
+ |> masked_input ( )
216
+ end
217
+
218
+ def masked_input ( assigns ) do
219
+ ~H"""
220
+ < div class = { [ "fieldset py-0" , @ class ] } >
221
+ < span :if = { @ label } class = "label mb-1 " > { @ label } </ span >
222
+ < div
223
+ id = { @ id }
224
+ phx-hook = "BackpexMaskedInput "
225
+ data-radix = { @ radix }
226
+ data-unit = { @ unit }
227
+ data-thousands-separator = { @ thousands_separator }
228
+ >
229
+ <%!-- As the input ignores updates, we need to wrap it in a span to apply the styles correctly --%>
230
+ < span class = { [
231
+ @ input_class || "[&_>_input]:input [&_>_input]:w-full" ,
232
+ @ errors != [ ] && ( @ error_class || "[&_>_input]:input-error [&_>_input]:bg-error/10" )
233
+ ] } >
234
+ < input
235
+ id = { "#{ @ id } _masked" }
236
+ name = { @ name }
237
+ value = { @ value }
238
+ data-masked-input
239
+ phx-update = "ignore "
240
+ class = { @ input_class }
241
+ { @ rest }
242
+ />
243
+ </ span >
244
+ </ div >
245
+ < . error :for = { msg <- @ errors } :if = { not @ hide_errors } > { msg } </ . error >
246
+ < . help_text :if = { @ help_text } > { @ help_text } </ . help_text >
247
+ </ div >
248
+ """
249
+ end
250
+
167
251
@ doc """
168
252
Generates a generic error message.
169
253
"""
0 commit comments