Skip to content

Commit

Permalink
Add input-specific propType.source type
Browse files Browse the repository at this point in the history
Most of the current sources read HTML values / attributes, but for `input` elements it is sometimes needed to get the actual "current" value from the JS API, since it could have been changed before the component was initialized.

This allows users to fetch user input from a form after it being rendered on the server (and after certain plugins autofill its content), so it's a better representation of the value on the page. It also allows reading a complete form into a single property.
  • Loading branch information
jspolancor authored Sep 26, 2022
1 parent 5d47cbf commit 3cbc011
Show file tree
Hide file tree
Showing 10 changed files with 845 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

- Add `event` binding to refComponents
- Add the `'custom'` `propType.source` for user-defined extraction functions
- Add `form` source, allowing you to easily extract initial values from forms or inputs

### Changed

Expand Down
50 changes: 47 additions & 3 deletions docs/api/props.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type PropTypeDefinition<T = any> = {
shapeType?: Function;
sourceOptions?: {
target?: string;
type?: 'data' | 'json' | 'attr' | 'css' | 'text' | 'html' | 'custom';
type?: 'data' | 'json' | 'attr' | 'css' | 'text' | 'html' | 'form' | 'custom';
name?: string;
options?: {
cssPredicate?: Array<string>;
Expand Down Expand Up @@ -265,7 +265,7 @@ HTML besides the default behaviour.
```ts
declare function source(options: {
target?: string;
type?: 'data' | 'json' | 'attr' | 'css' | 'text' | 'html', | 'custom';
type?: 'data' | 'json' | 'attr' | 'css' | 'text' | 'html' | 'form' | 'custom';
name?: string;
options?: {
cssPredicate?: Array<string>;
Expand All @@ -276,7 +276,8 @@ declare function source(options: {
* `target?: string` – The refName (those you configure as part of the component options)
from which you want to extract this property.
Defaults to the data-component element.
* `type?: 'data' | 'json' | 'attr' | 'css' | 'text' | 'html' | 'custom'` - The type source you want to extract.
* `type?: 'data' | 'json' | 'attr' | 'css' | 'text' | 'html' | 'form' | 'custom'` - The type source
you want to extract.
Defaults to the `data + json + css` source (`css` only for boolean props).
* `data` – Reads the `data-attribute` from your target element.
* `json` – Reads the object key from a `<script type="application/json">` JSON block that is
Expand All @@ -290,6 +291,7 @@ declare function source(options: {
to all values.
* `text` – Reads the `textContents` from the target element.
* `html` – Reads the `innerHTML` from the target element.
* `form` – Reads the `value` from the target element when targeting a form input and `FormData` when targeting a form element
* `name?: string` – For the `data`, `json`, `attr` and `css` source types, by default it will use
the
propName for the name of the (data) attribute or class name. For situations where the name
Expand Down Expand Up @@ -530,6 +532,48 @@ defineComponent({
<span data-ref="value">12.45</span>
</div>
```
#### Use `form`
```ts
defineComponent({
name: 'my-component',
refs: {
// this is needed for the source-target
form: 'form',
email: 'email',
phone: 'phone',
},
props: {
// get the FormData from the form ref
// outputs FormData {}
form: propType.object.source(
{ target: 'form', type: 'form', formData: true},
),
// get the value from the email ref
// outputs "[email protected]"
email: propType.string.source(
{ target: 'email', type: 'form'},
),
// Extract the 'email' property from the form ref FormData object
// outputs "[email protected]"
emailAddress: propType.string.source(
{ target: 'form', type: 'form', name: 'email'},
),
// conversions to Booleans, Numbers and Dates also work
// outputs "986868" (as a number)
phone: propType.number.source(
{ target: 'phone', type: 'form'},
),
},
})
```
```html
<div data-component="my-component">
<form data-ref="form">
<input type="text" data-ref="email" value="[email protected]"/>
<input type="text" data-ref="phone" value="986868"/>
</form>
</div>
```

#### Use `custom`

Expand Down
4 changes: 3 additions & 1 deletion docs/guide/props.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ specify exactly what values you want to extract from where.

* The `attr` source is similar to the `data` source, but uses normal attributes to extract data
from, and also allows conversion.

* The `form` source allow you to extract _Input state_ from form elements, when targeting an input it will extract the value, when targeting a form it will extract the FormData Object. It allows for value conversion into basic data types as well.

_Input state_ can be extracted using the `attr` binding if needed, but most often you will end
Remember, the `form` binding will extract the value from form inputs, but most often you will end
up using two-way bindings to manage syncing up these values with the internal component state.

### Parent components
Expand Down
11 changes: 10 additions & 1 deletion src/lib/props/propDefinitions.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { RefElementType } from '../refs/refDefinitions.types';
export type SourceOption =
| SourceOptionCss
| SourceOptionHtmlText
| SourceOptionForm
| SourceOptionCustom
| {
type?: 'data' | 'json' | 'attr' | 'custom';
Expand All @@ -20,6 +21,13 @@ export type SourceOptionHtmlText = {
target?: string;
};

export type SourceOptionForm = {
type: 'form';
target?: string;
name?: string;
formData?: boolean;
};

export type SourceOptionCss = {
type: 'css';
target?: string;
Expand Down Expand Up @@ -65,7 +73,8 @@ export type PropTypeInfo<T = any> = Pick<
target: RefElementType | undefined;
} & Pick<SourceOption, 'type'> &
Pick<SourceOptionCustom, 'options'> &
Pick<SourceOptionCss, 'options'>;
Pick<SourceOptionCss, 'options'> &
Pick<SourceOptionForm, 'formData'>;
};

// type OptionalPropertyKeys<T> = {
Expand Down
Loading

0 comments on commit 3cbc011

Please sign in to comment.