this repo has no description
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

alternative api

this one doesn’t require two sets of the same functions on both the field and the input. but both have their drawbacks.

+1198 -1171
+45
formz/src/formz/definition.gleam
··· 1 + import formz/field.{type Definition, Definition} 2 + 3 + pub fn validates( 4 + definition: Definition(format, output), 5 + next: fn(output) -> Result(output, String), 6 + ) -> Definition(format, output) { 7 + let Definition(widget, previous_transform, placeholder) = definition 8 + 9 + Definition( 10 + widget, 11 + fn(str) { 12 + case previous_transform(str) { 13 + Ok(value) -> next(value) 14 + Error(error) -> Error(error) 15 + } 16 + }, 17 + placeholder, 18 + ) 19 + } 20 + 21 + pub fn transforms( 22 + definition: Definition(format, a), 23 + placeholder: b, 24 + next: fn(a) -> Result(b, String), 25 + ) -> Definition(format, b) { 26 + let Definition(widget, previous_transform, _) = definition 27 + 28 + Definition( 29 + widget, 30 + fn(str) { 31 + case previous_transform(str) { 32 + Ok(value) -> next(value) 33 + Error(error) -> Error(error) 34 + } 35 + }, 36 + placeholder, 37 + ) 38 + } 39 + 40 + pub fn set_widget( 41 + definition: Definition(format, a), 42 + widget: field.Widget(format), 43 + ) -> Definition(format, a) { 44 + Definition(..definition, widget:) 45 + }
+415 -80
formz/src/formz/field.gleam
··· 1 - import formz/input.{type Input} 2 - import gleam/option 3 - import gleam/result 4 - import gleam/string 5 1 import justin 6 2 7 - pub type Field(format, output) { 8 - Field( 9 - input: Input(format), 10 - placeholder: output, 11 - transform: fn(String) -> Result(output, String), 3 + pub type Field(format) { 4 + Valid( 5 + name: String, 6 + label: String, 7 + help_text: String, 8 + disabled: Bool, 9 + required: Bool, 10 + widget: Widget(format), 11 + hidden: Bool, 12 + value: String, 13 + ) 14 + Invalid( 15 + name: String, 16 + label: String, 17 + help_text: String, 18 + disabled: Bool, 19 + required: Bool, 20 + widget: Widget(format), 21 + hidden: Bool, 22 + value: String, 23 + error: String, 12 24 ) 13 25 } 14 26 15 27 pub type Definition(format, output) { 16 28 Definition( 17 - widget: input.Widget(format), 29 + widget: Widget(format), 18 30 transform: fn(String) -> Result(output, String), 19 31 placeholder: output, 20 32 ) 21 33 } 22 34 23 - pub fn field( 24 - name: String, 25 - definition: Definition(format, output), 26 - ) -> Field(format, output) { 27 - Field( 28 - input.Valid( 29 - name, 30 - justin.sentence_case(name), 31 - help_text: "", 32 - widget: definition.widget, 33 - hidden: False, 34 - value: "", 35 - disabled: False, 36 - required: True, 37 - ), 38 - definition.placeholder, 39 - definition.transform, 35 + pub opaque type Widget(format) { 36 + Widget(fn(Field(format), WidgetArgs) -> format) 37 + } 38 + 39 + pub type WidgetArgs { 40 + WidgetArgs(id: String, labelled_by: InputLabelled) 41 + } 42 + 43 + pub type InputLabelled { 44 + Element 45 + Value 46 + Id(element_id: String) 47 + } 48 + 49 + pub fn field(named name: String) -> Field(format) { 50 + Valid( 51 + name: name, 52 + label: justin.sentence_case(name), 53 + help_text: "", 54 + disabled: False, 55 + required: False, 56 + widget: Widget(fn(_, _) { panic }), 57 + hidden: False, 58 + value: "", 40 59 ) 41 60 } 42 61 43 - pub fn set_name(field: Field(format, b), name: String) -> Field(format, b) { 44 - Field(..field, input: input.set_name(field.input, name)) 62 + pub fn widget(fun: fn(Field(format), WidgetArgs) -> format) -> Widget(format) { 63 + Widget(fun) 45 64 } 46 65 47 - pub fn set_label(field: Field(format, b), label: String) -> Field(format, b) { 48 - Field(..field, input: input.set_label(field.input, label)) 66 + pub fn set_name(field: Field(format), name: String) -> Field(format) { 67 + case field { 68 + Valid( 69 + _name, 70 + label:, 71 + help_text:, 72 + widget:, 73 + hidden:, 74 + value:, 75 + disabled:, 76 + required:, 77 + ) -> 78 + Valid( 79 + name:, 80 + label:, 81 + help_text:, 82 + widget:, 83 + hidden:, 84 + value:, 85 + disabled:, 86 + required:, 87 + ) 88 + Invalid( 89 + _name, 90 + label:, 91 + help_text:, 92 + widget:, 93 + hidden:, 94 + disabled:, 95 + required:, 96 + value:, 97 + error:, 98 + ) -> 99 + Invalid( 100 + name:, 101 + label:, 102 + help_text:, 103 + widget:, 104 + hidden:, 105 + value:, 106 + error:, 107 + disabled:, 108 + required:, 109 + ) 110 + } 49 111 } 50 112 51 - pub fn set_help_text( 52 - field: Field(format, b), 53 - help_text: String, 54 - ) -> Field(format, b) { 55 - Field(..field, input: input.set_help_text(field.input, help_text)) 113 + pub fn set_label(field: Field(format), label: String) -> Field(format) { 114 + case field { 115 + Valid( 116 + _label, 117 + name:, 118 + help_text:, 119 + widget:, 120 + hidden:, 121 + value:, 122 + disabled:, 123 + required:, 124 + ) -> 125 + Valid( 126 + name:, 127 + label:, 128 + help_text:, 129 + widget:, 130 + hidden:, 131 + value:, 132 + disabled:, 133 + required:, 134 + ) 135 + Invalid( 136 + _label, 137 + name:, 138 + help_text:, 139 + widget:, 140 + hidden:, 141 + disabled:, 142 + required:, 143 + value:, 144 + error:, 145 + ) -> 146 + Invalid( 147 + name:, 148 + label:, 149 + help_text:, 150 + widget:, 151 + hidden:, 152 + value:, 153 + error:, 154 + disabled:, 155 + required:, 156 + ) 157 + } 56 158 } 57 159 58 - pub fn set_widget( 59 - field: Field(format, b), 60 - widget: fn(Input(format), input.WidgetArgs) -> format, 61 - ) -> Field(format, b) { 62 - Field(..field, input: input.set_widget(field.input, widget)) 160 + pub fn set_help_text(field: Field(format), help_text: String) -> Field(format) { 161 + case field { 162 + Valid( 163 + _help_text, 164 + name:, 165 + label:, 166 + widget:, 167 + hidden:, 168 + value:, 169 + disabled:, 170 + required:, 171 + ) -> 172 + Valid( 173 + name:, 174 + label:, 175 + help_text:, 176 + widget:, 177 + hidden:, 178 + value:, 179 + disabled:, 180 + required:, 181 + ) 182 + Invalid( 183 + _help_text, 184 + name:, 185 + label:, 186 + widget:, 187 + hidden:, 188 + disabled:, 189 + required:, 190 + value:, 191 + error:, 192 + ) -> 193 + Invalid( 194 + name:, 195 + label:, 196 + help_text:, 197 + widget:, 198 + hidden:, 199 + value:, 200 + error:, 201 + disabled:, 202 + required:, 203 + ) 204 + } 63 205 } 64 206 65 - pub fn set_value(field: Field(format, b), value: String) -> Field(format, b) { 66 - Field(..field, input: input.set_value(field.input, value)) 207 + pub fn set_widget(field: Field(format), widget: Widget(format)) -> Field(format) { 208 + case field { 209 + Valid( 210 + _widget, 211 + name:, 212 + label:, 213 + help_text:, 214 + hidden:, 215 + value:, 216 + disabled:, 217 + required:, 218 + ) -> 219 + Valid( 220 + name:, 221 + label:, 222 + help_text:, 223 + widget:, 224 + hidden:, 225 + value:, 226 + disabled:, 227 + required:, 228 + ) 229 + Invalid( 230 + _widget, 231 + name:, 232 + label:, 233 + help_text:, 234 + hidden:, 235 + disabled:, 236 + required:, 237 + value:, 238 + error:, 239 + ) -> 240 + Invalid( 241 + name:, 242 + label:, 243 + help_text:, 244 + widget:, 245 + hidden:, 246 + value:, 247 + error:, 248 + disabled:, 249 + required:, 250 + ) 251 + } 67 252 } 68 253 69 - pub fn set_visibility( 70 - field: Field(format, b), 71 - visibility: Bool, 72 - ) -> Field(format, b) { 73 - Field(..field, input: input.set_hidden(field.input, visibility)) 254 + pub fn set_visibility(field: Field(format), hidden: Bool) -> Field(format) { 255 + case field { 256 + Valid( 257 + _hidden, 258 + name:, 259 + label:, 260 + help_text:, 261 + widget:, 262 + value:, 263 + disabled:, 264 + required:, 265 + ) -> 266 + Valid( 267 + name:, 268 + label:, 269 + help_text:, 270 + widget:, 271 + hidden:, 272 + value:, 273 + disabled:, 274 + required:, 275 + ) 276 + Invalid( 277 + _hidden, 278 + name:, 279 + label:, 280 + help_text:, 281 + widget:, 282 + disabled:, 283 + required:, 284 + value:, 285 + error:, 286 + ) -> 287 + Invalid( 288 + name:, 289 + label:, 290 + help_text:, 291 + widget:, 292 + hidden:, 293 + value:, 294 + error:, 295 + disabled:, 296 + required:, 297 + ) 298 + } 74 299 } 75 300 76 - pub fn make_visible(field: Field(format, b)) -> Field(format, b) { 301 + pub fn make_hidden(field: Field(format)) -> Field(format) { 77 302 set_visibility(field, True) 78 303 } 79 304 80 - pub fn make_hidden(field: Field(format, b)) -> Field(format, b) { 305 + pub fn make_visible(field: Field(format)) -> Field(format) { 81 306 set_visibility(field, False) 82 307 } 83 308 84 - pub fn set_optional(field: Field(format, b)) -> Field(format, option.Option(b)) { 85 - Field(input: field.input, placeholder: option.None, transform: fn(str) { 86 - case string.trim(str) { 87 - "" -> Ok(option.None) 88 - _ -> result.map(field.transform(str), option.Some) 89 - } 90 - }) 309 + pub fn set_disabled(field: Field(format), disabled: Bool) -> Field(format) { 310 + case field { 311 + Valid( 312 + _disabled, 313 + name:, 314 + label:, 315 + help_text:, 316 + widget:, 317 + value:, 318 + hidden:, 319 + required:, 320 + ) -> 321 + Valid( 322 + name:, 323 + label:, 324 + help_text:, 325 + widget:, 326 + hidden:, 327 + value:, 328 + disabled:, 329 + required:, 330 + ) 331 + Invalid( 332 + _disabled, 333 + name:, 334 + label:, 335 + help_text:, 336 + widget:, 337 + hidden:, 338 + required:, 339 + value:, 340 + error:, 341 + ) -> 342 + Invalid( 343 + name:, 344 + label:, 345 + help_text:, 346 + widget:, 347 + hidden:, 348 + value:, 349 + error:, 350 + disabled:, 351 + required:, 352 + ) 353 + } 91 354 } 92 355 93 - pub fn validates( 94 - field: Field(format, b), 95 - next: fn(b) -> Result(b, String), 96 - ) -> Field(format, b) { 97 - let Field(field, placeholder, previous_transform) = field 356 + pub fn set_value(field: Field(format), value: String) -> Field(format) { 357 + case field { 358 + Valid( 359 + _value, 360 + name:, 361 + label:, 362 + help_text:, 363 + widget:, 364 + hidden:, 365 + disabled:, 366 + required:, 367 + ) -> 368 + Valid( 369 + name:, 370 + label:, 371 + help_text:, 372 + widget:, 373 + hidden:, 374 + value:, 375 + disabled:, 376 + required:, 377 + ) 378 + Invalid( 379 + _value, 380 + name:, 381 + label:, 382 + help_text:, 383 + widget:, 384 + hidden:, 385 + disabled:, 386 + required:, 387 + error:, 388 + ) -> 389 + Invalid( 390 + name:, 391 + label:, 392 + help_text:, 393 + widget:, 394 + hidden:, 395 + value:, 396 + error:, 397 + disabled:, 398 + required:, 399 + ) 400 + } 401 + } 98 402 99 - Field(field, placeholder, fn(str) { 100 - case previous_transform(str) { 101 - Ok(value) -> next(value) 102 - Error(error) -> Error(error) 103 - } 104 - }) 403 + pub fn set_error(field: Field(format), error: String) -> Field(format) { 404 + case field { 405 + Valid( 406 + name:, 407 + label:, 408 + help_text:, 409 + widget:, 410 + hidden:, 411 + value:, 412 + disabled:, 413 + required:, 414 + ) -> 415 + Invalid( 416 + name:, 417 + label:, 418 + help_text:, 419 + widget:, 420 + hidden:, 421 + value:, 422 + disabled:, 423 + required:, 424 + error:, 425 + ) 426 + Invalid( 427 + _error, 428 + name:, 429 + label:, 430 + help_text:, 431 + widget:, 432 + hidden:, 433 + disabled:, 434 + required:, 435 + value:, 436 + ) -> 437 + Invalid( 438 + name:, 439 + label:, 440 + help_text:, 441 + widget:, 442 + hidden:, 443 + value:, 444 + error:, 445 + disabled:, 446 + required:, 447 + ) 448 + } 105 449 } 106 450 107 - pub fn transforms( 108 - field: Field(format, b), 109 - placeholder: c, 110 - next: fn(b) -> Result(c, String), 111 - ) -> Field(format, c) { 112 - let Field(field, _, previous_transform) = field 451 + pub fn run_widget(f: Field(format), args: WidgetArgs) -> format { 452 + let Widget(fun) = f.widget 113 453 114 - Field(field, placeholder, fn(str) { 115 - case previous_transform(str) { 116 - Ok(value) -> next(value) 117 - Error(error) -> Error(error) 118 - } 119 - }) 454 + fun(f, args) 120 455 }
+142 -142
formz/src/formz/formz_pipes.gleam
··· 13 13 // - errors on hidden fields? 14 14 // - custom types for input.hidden, input.disabled, input.required? 15 15 16 - import formz/field.{type Field} 17 - import formz/input.{type Input, Valid} 18 - import gleam/list 19 - import gleam/option.{type Option, None, Some} 20 - import gleam/result 16 + // import formz/field.{type Field} 17 + // import formz/input.{type Input, Valid} 18 + // import gleam/list 19 + // import gleam/option.{type Option, None, Some} 20 + // import gleam/result 21 21 22 - pub type HasDecoder 22 + // pub type HasDecoder 23 23 24 - pub type NoDecoder 24 + // pub type NoDecoder 25 25 26 - pub opaque type Form(format, output, decoder, has_decoder) { 27 - Form( 28 - fields: List(Input(format)), 29 - parse_with: fn(List(Input(format)), decoder) -> 30 - Result(output, List(Input(format))), 31 - decoder: Option(decoder), 32 - ) 33 - } 26 + // pub opaque type Form(format, output, decoder, has_decoder) { 27 + // Form( 28 + // fields: List(Input(format)), 29 + // parse_with: fn(List(Input(format)), decoder) -> 30 + // Result(output, List(Input(format))), 31 + // decoder: Option(decoder), 32 + // ) 33 + // } 34 34 35 - pub fn new() -> Form(format, a, a, NoDecoder) { 36 - Form([], fn(_, output) { Ok(output) }, None) 37 - } 35 + // pub fn new() -> Form(format, a, a, NoDecoder) { 36 + // Form([], fn(_, output) { Ok(output) }, None) 37 + // } 38 38 39 - pub fn add( 40 - form: Form( 41 - format, 42 - fn(decoder_step_input) -> decoder_step_output, 43 - form_output, 44 - has_decoder, 45 - ), 46 - definition: Field(format, decoder_step_input), 47 - ) -> Form(format, decoder_step_output, form_output, has_decoder) { 48 - let Form(inputs, parse_with, decoder) = form 39 + // pub fn add( 40 + // form: Form( 41 + // format, 42 + // fn(decoder_step_input) -> decoder_step_output, 43 + // form_output, 44 + // has_decoder, 45 + // ), 46 + // definition: Field(format, decoder_step_input), 47 + // ) -> Form(format, decoder_step_output, form_output, has_decoder) { 48 + // let Form(inputs, parse_with, decoder) = form 49 49 50 - // create new form with the new field and update the parse 51 - // function to handle the new details from the type of the 52 - // field 53 - Form( 54 - fields: [definition.input, ..inputs], 55 - parse_with: fn(inputs, decoder: form_output) { 56 - // can do let assert because we know there's at least one field since 57 - // we just added one 58 - let assert [input, ..rest] = inputs 59 - case parse_with(rest, decoder), definition.transform(input.value) { 60 - // the form we've already parsed has no errors and the field 61 - // we just parsed has no errors. so we can move on to the next 62 - Ok(next), Ok(value) -> Ok(next(value)) 50 + // // create new form with the new field and update the parse 51 + // // function to handle the new details from the type of the 52 + // // field 53 + // Form( 54 + // fields: [definition.input, ..inputs], 55 + // parse_with: fn(inputs, decoder: form_output) { 56 + // // can do let assert because we know there's at least one field since 57 + // // we just added one 58 + // let assert [input, ..rest] = inputs 59 + // case parse_with(rest, decoder), definition.transform(input.value) { 60 + // // the form we've already parsed has no errors and the field 61 + // // we just parsed has no errors. so we can move on to the next 62 + // Ok(next), Ok(value) -> Ok(next(value)) 63 63 64 - // the form already has errors even though this one succeeded. 65 - // so add this to the list and stop anymore parsing 66 - Error(inputs), Ok(_value) -> Error([input, ..inputs]) 64 + // // the form already has errors even though this one succeeded. 65 + // // so add this to the list and stop anymore parsing 66 + // Error(inputs), Ok(_value) -> Error([input, ..inputs]) 67 67 68 - // form was good so far, but this field errored, so need to 69 - // mark this field as invalid and return all the fields we've got 70 - // so far 71 - Ok(_), Error(error) -> Error([input.set_error(input, error), ..rest]) 68 + // // form was good so far, but this field errored, so need to 69 + // // mark this field as invalid and return all the fields we've got 70 + // // so far 71 + // Ok(_), Error(error) -> Error([input.set_error(input, error), ..rest]) 72 72 73 - // form already has errors and this field errored, so add this field 74 - // to the list 75 - Error(fields), Error(error) -> 76 - Error([input.set_error(input, error), ..fields]) 77 - } 78 - }, 79 - decoder:, 80 - ) 81 - } 73 + // // form already has errors and this field errored, so add this field 74 + // // to the list 75 + // Error(fields), Error(error) -> 76 + // Error([input.set_error(input, error), ..fields]) 77 + // } 78 + // }, 79 + // decoder:, 80 + // ) 81 + // } 82 82 83 - pub fn data( 84 - form: Form(format, a, b, has_decoder), 85 - field: List(#(String, String)), 86 - ) -> Form(format, a, b, has_decoder) { 87 - case form { 88 - Form(fields, parse_with, decoder) -> { 89 - fields 90 - // we always prepend fields, so reverse to get correct order 91 - // TODO I think we're going to make it so order doesn't matter 92 - |> list.reverse 93 - |> do_add_input_data(field, []) 94 - |> Form(parse_with, decoder) 95 - } 96 - // FormWithErrors(..) -> form 97 - } 98 - } 83 + // pub fn data( 84 + // form: Form(format, a, b, has_decoder), 85 + // field: List(#(String, String)), 86 + // ) -> Form(format, a, b, has_decoder) { 87 + // case form { 88 + // Form(fields, parse_with, decoder) -> { 89 + // fields 90 + // // we always prepend fields, so reverse to get correct order 91 + // // TODO I think we're going to make it so order doesn't matter 92 + // |> list.reverse 93 + // |> do_add_input_data(field, []) 94 + // |> Form(parse_with, decoder) 95 + // } 96 + // // FormWithErrors(..) -> form 97 + // } 98 + // } 99 99 100 - fn do_add_input_data( 101 - fields: List(Input(format)), 102 - data: List(#(String, String)), 103 - acc: List(Input(format)), 104 - ) { 105 - case fields, data { 106 - // no more fields, we've return all the fields with data we have accumulated 107 - [], _ -> acc 108 - // no more data! return all the fields we have left plus the ones we accumulated 109 - _, [] -> list.append(fields, acc) 110 - // we have a field and data, and the names match. update field to have data 111 - [Valid(name: field_name, ..) as field, ..fields_rest], 112 - [#(data_name, value), ..data_rest] 113 - if field_name == data_name 114 - -> 115 - do_add_input_data(fields_rest, data_rest, [ 116 - input.set_value(field, value), 117 - ..acc 118 - ]) 119 - // at this point we still have fields and data left, but the first 120 - // field and first data don't match. so we decide we've got no data 121 - // for the first field and move on to the next. but we need to add 122 - // this field without data to the accumulator 123 - [field, ..fields_rest], _ -> 124 - do_add_input_data(fields_rest, data, [field, ..acc]) 125 - } 126 - } 100 + // fn do_add_input_data( 101 + // fields: List(Input(format)), 102 + // data: List(#(String, String)), 103 + // acc: List(Input(format)), 104 + // ) { 105 + // case fields, data { 106 + // // no more fields, we've return all the fields with data we have accumulated 107 + // [], _ -> acc 108 + // // no more data! return all the fields we have left plus the ones we accumulated 109 + // _, [] -> list.append(fields, acc) 110 + // // we have a field and data, and the names match. update field to have data 111 + // [Valid(name: field_name, ..) as field, ..fields_rest], 112 + // [#(data_name, value), ..data_rest] 113 + // if field_name == data_name 114 + // -> 115 + // do_add_input_data(fields_rest, data_rest, [ 116 + // input.set_value(field, value), 117 + // ..acc 118 + // ]) 119 + // // at this point we still have fields and data left, but the first 120 + // // field and first data don't match. so we decide we've got no data 121 + // // for the first field and move on to the next. but we need to add 122 + // // this field without data to the accumulator 123 + // [field, ..fields_rest], _ -> 124 + // do_add_input_data(fields_rest, data, [field, ..acc]) 125 + // } 126 + // } 127 127 128 - pub fn decodes( 129 - form: Form(format, output, decoder, has_decoder), 130 - decoder: decoder, 131 - ) -> Form(format, output, decoder, HasDecoder) { 132 - let Form(fields, parse_with, _) = form 133 - Form(fields, parse_with, Some(decoder)) 134 - } 128 + // pub fn decodes( 129 + // form: Form(format, output, decoder, has_decoder), 130 + // decoder: decoder, 131 + // ) -> Form(format, output, decoder, HasDecoder) { 132 + // let Form(fields, parse_with, _) = form 133 + // Form(fields, parse_with, Some(decoder)) 134 + // } 135 135 136 - pub fn parse( 137 - form: Form(format, output, decoder, HasDecoder), 138 - ) -> Result(output, Form(format, output, decoder, HasDecoder)) { 139 - // we've tagged that we have a decoder with out has_decoder phantom type 140 - // so we can get away with let assert here 141 - let assert Form(fields, parse_with, Some(decoder)) = form 142 - case parse_with(fields, decoder) { 143 - Ok(output) -> Ok(output) 144 - Error(fields) -> Error(Form(fields, parse_with, Some(decoder))) 145 - } 146 - } 136 + // pub fn parse( 137 + // form: Form(format, output, decoder, HasDecoder), 138 + // ) -> Result(output, Form(format, output, decoder, HasDecoder)) { 139 + // // we've tagged that we have a decoder with out has_decoder phantom type 140 + // // so we can get away with let assert here 141 + // let assert Form(fields, parse_with, Some(decoder)) = form 142 + // case parse_with(fields, decoder) { 143 + // Ok(output) -> Ok(output) 144 + // Error(fields) -> Error(Form(fields, parse_with, Some(decoder))) 145 + // } 146 + // } 147 147 148 - pub fn try( 149 - form: Form(format, output, decoder, HasDecoder), 150 - apply fun: fn(output, Form(format, output, decoder, HasDecoder)) -> 151 - Result(c, Form(format, output, decoder, HasDecoder)), 152 - ) -> Result(c, Form(format, output, decoder, HasDecoder)) { 153 - parse(form) |> result.try(fun(_, form)) 154 - } 148 + // pub fn try( 149 + // form: Form(format, output, decoder, HasDecoder), 150 + // apply fun: fn(output, Form(format, output, decoder, HasDecoder)) -> 151 + // Result(c, Form(format, output, decoder, HasDecoder)), 152 + // ) -> Result(c, Form(format, output, decoder, HasDecoder)) { 153 + // parse(form) |> result.try(fun(_, form)) 154 + // } 155 155 156 - pub fn get_inputs(form: Form(format, a, b, has_decoder)) -> List(Input(format)) { 157 - form.fields |> list.reverse 158 - } 156 + // pub fn get_inputs(form: Form(format, a, b, has_decoder)) -> List(Input(format)) { 157 + // form.fields |> list.reverse 158 + // } 159 159 160 - pub fn update_input( 161 - form: Form(format, output, decoder, has_decoder), 162 - name: String, 163 - fun: fn(Input(format)) -> Input(format), 164 - ) -> Form(format, output, decoder, has_decoder) { 165 - form.fields 166 - |> list.map(fn(field) { 167 - case field.name == name { 168 - True -> fun(field) 169 - False -> field 170 - } 171 - }) 172 - |> Form(form.parse_with, form.decoder) 173 - } 160 + // pub fn update_input( 161 + // form: Form(format, output, decoder, has_decoder), 162 + // name: String, 163 + // fun: fn(Input(format)) -> Input(format), 164 + // ) -> Form(format, output, decoder, has_decoder) { 165 + // form.fields 166 + // |> list.map(fn(field) { 167 + // case field.name == name { 168 + // True -> fun(field) 169 + // False -> field 170 + // } 171 + // }) 172 + // |> Form(form.parse_with, form.decoder) 173 + // }
+32 -28
formz/src/formz/formz_use.gleam
··· 1 - import formz/field.{type Field} 2 - import formz/input.{type Input} 1 + import formz/field.{type Definition, type Field} 3 2 import gleam/dict 4 3 import gleam/list 5 4 import gleam/result ··· 13 12 } 14 13 15 14 pub type FormItem(format) { 16 - Item(input: Input(format)) 15 + Item(input: Field(format)) 17 16 Set(Fieldset(format), items: List(FormItem(format))) 18 17 } 19 18 ··· 21 20 Fieldset(prefix: String, label: String) 22 21 } 23 22 23 + pub fn create_form(thing: thing) -> Form(format, thing) { 24 + Form([], fn(_) { Ok(thing) }, thing) 25 + } 26 + 24 27 pub fn with( 25 - field: Field(format, input_output), 28 + field: Field(format), 29 + definition: Definition(format, input_output), 26 30 fun: fn(input_output) -> Form(format, form_output), 27 31 ) -> Form(format, form_output) { 28 32 // we pass in our placeholder value, and we're going to throw away the 29 33 // decoded result here, we just care about pulling out the fields 30 34 // from the form. 31 - let next = fun(field.placeholder) 35 + let next = fun(definition.placeholder) 36 + 37 + let field = field |> field.set_widget(definition.widget) 32 38 33 39 // prepend the new input to the inputs from the form we got in the 34 40 // previous step. 35 - let updated_inputs = [Item(field.input), ..next.items] 41 + let updated_inputs = [Item(field), ..next.items] 36 42 37 43 // now create the parse function. parse function accepts most recent 38 44 // version of input list, since data can be added to it. the list ··· 42 48 let assert Ok(#(Item(input), next_inputs)) = next_item(inputs) 43 49 44 50 // transform the input data using the transform/validate/decode/etc function 45 - let input_output = field.transform(input.value) 51 + let input_output = definition.transform(input.value) 46 52 47 53 // pass our transformed input data to the next function/form. if 48 54 // we errored we still do this with our placeholder so we can continue 49 55 // processing all the fields in the form. we will return a form 50 56 // with an error, so if we're on the error track we'll throw away 51 57 // the "output" made with this and just keep the errors. 52 - let next_form = fun(input_output |> result.unwrap(field.placeholder)) 58 + let next_form = fun(input_output |> result.unwrap(definition.placeholder)) 53 59 let form_output = next_form.parse(next_inputs) 54 60 55 61 // ok, check which track we're on ··· 66 72 // so far 67 73 Ok(_), Error(error) -> 68 74 input 69 - |> input.set_error(error) 75 + |> field.set_error(error) 70 76 |> Item 71 77 |> list.prepend(next_inputs, _) 72 78 |> Error ··· 75 81 // to the list of errors 76 82 Error(fields), Error(error) -> 77 83 input 78 - |> input.set_error(error) 84 + |> field.set_error(error) 79 85 |> Item 80 86 |> list.prepend(fields, _) 81 87 |> Error ··· 94 100 95 101 let sub_inputs = 96 102 sub.items 97 - |> map_items(fn(item) { item |> input.set_name(prefix <> "." <> item.name) }) 103 + |> map_inputs(fn(input) { 104 + input |> field.set_name(prefix <> "." <> input.name) 105 + }) 98 106 99 107 let updated_inputs = [Set(Fieldset(prefix, name), sub_inputs), ..next.items] 100 108 ··· 144 152 } 145 153 } 146 154 147 - fn map_items( 155 + fn map_inputs( 148 156 items: List(FormItem(format)), 149 - fun: fn(Input(format)) -> Input(format), 157 + fun: fn(Field(format)) -> Field(format), 150 158 ) -> List(FormItem(format)) { 151 159 list.map(items, fn(item) { 152 160 case item { 153 161 Item(input) -> Item(fun(input)) 154 - Set(s, items) -> Set(s, map_items(items, fun)) 162 + Set(s, items) -> Set(s, map_inputs(items, fun)) 155 163 } 156 164 }) 157 165 } ··· 173 181 input_data: List(#(String, String)), 174 182 ) -> Form(format, output) { 175 183 let data = dict.from_list(input_data) 176 - let Form(inputs, parse, placeholder) = form 177 - inputs 178 - |> map_items(fn(input) { 179 - case dict.get(data, input.name) { 180 - Ok(value) -> input.set_value(input, value) 181 - Error(_) -> input 184 + let Form(items, parse, placeholder) = form 185 + items 186 + |> map_inputs(fn(field) { 187 + case dict.get(data, field.name) { 188 + Ok(value) -> field.set_value(field, value) 189 + Error(_) -> field 182 190 } 183 191 }) 184 192 |> Form(parse, placeholder) 185 - } 186 - 187 - pub fn create_form(thing: thing) -> Form(format, thing) { 188 - Form([], fn(_) { Ok(thing) }, thing) 189 193 } 190 194 191 195 pub fn parse(form: Form(format, output)) -> Result(output, Form(format, output)) { ··· 235 239 pub fn get_input( 236 240 form: Form(format, output), 237 241 name: String, 238 - ) -> Result(Input(format), Nil) { 242 + ) -> Result(Field(format), Nil) { 239 243 form 240 244 |> get_inputs 241 245 |> list.filter(fn(input) { input.name == name }) ··· 245 249 pub fn map_input( 246 250 form: Form(format, output), 247 251 name: String, 248 - fun: fn(Input(format)) -> a, 252 + fun: fn(Field(format)) -> a, 249 253 ) -> Result(a, Nil) { 250 254 form |> get_input(name) |> result.map(fun) 251 255 } ··· 253 257 pub fn update_input( 254 258 form: Form(format, output), 255 259 name: String, 256 - fun: fn(Input(format)) -> Input(format), 260 + fun: fn(Field(format)) -> Field(format), 257 261 ) -> Form(format, output) { 258 262 form.items 259 - |> map_items(fn(field) { 263 + |> map_inputs(fn(field) { 260 264 case field.name == name { 261 265 True -> fun(field) 262 266 False -> field
-413
formz/src/formz/input.gleam
··· 1 - pub type Input(format) { 2 - Valid( 3 - name: String, 4 - label: String, 5 - help_text: String, 6 - disabled: Bool, 7 - required: Bool, 8 - widget: Widget(format), 9 - hidden: Bool, 10 - value: String, 11 - ) 12 - Invalid( 13 - name: String, 14 - label: String, 15 - help_text: String, 16 - disabled: Bool, 17 - required: Bool, 18 - widget: Widget(format), 19 - hidden: Bool, 20 - value: String, 21 - error: String, 22 - ) 23 - } 24 - 25 - pub type Widget(format) = 26 - fn(Input(format), WidgetArgs) -> format 27 - 28 - pub type WidgetArgs { 29 - WidgetArgs(id: String, labelled_by: InputLabelled) 30 - } 31 - 32 - pub type InputLabelled { 33 - Element 34 - Value 35 - Id(element_id: String) 36 - } 37 - 38 - pub fn set_name(field: Input(format), name: String) -> Input(format) { 39 - case field { 40 - Valid( 41 - _name, 42 - label:, 43 - help_text:, 44 - widget:, 45 - hidden:, 46 - value:, 47 - disabled:, 48 - required:, 49 - ) -> 50 - Valid( 51 - name:, 52 - label:, 53 - help_text:, 54 - widget:, 55 - hidden:, 56 - value:, 57 - disabled:, 58 - required:, 59 - ) 60 - Invalid( 61 - _name, 62 - label:, 63 - help_text:, 64 - widget:, 65 - hidden:, 66 - disabled:, 67 - required:, 68 - value:, 69 - error:, 70 - ) -> 71 - Invalid( 72 - name:, 73 - label:, 74 - help_text:, 75 - widget:, 76 - hidden:, 77 - value:, 78 - error:, 79 - disabled:, 80 - required:, 81 - ) 82 - } 83 - } 84 - 85 - pub fn set_label(field: Input(format), label: String) -> Input(format) { 86 - case field { 87 - Valid( 88 - _label, 89 - name:, 90 - help_text:, 91 - widget:, 92 - hidden:, 93 - value:, 94 - disabled:, 95 - required:, 96 - ) -> 97 - Valid( 98 - name:, 99 - label:, 100 - help_text:, 101 - widget:, 102 - hidden:, 103 - value:, 104 - disabled:, 105 - required:, 106 - ) 107 - Invalid( 108 - _label, 109 - name:, 110 - help_text:, 111 - widget:, 112 - hidden:, 113 - disabled:, 114 - required:, 115 - value:, 116 - error:, 117 - ) -> 118 - Invalid( 119 - name:, 120 - label:, 121 - help_text:, 122 - widget:, 123 - hidden:, 124 - value:, 125 - error:, 126 - disabled:, 127 - required:, 128 - ) 129 - } 130 - } 131 - 132 - pub fn set_help_text(field: Input(format), help_text: String) -> Input(format) { 133 - case field { 134 - Valid( 135 - _help_text, 136 - name:, 137 - label:, 138 - widget:, 139 - hidden:, 140 - value:, 141 - disabled:, 142 - required:, 143 - ) -> 144 - Valid( 145 - name:, 146 - label:, 147 - help_text:, 148 - widget:, 149 - hidden:, 150 - value:, 151 - disabled:, 152 - required:, 153 - ) 154 - Invalid( 155 - _help_text, 156 - name:, 157 - label:, 158 - widget:, 159 - hidden:, 160 - disabled:, 161 - required:, 162 - value:, 163 - error:, 164 - ) -> 165 - Invalid( 166 - name:, 167 - label:, 168 - help_text:, 169 - widget:, 170 - hidden:, 171 - value:, 172 - error:, 173 - disabled:, 174 - required:, 175 - ) 176 - } 177 - } 178 - 179 - pub fn set_widget(field: Input(format), widget: Widget(format)) -> Input(format) { 180 - case field { 181 - Valid( 182 - _widget, 183 - name:, 184 - label:, 185 - help_text:, 186 - hidden:, 187 - value:, 188 - disabled:, 189 - required:, 190 - ) -> 191 - Valid( 192 - name:, 193 - label:, 194 - help_text:, 195 - widget:, 196 - hidden:, 197 - value:, 198 - disabled:, 199 - required:, 200 - ) 201 - Invalid( 202 - _widget, 203 - name:, 204 - label:, 205 - help_text:, 206 - hidden:, 207 - disabled:, 208 - required:, 209 - value:, 210 - error:, 211 - ) -> 212 - Invalid( 213 - name:, 214 - label:, 215 - help_text:, 216 - widget:, 217 - hidden:, 218 - value:, 219 - error:, 220 - disabled:, 221 - required:, 222 - ) 223 - } 224 - } 225 - 226 - pub fn set_hidden(field: Input(format), hidden: Bool) -> Input(format) { 227 - case field { 228 - Valid( 229 - _hidden, 230 - name:, 231 - label:, 232 - help_text:, 233 - widget:, 234 - value:, 235 - disabled:, 236 - required:, 237 - ) -> 238 - Valid( 239 - name:, 240 - label:, 241 - help_text:, 242 - widget:, 243 - hidden:, 244 - value:, 245 - disabled:, 246 - required:, 247 - ) 248 - Invalid( 249 - _hidden, 250 - name:, 251 - label:, 252 - help_text:, 253 - widget:, 254 - disabled:, 255 - required:, 256 - value:, 257 - error:, 258 - ) -> 259 - Invalid( 260 - name:, 261 - label:, 262 - help_text:, 263 - widget:, 264 - hidden:, 265 - value:, 266 - error:, 267 - disabled:, 268 - required:, 269 - ) 270 - } 271 - } 272 - 273 - pub fn set_disabled(field: Input(format), disabled: Bool) -> Input(format) { 274 - case field { 275 - Valid( 276 - _disabled, 277 - name:, 278 - label:, 279 - help_text:, 280 - widget:, 281 - value:, 282 - hidden:, 283 - required:, 284 - ) -> 285 - Valid( 286 - name:, 287 - label:, 288 - help_text:, 289 - widget:, 290 - hidden:, 291 - value:, 292 - disabled:, 293 - required:, 294 - ) 295 - Invalid( 296 - _disabled, 297 - name:, 298 - label:, 299 - help_text:, 300 - widget:, 301 - hidden:, 302 - required:, 303 - value:, 304 - error:, 305 - ) -> 306 - Invalid( 307 - name:, 308 - label:, 309 - help_text:, 310 - widget:, 311 - hidden:, 312 - value:, 313 - error:, 314 - disabled:, 315 - required:, 316 - ) 317 - } 318 - } 319 - 320 - pub fn set_value(field: Input(format), value: String) -> Input(format) { 321 - case field { 322 - Valid( 323 - _value, 324 - name:, 325 - label:, 326 - help_text:, 327 - widget:, 328 - hidden:, 329 - disabled:, 330 - required:, 331 - ) -> 332 - Valid( 333 - name:, 334 - label:, 335 - help_text:, 336 - widget:, 337 - hidden:, 338 - value:, 339 - disabled:, 340 - required:, 341 - ) 342 - Invalid( 343 - _value, 344 - name:, 345 - label:, 346 - help_text:, 347 - widget:, 348 - hidden:, 349 - disabled:, 350 - required:, 351 - error:, 352 - ) -> 353 - Invalid( 354 - name:, 355 - label:, 356 - help_text:, 357 - widget:, 358 - hidden:, 359 - value:, 360 - error:, 361 - disabled:, 362 - required:, 363 - ) 364 - } 365 - } 366 - 367 - pub fn set_error(field: Input(format), error: String) -> Input(format) { 368 - case field { 369 - Valid( 370 - name:, 371 - label:, 372 - help_text:, 373 - widget:, 374 - hidden:, 375 - value:, 376 - disabled:, 377 - required:, 378 - ) -> 379 - Invalid( 380 - name:, 381 - label:, 382 - help_text:, 383 - widget:, 384 - hidden:, 385 - value:, 386 - disabled:, 387 - required:, 388 - error:, 389 - ) 390 - Invalid( 391 - _error, 392 - name:, 393 - label:, 394 - help_text:, 395 - widget:, 396 - hidden:, 397 - disabled:, 398 - required:, 399 - value:, 400 - ) -> 401 - Invalid( 402 - name:, 403 - label:, 404 - help_text:, 405 - widget:, 406 - hidden:, 407 - value:, 408 - error:, 409 - disabled:, 410 - required:, 411 - ) 412 - } 413 - }
+227 -227
formz/test/formz/formz_pipes_test.gleam
··· 1 - import formz/field.{field} 2 - import formz/formz_pipes as formz 3 - import formz/input 4 - import formz/string_generator/fields 5 - import gleam/list 6 - import gleeunit 7 - import gleeunit/should 1 + // import formz/field.{field} 2 + // import formz/formz_pipes as formz 3 + // import formz/input 4 + // import formz/string_generator/fields 5 + // import gleam/list 6 + // import gleeunit 7 + // import gleeunit/should 8 8 9 - pub fn main() { 10 - gleeunit.main() 11 - } 9 + // pub fn main() { 10 + // gleeunit.main() 11 + // } 12 12 13 - pub fn empty_form_test() { 14 - formz.new() 15 - |> formz.get_inputs 16 - |> list.length 17 - |> should.equal(0) 18 - } 13 + // pub fn empty_form_test() { 14 + // formz.new() 15 + // |> formz.get_inputs 16 + // |> list.length 17 + // |> should.equal(0) 18 + // } 19 19 20 - pub fn parse_empty_form_test() { 21 - formz.new() 22 - |> formz.data([]) 23 - |> formz.decodes(1) 24 - |> formz.parse 25 - |> should.equal(Ok(1)) 20 + // pub fn parse_empty_form_test() { 21 + // formz.new() 22 + // |> formz.data([]) 23 + // |> formz.decodes(1) 24 + // |> formz.parse 25 + // |> should.equal(Ok(1)) 26 26 27 - formz.new() 28 - |> formz.data([]) 29 - |> formz.decodes("Hello") 30 - |> formz.parse 31 - |> should.equal(Ok("Hello")) 32 - } 27 + // formz.new() 28 + // |> formz.data([]) 29 + // |> formz.decodes("Hello") 30 + // |> formz.parse 31 + // |> should.equal(Ok("Hello")) 32 + // } 33 33 34 - pub fn parse_single_field_form_test() { 35 - formz.new() 36 - |> formz.add(field("first", fields.text_field())) 37 - |> formz.data([#("first", "world")]) 38 - |> formz.decodes(fn(str) { "hello " <> str }) 39 - |> formz.parse 40 - |> should.equal(Ok("hello world")) 41 - } 34 + // pub fn parse_single_field_form_test() { 35 + // formz.new() 36 + // |> formz.add(field("first", fields.text_field())) 37 + // |> formz.data([#("first", "world")]) 38 + // |> formz.decodes(fn(str) { "hello " <> str }) 39 + // |> formz.parse 40 + // |> should.equal(Ok("hello world")) 41 + // } 42 42 43 - pub fn parse_double_field_form_test() { 44 - formz.new() 45 - |> formz.add(field("first", fields.text_field())) 46 - |> formz.add(field("second", fields.text_field())) 47 - |> formz.data([#("first", "hello"), #("second", "world")]) 48 - |> formz.decodes(fn(a) { fn(b) { a <> " " <> b } }) 49 - |> formz.parse 50 - |> should.equal(Ok("hello world")) 51 - } 43 + // pub fn parse_double_field_form_test() { 44 + // formz.new() 45 + // |> formz.add(field("first", fields.text_field())) 46 + // |> formz.add(field("second", fields.text_field())) 47 + // |> formz.data([#("first", "hello"), #("second", "world")]) 48 + // |> formz.decodes(fn(a) { fn(b) { a <> " " <> b } }) 49 + // |> formz.parse 50 + // |> should.equal(Ok("hello world")) 51 + // } 52 52 53 - pub fn parse_double_field_form_extra_data_test() { 54 - formz.new() 55 - |> formz.add(field("first", fields.text_field())) 56 - |> formz.add(field("second", fields.text_field())) 57 - |> formz.data([#("first", "1"), #("second", "2")]) 58 - |> formz.decodes(fn(a) { fn(b) { a <> " " <> b } }) 59 - |> formz.parse 60 - |> should.equal(Ok("1 2")) 53 + // pub fn parse_double_field_form_extra_data_test() { 54 + // formz.new() 55 + // |> formz.add(field("first", fields.text_field())) 56 + // |> formz.add(field("second", fields.text_field())) 57 + // |> formz.data([#("first", "1"), #("second", "2")]) 58 + // |> formz.decodes(fn(a) { fn(b) { a <> " " <> b } }) 59 + // |> formz.parse 60 + // |> should.equal(Ok("1 2")) 61 61 62 - formz.new() 63 - |> formz.add(field("first", fields.text_field())) 64 - |> formz.add(field("second", fields.text_field())) 65 - |> formz.data([#("first", "1"), #("second", "2"), #("second", "3")]) 66 - |> formz.decodes(fn(a) { fn(b) { a <> " " <> b } }) 67 - |> formz.parse 68 - |> should.equal(Ok("1 2")) 69 - } 62 + // formz.new() 63 + // |> formz.add(field("first", fields.text_field())) 64 + // |> formz.add(field("second", fields.text_field())) 65 + // |> formz.data([#("first", "1"), #("second", "2"), #("second", "3")]) 66 + // |> formz.decodes(fn(a) { fn(b) { a <> " " <> b } }) 67 + // |> formz.parse 68 + // |> should.equal(Ok("1 2")) 69 + // } 70 70 71 - pub fn integer_field_test() { 72 - formz.new() 73 - |> formz.add(field("first", fields.integer_field())) 74 - |> formz.data([#("first", " 1 ")]) 75 - |> formz.decodes(fn(i) { i }) 76 - |> formz.parse 77 - |> should.equal(Ok(1)) 78 - } 71 + // pub fn integer_field_test() { 72 + // formz.new() 73 + // |> formz.add(field("first", fields.integer_field())) 74 + // |> formz.data([#("first", " 1 ")]) 75 + // |> formz.decodes(fn(i) { i }) 76 + // |> formz.parse 77 + // |> should.equal(Ok(1)) 78 + // } 79 79 80 - pub fn can_decodes_in_any_order_test() { 81 - formz.new() 82 - |> formz.decodes(fn(str) { "hello " <> str }) 83 - |> formz.add(field("first", fields.text_field())) 84 - |> formz.data([#("first", "world")]) 85 - |> formz.parse 86 - |> should.equal(Ok("hello world")) 80 + // pub fn can_decodes_in_any_order_test() { 81 + // formz.new() 82 + // |> formz.decodes(fn(str) { "hello " <> str }) 83 + // |> formz.add(field("first", fields.text_field())) 84 + // |> formz.data([#("first", "world")]) 85 + // |> formz.parse 86 + // |> should.equal(Ok("hello world")) 87 87 88 - formz.new() 89 - |> formz.add(field("first", fields.text_field())) 90 - |> formz.data([#("first", "world")]) 91 - |> formz.decodes(fn(str) { "hello " <> str }) 92 - |> formz.parse 93 - |> should.equal(Ok("hello world")) 94 - } 88 + // formz.new() 89 + // |> formz.add(field("first", fields.text_field())) 90 + // |> formz.data([#("first", "world")]) 91 + // |> formz.decodes(fn(str) { "hello " <> str }) 92 + // |> formz.parse 93 + // |> should.equal(Ok("hello world")) 94 + // } 95 95 96 - pub fn parse_single_field_form_with_error_test() { 97 - let assert Error(f) = 98 - formz.new() 99 - |> formz.add(field("first", fields.integer_field())) 100 - |> formz.data([#("first", "world")]) 101 - |> formz.decodes(fn(_) { 1 }) 102 - |> formz.parse 96 + // pub fn parse_single_field_form_with_error_test() { 97 + // let assert Error(f) = 98 + // formz.new() 99 + // |> formz.add(field("first", fields.integer_field())) 100 + // |> formz.data([#("first", "world")]) 101 + // |> formz.decodes(fn(_) { 1 }) 102 + // |> formz.parse 103 103 104 - let assert [field] = formz.get_inputs(f) 105 - field |> should_be_field_with_error("Must be a whole number") 106 - } 104 + // let assert [field] = formz.get_inputs(f) 105 + // field |> should_be_field_with_error("Must be a whole number") 106 + // } 107 107 108 - pub fn parse_double_field_form_with_error_test() { 109 - let form = 110 - formz.new() 111 - |> formz.add(field("a", fields.integer_field())) 112 - |> formz.add(field("b", fields.integer_field())) 113 - |> formz.decodes(fn(_) { fn(_) { 1 } }) 108 + // pub fn parse_double_field_form_with_error_test() { 109 + // let form = 110 + // formz.new() 111 + // |> formz.add(field("a", fields.integer_field())) 112 + // |> formz.add(field("b", fields.integer_field())) 113 + // |> formz.decodes(fn(_) { fn(_) { 1 } }) 114 114 115 - let assert Error(f) = 116 - form 117 - |> formz.data([#("a", "not a number"), #("b", "2")]) 118 - |> formz.parse 115 + // let assert Error(f) = 116 + // form 117 + // |> formz.data([#("a", "not a number"), #("b", "2")]) 118 + // |> formz.parse 119 119 120 - let assert [fielda, fieldb] = formz.get_inputs(f) 121 - fielda |> should_be_field_with_error("Must be a whole number") 122 - fieldb |> should_be_field_no_error 120 + // let assert [fielda, fieldb] = formz.get_inputs(f) 121 + // fielda |> should_be_field_with_error("Must be a whole number") 122 + // fieldb |> should_be_field_no_error 123 123 124 - let assert Error(f) = 125 - form 126 - |> formz.data([#("a", "1"), #("b", "string")]) 127 - |> formz.parse 124 + // let assert Error(f) = 125 + // form 126 + // |> formz.data([#("a", "1"), #("b", "string")]) 127 + // |> formz.parse 128 128 129 - let assert [fielda, fieldb] = formz.get_inputs(f) 130 - fielda |> should_be_field_no_error 131 - fieldb |> should_be_field_with_error("Must be a whole number") 129 + // let assert [fielda, fieldb] = formz.get_inputs(f) 130 + // fielda |> should_be_field_no_error 131 + // fieldb |> should_be_field_with_error("Must be a whole number") 132 132 133 - let assert Error(f) = 134 - form 135 - |> formz.data([#("a", "string"), #("b", "string")]) 136 - |> formz.parse 133 + // let assert Error(f) = 134 + // form 135 + // |> formz.data([#("a", "string"), #("b", "string")]) 136 + // |> formz.parse 137 137 138 - let assert [fielda, fieldb] = formz.get_inputs(f) 139 - fielda |> should_be_field_with_error("Must be a whole number") 140 - fieldb |> should_be_field_with_error("Must be a whole number") 141 - } 138 + // let assert [fielda, fieldb] = formz.get_inputs(f) 139 + // fielda |> should_be_field_with_error("Must be a whole number") 140 + // fieldb |> should_be_field_with_error("Must be a whole number") 141 + // } 142 142 143 - pub fn parse_triple_field_form_with_error_test() { 144 - let form = 145 - formz.new() 146 - |> formz.add(field("a", fields.integer_field())) 147 - |> formz.add(field("b", fields.integer_field())) 148 - |> formz.add(field("c", fields.integer_field())) 149 - |> formz.decodes(fn(_) { fn(_) { fn(_) { 1 } } }) 143 + // pub fn parse_triple_field_form_with_error_test() { 144 + // let form = 145 + // formz.new() 146 + // |> formz.add(field("a", fields.integer_field())) 147 + // |> formz.add(field("b", fields.integer_field())) 148 + // |> formz.add(field("c", fields.integer_field())) 149 + // |> formz.decodes(fn(_) { fn(_) { fn(_) { 1 } } }) 150 150 151 - let assert Error(f) = 152 - form 153 - |> formz.data([#("a", "1"), #("b", "2"), #("c", "string")]) 154 - |> formz.parse 155 - let assert [fielda, fieldb, fieldc] = formz.get_inputs(f) 156 - fielda |> should_be_field_no_error 157 - fieldb |> should_be_field_no_error 158 - fieldc |> should_be_field_with_error("Must be a whole number") 151 + // let assert Error(f) = 152 + // form 153 + // |> formz.data([#("a", "1"), #("b", "2"), #("c", "string")]) 154 + // |> formz.parse 155 + // let assert [fielda, fieldb, fieldc] = formz.get_inputs(f) 156 + // fielda |> should_be_field_no_error 157 + // fieldb |> should_be_field_no_error 158 + // fieldc |> should_be_field_with_error("Must be a whole number") 159 159 160 - let assert Error(f) = 161 - form 162 - |> formz.data([#("a", "1"), #("b", "string"), #("c", "string")]) 163 - |> formz.parse 164 - let assert [fielda, fieldb, fieldc] = formz.get_inputs(f) 165 - fielda |> should_be_field_no_error 166 - fieldb |> should_be_field_with_error("Must be a whole number") 167 - fieldc |> should_be_field_with_error("Must be a whole number") 160 + // let assert Error(f) = 161 + // form 162 + // |> formz.data([#("a", "1"), #("b", "string"), #("c", "string")]) 163 + // |> formz.parse 164 + // let assert [fielda, fieldb, fieldc] = formz.get_inputs(f) 165 + // fielda |> should_be_field_no_error 166 + // fieldb |> should_be_field_with_error("Must be a whole number") 167 + // fieldc |> should_be_field_with_error("Must be a whole number") 168 168 169 - let assert Error(f) = 170 - form 171 - |> formz.data([#("a", "1"), #("b", "string"), #("c", "3")]) 172 - |> formz.parse 173 - let assert [fielda, fieldb, fieldc] = formz.get_inputs(f) 174 - fielda |> should_be_field_no_error 175 - fieldb |> should_be_field_with_error("Must be a whole number") 176 - fieldc |> should_be_field_no_error 169 + // let assert Error(f) = 170 + // form 171 + // |> formz.data([#("a", "1"), #("b", "string"), #("c", "3")]) 172 + // |> formz.parse 173 + // let assert [fielda, fieldb, fieldc] = formz.get_inputs(f) 174 + // fielda |> should_be_field_no_error 175 + // fieldb |> should_be_field_with_error("Must be a whole number") 176 + // fieldc |> should_be_field_no_error 177 177 178 - let assert Error(f) = 179 - form 180 - |> formz.data([#("a", "string"), #("b", "string"), #("c", "3")]) 181 - |> formz.parse 182 - let assert [fielda, fieldb, fieldc] = formz.get_inputs(f) 183 - fielda |> should_be_field_with_error("Must be a whole number") 184 - fieldb |> should_be_field_with_error("Must be a whole number") 185 - fieldc |> should_be_field_no_error 178 + // let assert Error(f) = 179 + // form 180 + // |> formz.data([#("a", "string"), #("b", "string"), #("c", "3")]) 181 + // |> formz.parse 182 + // let assert [fielda, fieldb, fieldc] = formz.get_inputs(f) 183 + // fielda |> should_be_field_with_error("Must be a whole number") 184 + // fieldb |> should_be_field_with_error("Must be a whole number") 185 + // fieldc |> should_be_field_no_error 186 186 187 - let assert Error(f) = 188 - form 189 - |> formz.data([#("a", "string"), #("b", "2"), #("c", "3")]) 190 - |> formz.parse 191 - let assert [fielda, fieldb, fieldc] = formz.get_inputs(f) 192 - fielda |> should_be_field_with_error("Must be a whole number") 193 - fieldb |> should_be_field_no_error 194 - fieldc |> should_be_field_no_error 195 - } 187 + // let assert Error(f) = 188 + // form 189 + // |> formz.data([#("a", "string"), #("b", "2"), #("c", "3")]) 190 + // |> formz.parse 191 + // let assert [fielda, fieldb, fieldc] = formz.get_inputs(f) 192 + // fielda |> should_be_field_with_error("Must be a whole number") 193 + // fieldb |> should_be_field_no_error 194 + // fieldc |> should_be_field_no_error 195 + // } 196 196 197 - fn should_be_field_no_error(field: input.Input(String)) { 198 - should.equal( 199 - field, 200 - input.Valid( 201 - name: field.name, 202 - label: field.label, 203 - help_text: field.help_text, 204 - value: field.value, 205 - widget: field.widget, 206 - hidden: field.hidden, 207 - disabled: field.disabled, 208 - required: field.required, 209 - ), 210 - ) 211 - } 197 + // fn should_be_field_no_error(field: input.Input(String)) { 198 + // should.equal( 199 + // field, 200 + // input.Valid( 201 + // name: field.name, 202 + // label: field.label, 203 + // help_text: field.help_text, 204 + // value: field.value, 205 + // widget: field.widget, 206 + // hidden: field.hidden, 207 + // disabled: field.disabled, 208 + // required: field.required, 209 + // ), 210 + // ) 211 + // } 212 212 213 - fn should_be_field_with_error(field: input.Input(String), str: String) { 214 - should.equal( 215 - field, 216 - input.Invalid( 217 - name: field.name, 218 - label: field.label, 219 - help_text: field.help_text, 220 - value: field.value, 221 - widget: field.widget, 222 - hidden: field.hidden, 223 - error: str, 224 - disabled: field.disabled, 225 - required: field.required, 226 - ), 227 - ) 228 - } 213 + // fn should_be_field_with_error(field: input.Input(String), str: String) { 214 + // should.equal( 215 + // field, 216 + // input.Invalid( 217 + // name: field.name, 218 + // label: field.label, 219 + // help_text: field.help_text, 220 + // value: field.value, 221 + // widget: field.widget, 222 + // hidden: field.hidden, 223 + // error: str, 224 + // disabled: field.disabled, 225 + // required: field.required, 226 + // ), 227 + // ) 228 + // } 229 229 230 - pub fn try_test() { 231 - let f = 232 - formz.new() 233 - |> formz.add(field("a", fields.integer_field())) 234 - |> formz.add(field("b", fields.integer_field())) 235 - |> formz.add(field("c", fields.integer_field())) 236 - |> formz.decodes(fn(a) { fn(b) { fn(c) { [a, b, c] } } }) 237 - |> formz.data([#("a", "1"), #("b", "2"), #("c", "3")]) 230 + // pub fn try_test() { 231 + // let f = 232 + // formz.new() 233 + // |> formz.add(field("a", fields.integer_field())) 234 + // |> formz.add(field("b", fields.integer_field())) 235 + // |> formz.add(field("c", fields.integer_field())) 236 + // |> formz.decodes(fn(a) { fn(b) { fn(c) { [a, b, c] } } }) 237 + // |> formz.data([#("a", "1"), #("b", "2"), #("c", "3")]) 238 238 239 - // can succeed 240 - formz.try(f, fn(_, _) { Ok(3) }) 241 - |> should.equal(Ok(3)) 239 + // // can succeed 240 + // formz.try(f, fn(_, _) { Ok(3) }) 241 + // |> should.equal(Ok(3)) 242 242 243 - // can change type 244 - formz.try(f, fn(_, _) { Ok("it worked") }) 245 - |> should.equal(Ok("it worked")) 243 + // // can change type 244 + // formz.try(f, fn(_, _) { Ok("it worked") }) 245 + // |> should.equal(Ok("it worked")) 246 246 247 - // can error 248 - formz.try(f, fn(_, form) { Error(form) }) 249 - |> should.equal(Error(f)) 247 + // // can error 248 + // formz.try(f, fn(_, form) { Error(form) }) 249 + // |> should.equal(Error(f)) 250 250 251 - // can change field 252 - let assert Error(form) = 253 - formz.try(f, fn(_, form) { 254 - Error(formz.update_input(form, "a", input.set_error(_, "woops"))) 255 - }) 256 - let assert [fielda, fieldb, fieldc] = formz.get_inputs(form) 257 - fielda |> should_be_field_with_error("woops") 258 - fieldb |> should_be_field_no_error 259 - fieldc |> should_be_field_no_error 260 - } 251 + // // can change field 252 + // let assert Error(form) = 253 + // formz.try(f, fn(_, form) { 254 + // Error(formz.update_input(form, "a", input.set_error(_, "woops"))) 255 + // }) 256 + // let assert [fielda, fieldb, fieldc] = formz.get_inputs(form) 257 + // fielda |> should_be_field_with_error("woops") 258 + // fieldb |> should_be_field_no_error 259 + // fieldc |> should_be_field_no_error 260 + // }
+73 -54
formz/test/formz/formz_use_test.gleam
··· 1 + import formz/definition 1 2 import formz/field.{field} 2 3 import formz/formz_use.{Item, Set} as formz 3 - import formz/input 4 - import formz/string_generator/fields 5 4 import formz/validation 5 + import gleam/io 6 6 import gleam/option 7 7 import gleeunit 8 8 import gleeunit/should 9 9 10 - fn should_be_field_no_error(field: input.Input(String)) { 10 + pub fn text_field() { 11 + field.Definition(field.widget(fn(_, _) { "" }), validation.string, "") 12 + } 13 + 14 + pub fn int_field() { 15 + field.Definition(field.widget(fn(_, _) { "" }), validation.int, 0) 16 + } 17 + 18 + pub fn float_field() { 19 + field.Definition(field.widget(fn(_, _) { "" }), validation.number, 0.0) 20 + } 21 + 22 + fn should_be_field_no_error(field: field.Field(String)) { 11 23 should.equal( 12 24 field, 13 - input.Valid( 25 + field.Valid( 14 26 name: field.name, 15 27 label: field.label, 16 28 help_text: field.help_text, ··· 23 35 ) 24 36 } 25 37 26 - fn should_be_field_with_error(field: input.Input(String), str: String) { 38 + fn should_be_field_with_error(field: field.Field(String), str: String) { 27 39 should.equal( 28 40 field, 29 - input.Invalid( 41 + field.Invalid( 30 42 name: field.name, 31 43 label: field.label, 32 44 help_text: field.help_text, ··· 56 68 } 57 69 58 70 fn one_field_form() { 59 - use a <- formz.with(field("a", fields.text_field())) 71 + use a <- formz.with(field("a"), text_field()) 60 72 formz.create_form("hello " <> a) 61 73 } 62 74 63 75 fn two_field_form() { 64 76 { 65 - use a <- formz.with(field("a", fields.text_field())) 66 - use b <- formz.with(field("b", fields.text_field())) 77 + use a <- formz.with(field("a"), text_field()) 78 + use b <- formz.with(field("b"), text_field()) 67 79 68 80 formz.create_form(#(a, b)) 69 81 } ··· 71 83 72 84 fn three_field_form() { 73 85 use a <- formz.with( 74 - field("x", fields.text_field()) 75 - |> field.set_name("a") 76 - |> field.set_label("A") 77 - |> field.validates(validation.must_be_longer_than(3)), 86 + field("x") 87 + |> field.set_name("a") 88 + |> field.set_label("A"), 89 + text_field() 90 + |> definition.validates(validation.must_be_longer_than(3)), 91 + ) 92 + 93 + use b <- formz.with(field(named: "b"), int_field()) 94 + use c <- formz.with( 95 + field(named: "c") 96 + |> field.set_name("c") 97 + |> field.set_label("C"), 98 + float_field(), 78 99 ) 79 - use b <- formz.with(field("b", fields.integer_field())) 80 - use c <- formz.with(field.full("c", "C", "help!", fields.number_field())) 81 100 82 101 formz.create_form(#(a, b, c)) 83 102 } ··· 136 155 |> should.equal(Ok(#("hello", "world"))) 137 156 } 138 157 139 - pub fn parse_double_optional_field_form_test() { 140 - let f = { 141 - use a <- formz.with(field("a", fields.text_field()) |> field.set_optional) 142 - use b <- formz.with(field("b", fields.text_field()) |> field.set_optional) 158 + // pub fn parse_double_optional_field_form_test() { 159 + // let f = { 160 + // use a <- formz.with(field("a") |> field.set_optional, text_field()) 161 + // use b <- formz.with(field("b") |> field.set_optional, text_field()) 143 162 144 - formz.create_form(#(a, b)) 145 - } 163 + // formz.create_form(#(a, b)) 164 + // } 146 165 147 - f 148 - |> formz.data([#("a", "hello"), #("b", "world")]) 149 - |> formz.parse 150 - |> should.equal(Ok(#(option.Some("hello"), option.Some("world")))) 166 + // f 167 + // |> formz.data([#("a", "hello"), #("b", "world")]) 168 + // |> formz.parse 169 + // |> should.equal(Ok(#(option.Some("hello"), option.Some("world")))) 151 170 152 - // missing second 153 - f 154 - |> formz.data([#("a", "hello")]) 155 - |> formz.parse 156 - |> should.equal(Ok(#(option.Some("hello"), option.None))) 171 + // // missing second 172 + // f 173 + // |> formz.data([#("a", "hello")]) 174 + // |> formz.parse 175 + // |> should.equal(Ok(#(option.Some("hello"), option.None))) 157 176 158 - // missing first 159 - f 160 - |> formz.data([#("b", "world")]) 161 - |> formz.parse 162 - |> should.equal(Ok(#(option.None, option.Some("world")))) 177 + // // missing first 178 + // f 179 + // |> formz.data([#("b", "world")]) 180 + // |> formz.parse 181 + // |> should.equal(Ok(#(option.None, option.Some("world")))) 163 182 164 - // missing both 165 - f 166 - |> formz.data([]) 167 - |> formz.parse 168 - |> should.equal(Ok(#(option.None, option.None))) 169 - } 183 + // // missing both 184 + // f 185 + // |> formz.data([]) 186 + // |> formz.parse 187 + // |> should.equal(Ok(#(option.None, option.None))) 188 + // } 170 189 171 190 pub fn parse_single_field_form_with_error_test() { 172 191 let assert Error(f) = 173 192 { 174 - use a <- formz.with(field("a", fields.integer_field())) 193 + use a <- formz.with(field("a"), int_field()) 175 194 formz.create_form(a) 176 195 } 177 196 |> formz.data([#("first", "world")]) ··· 189 208 |> get_form_from_error_result 190 209 |> formz.get_items 191 210 192 - fielda |> should_be_field_no_error 193 - fieldb |> should_be_field_no_error 194 - fieldc |> should_be_field_with_error("Must be a number") 211 + fielda |> io.debug |> should_be_field_no_error 212 + fieldb |> io.debug |> should_be_field_no_error 213 + fieldc |> io.debug |> should_be_field_with_error("Must be a number") 195 214 196 215 let assert [Item(fielda), Item(fieldb), Item(fieldc)] = 197 216 three_field_form() ··· 236 255 237 256 pub fn sub_form_test() { 238 257 let f1 = { 239 - use a <- formz.with(field("a", fields.integer_field())) 240 - use b <- formz.with(field("b", fields.integer_field())) 241 - use c <- formz.with(field("c", fields.integer_field())) 258 + use a <- formz.with(field("a"), int_field()) 259 + use b <- formz.with(field("b"), int_field()) 260 + use c <- formz.with(field("c"), int_field()) 242 261 243 262 formz.create_form(#(a, b, c)) 244 263 } 245 264 246 265 let f2 = { 247 266 use a <- formz.sub_form("name", "Name", f1) 248 - use b <- formz.with(field("d", fields.integer_field())) 267 + use b <- formz.with(field("d"), int_field()) 249 268 250 269 formz.create_form(#(a, b)) 251 270 } ··· 263 282 264 283 pub fn sub_form_error_test() { 265 284 let f1 = { 266 - use a <- formz.with(field("a", fields.integer_field())) 267 - use b <- formz.with(field("b", fields.integer_field())) 268 - use c <- formz.with(field("c", fields.integer_field())) 285 + use a <- formz.with(field("a"), int_field()) 286 + use b <- formz.with(field("b"), int_field()) 287 + use c <- formz.with(field("c"), int_field()) 269 288 270 289 formz.create_form(#(a, b, c)) 271 290 } 272 291 273 292 let f2 = { 274 293 use a <- formz.sub_form("name", "Name", f1) 275 - use b <- formz.with(field("d", fields.integer_field())) 294 + use b <- formz.with(field("d"), int_field()) 276 295 277 296 formz.create_form(#(a, b)) 278 297 } ··· 316 335 let assert Error(form) = 317 336 formz.try(f, fn(_, form) { 318 337 form 319 - |> formz.update_input("a", input.set_error(_, "woops")) 338 + |> formz.update_input("a", field.set_error(_, "woops")) 320 339 |> Error 321 340 }) 322 341 let assert [Item(fielda), Item(fieldb), Item(fieldc)] = formz.get_items(form)
+3 -3
formz_demo/src/formz_demo/example/page.gleam
··· 1 + import formz/field 1 2 import formz/formz_use as formz 2 - import formz/input 3 3 import gleam/list 4 4 import gleam/option 5 5 import gleam/result ··· 82 82 ]), 83 83 html.td([], [ 84 84 html.text(case i { 85 - input.Valid(..) -> "" 86 - input.Invalid(error:, ..) -> error 85 + field.Valid(..) -> "" 86 + field.Invalid(error:, ..) -> error 87 87 }), 88 88 ]), 89 89 ])
+8 -8
formz_demo/src/formz_demo/examples/all_the_inputs.gleam
··· 5 5 pub fn make_form() { 6 6 let choices = [#("Yes", True), #("Maybe", True), #("No", False)] 7 7 8 - use a <- formz.with(field("a", fields.text_field())) 9 - use b <- formz.with(field("b", fields.integer_field())) 10 - use c <- formz.with(field("c", fields.number_field())) 11 - use d <- formz.with(field("d", fields.boolean_field())) 12 - use e <- formz.with(field("e", fields.email_field())) 13 - use f <- formz.with(field("g", fields.enum_field(letters()))) 14 - use g <- formz.with(field("h", fields.indexed_enum_field(choices))) 15 - use h <- formz.with(field("i", fields.list_field(["Dog", "Cat", "Bird"]))) 8 + use a <- formz.with(field("a"), fields.text_field()) 9 + use b <- formz.with(field("b"), fields.integer_field()) 10 + use c <- formz.with(field("c"), fields.number_field()) 11 + use d <- formz.with(field("d"), fields.boolean_field()) 12 + use e <- formz.with(field("e"), fields.email_field()) 13 + use f <- formz.with(field("g"), fields.enum_field(letters())) 14 + use g <- formz.with(field("h"), fields.indexed_enum_field(choices)) 15 + use h <- formz.with(field("i"), fields.list_field(["Dog", "Cat", "Bird"])) 16 16 17 17 formz.create_form(#(a, b, c, d, e, f, g, h)) 18 18 }
+11 -5
formz_demo/src/formz_demo/examples/custom_output.gleam
··· 1 - import formz/field 1 + import formz/field.{field} 2 2 import formz/formz_use as formz 3 3 import formz_lustre/fields 4 4 import formz_lustre/simple ··· 22 22 } 23 23 24 24 fn address_form() { 25 - use street <- formz.with(field.field("street", fields.text_field())) 26 - use city <- formz.with(field.field("city", fields.text_field())) 27 - use state <- formz.with(field.field("state", fields.list_field(states_list()))) 28 - use postal_code <- formz.with(field.field("postal_code", fields.text_field())) 25 + use street <- formz.with(field(named: "street"), fields.text_field()) 26 + use city <- formz.with(field(named: "city"), fields.text_field()) 27 + use state <- formz.with( 28 + field(named: "state"), 29 + fields.list_field(states_list()), 30 + ) 31 + use postal_code <- formz.with( 32 + field(named: "postal_code"), 33 + fields.text_field(), 34 + ) 29 35 30 36 formz.create_form(Address(street:, city:, state:, postal_code:)) 31 37 }
+1 -1
formz_demo/src/formz_demo/examples/hello_world.gleam
··· 3 3 import formz_string/fields 4 4 5 5 pub fn make_form() { 6 - use name <- formz.with(field("name", fields.text_field())) 6 + use name <- formz.with(field("name"), fields.text_field()) 7 7 formz.create_form("Hello " <> name) 8 8 }
+18 -9
formz_demo/src/formz_demo/examples/labels.gleam
··· 1 + import formz/definition as d 1 2 import formz/field.{field} 2 3 import formz/formz_use as formz 4 + import formz/validation 3 5 import formz_string/fields 4 6 5 7 pub fn make_form() { 6 - use name <- formz.with( 7 - field("name", fields.text_field()) 8 - |> field.set_label("Name"), 9 - ) 8 + use name <- formz.with(field(named: "name"), fields.text_field()) 10 9 use age <- formz.with( 11 - field("age", fields.integer_field()) 12 - |> field.set_label("Age"), 10 + field("age") |> field.set_label("Age"), 11 + fields.integer_field(), 13 12 ) 14 13 use height <- formz.with( 15 - field("height", fields.integer_field()) 16 - |> field.set_label("Height (cm)") 17 - |> field.set_help_text("Please enter your height in centimeters"), 14 + field("height") 15 + |> field.set_label("Height (cm)") 16 + |> field.set_help_text("Please enter your height in centimeters"), 17 + fields.integer_field(), 18 18 ) 19 + 20 + // use something <- formz.with( 21 + // field(named: "something") 22 + // |> field.make_hidden() 23 + // |> field.set_label("Something") 24 + // |> field.set_help_text("Please enter something"), 25 + // fields.text_field() 26 + // |> d.validates(validation.must_be_longer_than(3)), 27 + // ) 19 28 20 29 formz.create_form(#(name, age, height)) 21 30 }
+6 -6
formz_demo/src/formz_demo/examples/login.gleam
··· 1 + import formz/definition 1 2 import formz/field.{field} 2 3 import formz/formz_use as formz 3 - import formz/input 4 4 import formz_string/fields 5 5 import formz_string/widgets 6 6 import wisp ··· 14 14 } 15 15 16 16 pub fn make_form() { 17 - use username <- formz.with(field("username", fields.text_field())) 17 + use username <- formz.with(field("username"), fields.text_field()) 18 18 use password <- formz.with( 19 - field("password", fields.text_field()) 20 - |> field.set_widget(widgets.password_widget()), 19 + field("password"), 20 + fields.text_field() |> definition.set_widget(widgets.password_widget()), 21 21 ) 22 22 23 23 formz.create_form(Credentials(username, password)) ··· 30 30 Credentials("admin", "l33t") -> Ok(User(cred.username)) 31 31 Credentials("admin", _) -> 32 32 form 33 - |> formz.update_input("password", input.set_error(_, "wrong password")) 33 + |> formz.update_input("password", field.set_error(_, "wrong password")) 34 34 |> Error 35 35 Credentials(_, _) -> 36 36 form 37 - |> formz.update_input("username", input.set_error(_, "wrong username")) 37 + |> formz.update_input("username", field.set_error(_, "wrong username")) 38 38 |> Error 39 39 } 40 40 }
+5 -5
formz_demo/src/formz_demo/examples/sub_form.gleam
··· 1 - import formz/field 1 + import formz/field.{field} 2 2 import formz/formz_use as formz 3 3 import formz_string/fields 4 4 ··· 18 18 } 19 19 20 20 fn address_form() { 21 - use street <- formz.with(field.field("street", fields.text_field())) 22 - use city <- formz.with(field.field("city", fields.text_field())) 23 - use state <- formz.with(field.field("state", fields.list_field(states_list()))) 24 - use postal_code <- formz.with(field.field("postal_code", fields.text_field())) 21 + use street <- formz.with(field("street"), fields.text_field()) 22 + use city <- formz.with(field("city"), fields.text_field()) 23 + use state <- formz.with(field("state"), fields.list_field(states_list())) 24 + use postal_code <- formz.with(field.field("postal_code"), fields.text_field()) 25 25 26 26 formz.create_form(Address(street:, city:, state:, postal_code:)) 27 27 }
+8 -8
formz_lustre/src/formz_lustre/fields.gleam
··· 1 - import formz/field 1 + import formz/field.{Definition} 2 2 import formz/validation 3 3 import formz_lustre/widgets 4 4 import gleam/list 5 5 6 6 pub fn text_field() { 7 - field.Definition(widgets.text_like_widget("text"), validation.string, "") 7 + Definition(widgets.text_like_widget("text"), validation.string, "") 8 8 } 9 9 10 10 pub fn email_field() { 11 - field.Definition(widgets.text_like_widget("email"), validation.email, "") 11 + Definition(widgets.text_like_widget("email"), validation.email, "") 12 12 } 13 13 14 14 pub fn integer_field() { 15 - field.Definition(widgets.text_like_widget("number"), validation.int, 0) 15 + Definition(widgets.text_like_widget("number"), validation.int, 0) 16 16 } 17 17 18 18 pub fn number_field() { 19 - field.Definition(widgets.text_like_widget("number"), validation.number, 0.0) 19 + Definition(widgets.text_like_widget("number"), validation.number, 0.0) 20 20 } 21 21 22 22 pub fn boolean_field() { 23 - field.Definition(widgets.checkbox_widget(), validation.boolean, False) 23 + Definition(widgets.checkbox_widget(), validation.boolean, False) 24 24 } 25 25 26 26 pub fn enum_field(variants: List(#(String, enum))) { 27 27 let assert Ok(#(_, first)) = list.first(variants) 28 - field.Definition( 28 + Definition( 29 29 widgets.select_widget(variants), 30 30 validation.enum(variants) 31 31 |> validation.replace_error("Please select an option"), ··· 36 36 pub fn indexed_enum_field(variants: List(#(String, enum))) { 37 37 let keys_indexed = list.index_map(variants, fn(t, i) { #(t.0, i) }) 38 38 let assert Ok(#(_, first)) = list.first(variants) 39 - field.Definition( 39 + Definition( 40 40 widgets.select_widget(keys_indexed), 41 41 validation.enum_by_index(variants) 42 42 |> validation.replace_error("Please select an option"),
+7 -4
formz_lustre/src/formz_lustre/simple.gleam
··· 1 + import formz/field.{WidgetArgs} 1 2 import formz/formz_use as formz 2 - import formz/input.{WidgetArgs} 3 3 import gleam/list 4 4 import gleam/string 5 5 import lustre/attribute ··· 33 33 } 34 34 let widget_el = 35 35 html.span([attribute.class("widget")], [ 36 - f.widget(f, WidgetArgs(id: f.name, labelled_by: input.Element)), 36 + field.run_widget( 37 + f, 38 + WidgetArgs(id: f.name, labelled_by: field.Element), 39 + ), 37 40 ]) 38 41 39 42 let errors_el = case f { 40 - input.Valid(..) -> element.none() 41 - input.Invalid(error:, ..) -> 43 + field.Valid(..) -> element.none() 44 + field.Invalid(error:, ..) -> 42 45 html.span([attribute.class("errors")], [html.text(error)]) 43 46 } 44 47
+97 -85
formz_lustre/src/formz_lustre/widgets.gleam
··· 1 - import formz/input.{type Input, type WidgetArgs, WidgetArgs} 1 + import formz/field.{type Field, type WidgetArgs, WidgetArgs} 2 2 import gleam/list 3 3 import gleam/string 4 4 import lustre/attribute ··· 20 20 } 21 21 22 22 fn aria_label_attr( 23 - labelled_by: input.InputLabelled, 23 + labelled_by: field.InputLabelled, 24 24 label: String, 25 25 ) -> attribute.Attribute(msg) { 26 26 case labelled_by { 27 - input.Element -> attribute.none() 28 - input.Id(id) -> attribute.attribute("aria-labelledby", id) 29 - input.Value -> 27 + field.Element -> attribute.none() 28 + field.Id(id) -> attribute.attribute("aria-labelledby", id) 29 + field.Value -> 30 30 case label { 31 31 "" -> attribute.none() 32 32 _ -> attribute.attribute("aria-label", label) ··· 42 42 } 43 43 44 44 pub fn checkbox_widget() { 45 - fn(input: Input(element.Element(msg)), args: input.WidgetArgs) -> element.Element( 46 - msg, 47 - ) { 48 - html.input([ 49 - attribute.type_("checkbox"), 50 - name_attr(input.name), 51 - id_attr(args.id), 52 - attribute.checked(input.value == "on"), 53 - aria_label_attr(args.labelled_by, input.label), 54 - ]) 55 - } 45 + field.widget( 46 + fn(input: Field(element.Element(msg)), args: WidgetArgs) -> element.Element( 47 + msg, 48 + ) { 49 + html.input([ 50 + attribute.type_("checkbox"), 51 + name_attr(input.name), 52 + id_attr(args.id), 53 + attribute.checked(input.value == "on"), 54 + aria_label_attr(args.labelled_by, input.label), 55 + ]) 56 + }, 57 + ) 56 58 } 57 59 58 60 pub fn password_widget() { 59 - fn(input: Input(element.Element(msg)), args: WidgetArgs) -> element.Element( 60 - msg, 61 - ) { 62 - html.input([ 63 - attribute.type_("password"), 64 - name_attr(input.name), 65 - id_attr(args.id), 66 - // value_attr(input.value), 67 - aria_label_attr(args.labelled_by, input.label), 68 - ]) 69 - } 61 + field.widget( 62 + fn(input: Field(element.Element(msg)), args: WidgetArgs) -> element.Element( 63 + msg, 64 + ) { 65 + html.input([ 66 + attribute.type_("password"), 67 + name_attr(input.name), 68 + id_attr(args.id), 69 + // value_attr(input.value), 70 + aria_label_attr(args.labelled_by, input.label), 71 + ]) 72 + }, 73 + ) 70 74 } 71 75 72 76 pub fn text_widget() { ··· 74 78 } 75 79 76 80 pub fn text_like_widget(type_: String) { 77 - fn(input: Input(element.Element(msg)), args: WidgetArgs) -> element.Element( 78 - msg, 79 - ) { 80 - html.input([ 81 - attribute.type_(type_), 82 - name_attr(input.name), 83 - id_attr(args.id), 84 - value_attr(input.value), 85 - aria_label_attr(args.labelled_by, input.label), 86 - ]) 87 - } 88 - } 89 - 90 - pub fn textarea_widget() { 91 - fn(input: Input(element.Element(msg)), args: WidgetArgs) -> element.Element( 92 - msg, 93 - ) { 94 - html.textarea( 95 - [ 81 + field.widget( 82 + fn(input: Field(element.Element(msg)), args: WidgetArgs) -> element.Element( 83 + msg, 84 + ) { 85 + html.input([ 86 + attribute.type_(type_), 96 87 name_attr(input.name), 97 88 id_attr(args.id), 89 + value_attr(input.value), 98 90 aria_label_attr(args.labelled_by, input.label), 99 - ], 100 - input.value, 101 - ) 102 - } 91 + ]) 92 + }, 93 + ) 94 + } 95 + 96 + pub fn textarea_widget() { 97 + field.widget( 98 + fn(input: Field(element.Element(msg)), args: WidgetArgs) -> element.Element( 99 + msg, 100 + ) { 101 + html.textarea( 102 + [ 103 + name_attr(input.name), 104 + id_attr(args.id), 105 + aria_label_attr(args.labelled_by, input.label), 106 + ], 107 + input.value, 108 + ) 109 + }, 110 + ) 103 111 } 104 112 105 113 pub fn hidden_widget() { 106 - fn(input: Input(element.Element(msg)), _args: WidgetArgs) -> element.Element( 107 - msg, 108 - ) { 109 - html.input([ 110 - attribute.type_("hidden"), 111 - name_attr(input.name), 112 - value_attr(input.value), 113 - ]) 114 - } 114 + field.widget( 115 + fn(input: Field(element.Element(msg)), _args: WidgetArgs) -> element.Element( 116 + msg, 117 + ) { 118 + html.input([ 119 + attribute.type_("hidden"), 120 + name_attr(input.name), 121 + value_attr(input.value), 122 + ]) 123 + }, 124 + ) 115 125 } 116 126 117 127 pub fn select_widget(variants: List(#(String, value))) { 118 - fn(input: Input(element.Element(msg)), args: WidgetArgs) -> element.Element( 119 - msg, 120 - ) { 121 - html.select( 122 - [attribute.name(input.name)], 123 - list.map(variants, fn(variant) { 124 - let val = string.inspect(variant.1) 125 - html.option( 126 - [attribute.value(val), attribute.selected(input.value == val)], 127 - variant.0, 128 - ) 129 - }), 130 - ) 131 - 132 - html.select( 133 - [ 134 - name_attr(input.name), 135 - id_attr(args.id), 136 - aria_label_attr(args.labelled_by, input.label), 137 - ], 138 - list.flatten([ 139 - [html.option([attribute.value("")], "Select..."), html.hr([])], 128 + field.widget( 129 + fn(input: Field(element.Element(msg)), args: WidgetArgs) -> element.Element( 130 + msg, 131 + ) { 132 + html.select( 133 + [attribute.name(input.name)], 140 134 list.map(variants, fn(variant) { 141 135 let val = string.inspect(variant.1) 142 136 html.option( 143 - [value_attr(val), attribute.selected(input.value == val)], 137 + [attribute.value(val), attribute.selected(input.value == val)], 144 138 variant.0, 145 139 ) 146 140 }), 147 - ]), 148 - ) 149 - } 141 + ) 142 + 143 + html.select( 144 + [ 145 + name_attr(input.name), 146 + id_attr(args.id), 147 + aria_label_attr(args.labelled_by, input.label), 148 + ], 149 + list.flatten([ 150 + [html.option([attribute.value("")], "Select..."), html.hr([])], 151 + list.map(variants, fn(variant) { 152 + let val = string.inspect(variant.1) 153 + html.option( 154 + [value_attr(val), attribute.selected(input.value == val)], 155 + variant.0, 156 + ) 157 + }), 158 + ]), 159 + ) 160 + }, 161 + ) 150 162 }
+8 -8
formz_nakai/src/formz_nakai/fields.gleam
··· 1 - import formz/field 1 + import formz/field.{Definition} 2 2 import formz/validation 3 3 import formz_nakai/widgets 4 4 import gleam/list 5 5 6 6 pub fn text_field() { 7 - field.Definition(widgets.text_like_widget("text"), validation.string, "") 7 + Definition(widgets.text_like_widget("text"), validation.string, "") 8 8 } 9 9 10 10 pub fn email_field() { 11 - field.Definition(widgets.text_like_widget("email"), validation.email, "") 11 + Definition(widgets.text_like_widget("email"), validation.email, "") 12 12 } 13 13 14 14 pub fn integer_field() { 15 - field.Definition(widgets.text_like_widget("number"), validation.int, 0) 15 + Definition(widgets.text_like_widget("number"), validation.int, 0) 16 16 } 17 17 18 18 pub fn number_field() { 19 - field.Definition(widgets.text_like_widget("number"), validation.number, 0.0) 19 + Definition(widgets.text_like_widget("number"), validation.number, 0.0) 20 20 } 21 21 22 22 pub fn boolean_field() { 23 - field.Definition(widgets.checkbox_widget(), validation.boolean, False) 23 + Definition(widgets.checkbox_widget(), validation.boolean, False) 24 24 } 25 25 26 26 pub fn enum_field(variants: List(#(String, enum))) { 27 27 let assert Ok(#(_, first)) = list.first(variants) 28 - field.Definition( 28 + Definition( 29 29 widgets.select_widget(variants), 30 30 validation.enum(variants) 31 31 |> validation.replace_error("Please select an option"), ··· 36 36 pub fn indexed_enum_field(variants: List(#(String, enum))) { 37 37 let keys_indexed = list.index_map(variants, fn(t, i) { #(t.0, i) }) 38 38 let assert Ok(#(_, first)) = list.first(variants) 39 - field.Definition( 39 + Definition( 40 40 widgets.select_widget(keys_indexed), 41 41 validation.enum_by_index(variants) 42 42 |> validation.replace_error("Please select an option"),
+7 -4
formz_nakai/src/formz_nakai/simple.gleam
··· 1 + import formz/field.{WidgetArgs} 1 2 import formz/formz_use as formz 2 - import formz/input.{WidgetArgs} 3 3 import gleam/list 4 4 import gleam/string 5 5 import nakai/attr ··· 26 26 } 27 27 let widget_el = 28 28 html.span([attr.class("widget")], [ 29 - f.widget(f, WidgetArgs(id: f.name, labelled_by: input.Element)), 29 + field.run_widget( 30 + f, 31 + WidgetArgs(id: f.name, labelled_by: field.Element), 32 + ), 30 33 ]) 31 34 32 35 let errors_el = case f { 33 - input.Valid(..) -> html.Nothing 34 - input.Invalid(error:, ..) -> 36 + field.Valid(..) -> html.Nothing 37 + field.Invalid(error:, ..) -> 35 38 html.span([attr.class("errors")], [html.Text(error)]) 36 39 } 37 40
+34 -34
formz_nakai/src/formz_nakai/widgets.gleam
··· 1 - import formz/input.{type Input, type WidgetArgs} 1 + import formz/field.{type Field, type WidgetArgs} 2 2 import gleam/list 3 3 import gleam/string 4 4 import nakai/attr ··· 19 19 } 20 20 21 21 fn aria_label_attr( 22 - labelled_by: input.InputLabelled, 22 + labelled_by: field.InputLabelled, 23 23 label: String, 24 24 ) -> List(attr.Attr) { 25 25 case labelled_by { 26 - input.Element -> [] 27 - input.Id(id) -> [attr.aria_labelledby(id)] 28 - input.Value -> 26 + field.Element -> [] 27 + field.Id(id) -> [attr.aria_labelledby(id)] 28 + field.Value -> 29 29 case label { 30 30 "" -> [] 31 31 _ -> [attr.aria_label(label)] ··· 45 45 } 46 46 47 47 pub fn checkbox_widget() { 48 - fn(input: Input(html.Node), args: input.WidgetArgs) -> html.Node { 49 - let checked_attr = case input.value { 48 + field.widget(fn(field: Field(html.Node), args: field.WidgetArgs) -> html.Node { 49 + let checked_attr = case field.value { 50 50 "on" -> [attr.checked()] 51 51 _ -> [] 52 52 } ··· 54 54 html.input( 55 55 list.flatten([ 56 56 type_attr("checkbox"), 57 - name_attr(input.name), 57 + name_attr(field.name), 58 58 id_attr(args.id), 59 59 checked_attr, 60 - aria_label_attr(args.labelled_by, input.label), 60 + aria_label_attr(args.labelled_by, field.label), 61 61 ]), 62 62 ) 63 - } 63 + }) 64 64 } 65 65 66 66 pub fn password_widget() { 67 - fn(input: Input(html.Node), args: WidgetArgs) -> html.Node { 67 + field.widget(fn(field: Field(html.Node), args: WidgetArgs) -> html.Node { 68 68 html.input( 69 69 list.flatten([ 70 70 type_attr("password"), 71 - name_attr(input.name), 71 + name_attr(field.name), 72 72 id_attr(args.id), 73 - // value_attr(input.value), 74 - aria_label_attr(args.labelled_by, input.label), 73 + // value_attr(field.value), 74 + aria_label_attr(args.labelled_by, field.label), 75 75 ]), 76 76 ) 77 - } 77 + }) 78 78 } 79 79 80 80 pub fn text_like_widget(type_: String) { 81 - fn(input: Input(html.Node), args: WidgetArgs) -> html.Node { 81 + field.widget(fn(field: Field(html.Node), args: WidgetArgs) -> html.Node { 82 82 html.input( 83 83 list.flatten([ 84 84 type_attr(type_), 85 - name_attr(input.name), 85 + name_attr(field.name), 86 86 id_attr(args.id), 87 - value_attr(input.value), 88 - aria_label_attr(args.labelled_by, input.label), 87 + value_attr(field.value), 88 + aria_label_attr(args.labelled_by, field.label), 89 89 ]), 90 90 ) 91 - } 91 + }) 92 92 } 93 93 94 94 pub fn textarea_widget() { 95 - fn(input: Input(html.Node), args: WidgetArgs) -> html.Node { 95 + field.widget(fn(field: Field(html.Node), args: WidgetArgs) -> html.Node { 96 96 html.textarea( 97 97 list.flatten([ 98 - name_attr(input.name), 98 + name_attr(field.name), 99 99 id_attr(args.id), 100 - aria_label_attr(args.labelled_by, input.label), 100 + aria_label_attr(args.labelled_by, field.label), 101 101 ]), 102 - [html.Text(input.value)], 102 + [html.Text(field.value)], 103 103 ) 104 - } 104 + }) 105 105 } 106 106 107 107 pub fn hidden_widget() { 108 - fn(input: Input(html.Node), _) -> html.Node { 108 + field.widget(fn(field: Field(html.Node), _) -> html.Node { 109 109 html.input( 110 110 list.flatten([ 111 111 type_attr("hidden"), 112 - name_attr(input.name), 113 - value_attr(input.value), 112 + name_attr(field.name), 113 + value_attr(field.value), 114 114 ]), 115 115 ) 116 - } 116 + }) 117 117 } 118 118 119 119 pub fn select_widget(variants: List(#(String, value))) { 120 - fn(input: Input(html.Node), args: WidgetArgs) -> html.Node { 120 + field.widget(fn(field: Field(html.Node), args: WidgetArgs) -> html.Node { 121 121 html.select( 122 122 list.flatten([ 123 - name_attr(input.name), 123 + name_attr(field.name), 124 124 id_attr(args.id), 125 - aria_label_attr(args.labelled_by, input.label), 125 + aria_label_attr(args.labelled_by, field.label), 126 126 ]), 127 127 list.flatten([ 128 128 [html.option([attr.value("")], [html.Text("Select...")]), html.hr([])], 129 129 list.map(variants, fn(variant) { 130 130 let val = string.inspect(variant.1) 131 - let selected_attr = case input.value == val { 131 + let selected_attr = case field.value == val { 132 132 True -> [attr.selected()] 133 133 _ -> [] 134 134 } ··· 138 138 }), 139 139 ]), 140 140 ) 141 - } 141 + }) 142 142 }
+8 -8
formz_string/src/formz_string/fields.gleam
··· 1 - import formz/field 1 + import formz/field.{Definition} 2 2 import formz/validation 3 3 import formz_string/widgets 4 4 import gleam/list 5 5 6 6 pub fn text_field() { 7 - field.Definition(widgets.text_like_widget("text"), validation.string, "") 7 + Definition(widgets.text_like_widget("text"), validation.string, "") 8 8 } 9 9 10 10 pub fn email_field() { 11 - field.Definition(widgets.text_like_widget("email"), validation.email, "") 11 + Definition(widgets.text_like_widget("email"), validation.email, "") 12 12 } 13 13 14 14 pub fn integer_field() { 15 - field.Definition(widgets.text_like_widget("number"), validation.int, 0) 15 + Definition(widgets.text_like_widget("number"), validation.int, 0) 16 16 } 17 17 18 18 pub fn number_field() { 19 - field.Definition(widgets.text_like_widget("number"), validation.number, 0.0) 19 + Definition(widgets.text_like_widget("number"), validation.number, 0.0) 20 20 } 21 21 22 22 pub fn boolean_field() { 23 - field.Definition(widgets.checkbox_widget(), validation.boolean, False) 23 + Definition(widgets.checkbox_widget(), validation.boolean, False) 24 24 } 25 25 26 26 pub fn enum_field(variants: List(#(String, enum))) { 27 27 let assert Ok(#(_, first)) = list.first(variants) 28 - field.Definition( 28 + Definition( 29 29 widgets.select_widget(variants), 30 30 validation.enum(variants) 31 31 |> validation.replace_error("Please select an option"), ··· 36 36 pub fn indexed_enum_field(variants: List(#(String, enum))) { 37 37 let keys_indexed = list.index_map(variants, fn(t, i) { #(t.0, i) }) 38 38 let assert Ok(#(_, first)) = list.first(variants) 39 - field.Definition( 39 + Definition( 40 40 widgets.select_widget(keys_indexed), 41 41 validation.enum_by_index(variants) 42 42 |> validation.replace_error("Please select an option"),
+9 -5
formz_string/src/formz_string/simple.gleam
··· 1 + import formz/field 1 2 import formz/formz_use as formz 2 - import formz/input 3 3 import formz_string/widgets 4 4 import gleam/list 5 5 import gleam/string ··· 16 16 pub fn generate_item(item: formz.FormItem(String)) -> String { 17 17 case item { 18 18 formz.Item(f) if f.hidden == True -> 19 - widgets.hidden_widget()(f, input.WidgetArgs("", input.Value)) 19 + "<input" 20 + <> { " type=\"hidden\"" } 21 + <> { " name=\"" <> f.name <> "\"" } 22 + <> { " value\"" <> f.value <> "\"" } 23 + <> ">" 20 24 formz.Item(f) -> 21 25 case f.hidden { 22 26 True -> "" ··· 29 33 } 30 34 let widget_el = 31 35 "<span class=\"widget\">" 32 - <> f.widget(f, input.WidgetArgs(f.name, input.Element)) 36 + <> field.run_widget(f, field.WidgetArgs(f.name, field.Element)) 33 37 <> "</span>" 34 38 35 39 let errors_el = case f { 36 - input.Valid(..) -> "<span class=\"error-placeholder\"></span>" 37 - input.Invalid(error:, ..) -> 40 + field.Valid(..) -> "<span class=\"error-placeholder\"></span>" 41 + field.Invalid(error:, ..) -> 38 42 "<span class=\"errors\">" <> error <> "</span>" 39 43 } 40 44
+34 -34
formz_string/src/formz_string/widgets.gleam
··· 1 - import formz/input.{type Input, type WidgetArgs} 1 + import formz/field.{type Field, type WidgetArgs} 2 2 import gleam/list 3 3 import gleam/string 4 4 ··· 16 16 } 17 17 } 18 18 19 - fn aria_label_attr(labelled_by: input.InputLabelled, label: String) -> String { 19 + fn aria_label_attr(labelled_by: field.InputLabelled, label: String) -> String { 20 20 case labelled_by { 21 21 // there should be a label with a for attribute pointing to this id 22 - input.Element -> "" 22 + field.Element -> "" 23 23 24 24 // we have the id of the element that labels this input 25 - input.Id(id) -> " aria-labelledby=\"" <> id <> "\"" 25 + field.Id(id) -> " aria-labelledby=\"" <> id <> "\"" 26 26 27 27 // we'll use the label value as the aria-label 28 - input.Value -> { 28 + field.Value -> { 29 29 let sanitized_label = 30 30 label 31 31 |> string.replace("\"", "&quot;") ··· 54 54 } 55 55 56 56 pub fn checkbox_widget() { 57 - fn(input: Input(String), args: WidgetArgs) -> String { 58 - let checked_attr = case input.value { 57 + field.widget(fn(field: Field(String), args: WidgetArgs) -> String { 58 + let checked_attr = case field.value { 59 59 "on" -> " checked" 60 60 _ -> "" 61 61 } 62 62 63 63 "<input" 64 64 <> type_attr("checkbox") 65 - <> name_attr(input.name) 65 + <> name_attr(field.name) 66 66 <> id_attr(args.id) 67 67 <> checked_attr 68 - <> aria_label_attr(args.labelled_by, input.label) 68 + <> aria_label_attr(args.labelled_by, field.label) 69 69 <> ">" 70 - } 70 + }) 71 71 } 72 72 73 73 pub fn password_widget() { 74 - fn(input: Input(String), args: WidgetArgs) -> String { 74 + field.widget(fn(field: Field(String), args: WidgetArgs) -> String { 75 75 "<input" 76 76 <> type_attr("password") 77 - <> name_attr(input.name) 77 + <> name_attr(field.name) 78 78 <> id_attr(args.id) 79 - // <> value_attr(input.value) 80 - <> aria_label_attr(args.labelled_by, input.label) 79 + // <> value_attr(field.value) 80 + <> aria_label_attr(args.labelled_by, field.label) 81 81 <> ">" 82 - } 82 + }) 83 83 } 84 84 85 85 pub fn text_like_widget(type_: String) { 86 - fn(input: Input(String), args: WidgetArgs) -> String { 86 + field.widget(fn(field: Field(String), args: WidgetArgs) -> String { 87 87 "<input" 88 88 <> type_attr(type_) 89 - <> name_attr(input.name) 89 + <> name_attr(field.name) 90 90 <> id_attr(args.id) 91 - <> value_attr(input.value) 92 - <> aria_label_attr(args.labelled_by, input.label) 91 + <> value_attr(field.value) 92 + <> aria_label_attr(args.labelled_by, field.label) 93 93 <> ">" 94 - } 94 + }) 95 95 } 96 96 97 97 pub fn textarea_widget() { 98 - fn(input: Input(String), args: WidgetArgs) -> String { 98 + field.widget(fn(field: Field(String), args: WidgetArgs) -> String { 99 99 // https://chriscoyier.net/2023/09/29/css-solves-auto-expanding-textareas-probably-eventually/ 100 100 // https://til.simonwillison.net/css/resizing-textarea 101 101 "<textarea" 102 - <> name_attr(input.name) 102 + <> name_attr(field.name) 103 103 <> id_attr(args.id) 104 - <> aria_label_attr(args.labelled_by, input.label) 104 + <> aria_label_attr(args.labelled_by, field.label) 105 105 <> ">" 106 - <> input.value 106 + <> field.value 107 107 <> "</textarea>" 108 - } 108 + }) 109 109 } 110 110 111 111 pub fn hidden_widget() { 112 - fn(input: Input(String), _args: WidgetArgs) -> String { 112 + field.widget(fn(field: Field(String), _args: WidgetArgs) -> String { 113 113 "<input" 114 114 <> type_attr("hidden") 115 - <> name_attr(input.name) 116 - <> value_attr(input.value) 115 + <> name_attr(field.name) 116 + <> value_attr(field.value) 117 117 <> ">" 118 - } 118 + }) 119 119 } 120 120 121 121 pub fn select_widget(variants: List(#(String, value))) { 122 - fn(input: Input(String), args: WidgetArgs) { 122 + field.widget(fn(field: Field(String), args: WidgetArgs) { 123 123 let choices = 124 124 list.map(variants, fn(variant) { 125 125 let val = string.inspect(variant.1) 126 - let selected_attr = case input.value == val { 126 + let selected_attr = case field.value == val { 127 127 True -> " selected" 128 128 _ -> "" 129 129 } ··· 135 135 136 136 { 137 137 "<select" 138 - <> name_attr(input.name) 138 + <> name_attr(field.name) 139 139 <> id_attr(args.id) 140 - <> aria_label_attr(args.labelled_by, input.label) 140 + <> aria_label_attr(args.labelled_by, field.label) 141 141 <> ">" 142 142 } 143 143 // TODO make this placeholder option not selectable? with disabled selected attributes ··· 146 146 <> { "<hr>" } 147 147 <> choices 148 148 <> { "</select>" } 149 - } 149 + }) 150 150 }