Skip to content
This repository has been archived by the owner on Feb 27, 2022. It is now read-only.

Commit

Permalink
Add typescript (#7)
Browse files Browse the repository at this point in the history
* Initial TypeScript commit

* Replace 'formLeaveGuardMixin' with 'FormGuardMixin'

* Deprecate 'FormLeaveGuardMixin'

* Fix tests with Typescript

* Separate build TS config

* Overhaul for additional typescript changes

* Update package version

Co-authored-by: Kendall Roth <kendall@focus21.io>
  • Loading branch information
kendallroth and Kendall Roth committed Oct 2, 2020
1 parent 217676a commit d2586e7
Show file tree
Hide file tree
Showing 24 changed files with 672 additions and 603 deletions.
4 changes: 3 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#test
coverage
dist
node_modules
18 changes: 12 additions & 6 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
module.exports = {
parser: "babel-eslint",
extends: "eslint:recommended",
parser: "@typescript-eslint/parser",
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint",
],
plugins: ["@typescript-eslint"],
env: {
jest: true,
node: true,
},
rules: {
"comma-dangle": ["warn", "always-multiline"],
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-ts-ignore": "off",
"no-console": "warn",
"no-tabs": "warn",
"no-trailing-spaces": "warn",
"no-unused-vars": "error",
"no-unused-vars": "warn",
"no-unreachable": "error",
"prefer-const": "warn",
"prefer-destructuring": "warn",
quotes: ["warn", "double"],
semi: ["warn", "always"],
},
};
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jspm_packages
.node_repl_history

# Lib
lib
/lib

# npm package lock
package-lock.json
Expand Down
1 change: 1 addition & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
singleQuote: false,
endOfLine: "lf",
trailingComma: "es5",
};
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

## [0.3.0] - 2020-10-01
### Removed
- Removed the `FormCreateMixin` (replaced with typed `createForm` function)
- _The `FormCreaetMixin` (not truly a mixin...) did not work with TypeScript_
- _The old mixin simply called this function anyway..._
- Removed the `FormLeaveGuardMixin` (replaced with typed `FormGuardMixin`)
- _The `FormLeaveGuardMixin` (not truly a mixin...) did not work with TypeScript_
- _There was no need for customizing the leave guard to the extend provided_
- Removed the form key/name from the `createForm` function API
- _This was an unnecessary step that caused more internal work for no gain (simply assign to data)_

### Changed
- Changed the default behaviour of the `setValues` form function (now will not set initial values by default)
- _This change was made to align with developer expectations (behaviour moved to `setInitial`)_

### Added
- Overhauled package to use [TypeScript](https://typescriptlang.org)!
- Fully typed `FormGuardMixin` to replace `FormLeaveGuardMixin` (can be customized with `formGuards` data key)
- New `setInitial` form function to set a form's initial (and current) values (similar to old behaviour of `setValues`)

## [0.2.3] - 2020-09-30
### Added
- Development instructions and guide
Expand Down
155 changes: 97 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

Simple Vue form state management library (no validation, etc).

- [`FormCreateMixin`](#formcreatemixin)
- [`FormLeaveGuardMixin`](#formleaveguardmixin)
- [`createForm`](#createform)
- [~~`FormCreateMixin`~~](#deprecated-formcreatemixin) (_deprecated_)
- [`FormGuardMixin`](#formguardmixin)
- [~~`FormLeaveGuardMixin`~~](#deprecated-formleaveguardmixin) (_deprecated_)

```sh
npm install @kendallroth/vue-simple-forms --save
Expand All @@ -17,19 +19,23 @@ npm install @kendallroth/vue-simple-forms --save
- Track basic form fields
- Help prevent leaving a route with unsaved changes

## `FormCreateMixin`
## `createForm`

> **NOTE:** The previous `FormCreateMixin` has been removed as it did not support TypeScript!
### Usage

The `FormCreateMixin` handles creating the reactive data and flags from the field keys and initial values. The form name/key and fields (with intial values) can be specified when adding the mixin to the component.
The `createForm` function handles creating the reactive data and flags from the field keys and initial values. The form name/key and fields (with intial values) can be specified when adding the data to the component.

```js
import { FormCreateMixin } from "@kendallroth/vue-simple-forms";
import { createForm } from "@kendallroth/vue-simple-forms";

const fields = { email: "test@example.com", password: "********" };
const fields = { email: "", password: "" };

const vm = new Vue({
mixins: [FormCreateMixin("testForm", fields, { calculateChanged: false })],
data() {
testForm: createForm(fields, { calculateChanged: false }),
},
});

// Indicate loading
Expand All @@ -38,30 +44,31 @@ vm.data.testForm.setLoading(true);
vm.data.testForm.setSubmitting(true);
```

> **NOTE:** The `createForm` function is an alternative to the `FormCreateMixin` (which is preferred).
Alternatively, TypeScript users will benefit from `vue-property-decorator` integration:

```js
// Alternative approach
import { createForm } from "@kendallroth/vue-simple-forms";
import { Component, Vue } from "vue-property-decorator";

const fields = { email: "", password: "" };
@Component
export default class Form extends Vue {
testForm = createForm({ ... });

mounted() {
this.testForm.setValues({ ... });
}
}

const vm = new Vue({
data() {
...createForm("testForm", fields, { calculateChanged: false }),
},
});
```

### API

### Config

Both `FormCreateMixin` and `createForm` accept several arguments to configure the form.
`createForm` accepts several arguments to configure the form.

| Property | Type | Default | Description |
| -------------------------- | --------- | ------- | ------------------------------------------------------ |
| `name` | `string` | | Form `data` key name |
| `fields` | `Object` | | Form fields and initial values |
| `options` | `Object` | | Form configuration options |
| `options.calculateChanged` | `boolean` | `true` | Whether `changed` flag is calculated (performance) |
Expand All @@ -71,17 +78,18 @@ Both `FormCreateMixin` and `createForm` accept several arguments to configure th

The `form` object (name specified by mixin options) provides a simple API, particularly the field values and form flags. There are several additional utility methods to control the flags.

| Property | Description |
| -------------------------------------- | ------------------------------------------------------ |
| `_initial` | _Initial field values_ |
| `flags` | Form state flags |
| `fields` | Form field values |
| `getValues()` | Get form values |
| `setFlag(flag, value)` | Set a form flag (**only use for custom `flags`!**) |
| `setLoading(isLoading)` | Set the loading flag |
| `setSubmitting(isSubmitting)` | Set the submitting flag |
| `setValues(values, setInitial = true)` | Set the form values (optionally update initial values) |
| `reset()` | Reset the form to initial values |
| Property | Description |
| --------------------------------------- | ------------------------------------------------------ |
| `_initial` | _Initial field values_ |
| `flags` | Form state flags |
| `fields` | Form field values |
| `getValues()` | Get form values |
| `setFlag(flag, value)` | Set a form flag (**only use for custom `flags`!**) |
| `setInitial(values)` | Set the initial form values |
| `setLoading(isLoading)` | Set the loading flag |
| `setSubmitting(isSubmitting)` | Set the submitting flag |
| `setValues(values, setInitial = false)` | Set the form values (update initial values by default) |
| `reset()` | Reset the form to initial values |

> **NOTE:** Included form `flags` are handled internally and should not be modified with `setFlags()` method!
Expand All @@ -96,62 +104,89 @@ The form flags are computed from the form state and should not be modified direc
| `loading` | Whether form is loading | `setLoading()` |
| `submitting` | Whether form is submitting | `setSubmitting()` |

## `FormLeaveGuardMixin`
## [DEPRECATED] `FormCreateMixin`

> **NOTE:** This has been deprecated in favour of the fully typed `createForm`.
## `FormGuardMixin`

### Usage

The `FormLeaveGuardMixin` provides helpers to prevent leaving a form (managed by `FormCreateMixin`) with unsaved data. These helpers can be utilized by the component to allow the user to handle the route change or cancellation based on the provided properties. The mixin checks the `changed` flag of a form (or forms) created by the `FormCreateMixin`.
The `FormGuardMixin` provides helpers to prevent leaving a form (managed by `createForm`) with unsaved data. These helpers can be utilized by the component to allow the user to handle the route change or cancellation based on the provided properties. The mixin checks the `changed` flag of a form (or forms) created by the `createForm`.

```js
import { FormLeaveGuardMixin } from "@kendallroth/vue-simple-forms";
import { createForm, FormGuardMixin } from "@kendallroth/vue-simple-forms";

const vm = new Vue({
mixins: [
FormLeaveGuardMixin("testForm", {
activeKey: "isLeavingForm",
callbackKey: "formLeaveCallback",
onlyPrevent: false, // Would render "activeKey" useless
// onPrevent: (callback) => Vuex.commit("SHOW_ROUTE_LEAVE", { callback })
}),
],
// mixins: [FormLeaveGuardMixin(["testForm", "anotherForm")],
data() {
sampleForm: createForm(...),
formGuards: [this.sampleForm],
},
mixins: [FormLeaveGuardMixin],
template: `
<template>
<ConfirmDialog
v-if="isLeavingForm"
@confirm="formLeaveCallback(true)"
@cancel="formLeaveCallback(false)"
v-if="isFormGuardActive"
text="Are you sure? There are unsaved changes!"
@confirm="onFormLeave(true)"
@cancel="onFormLeave(false)"
/>
</template>
`,
});
```

Alternatively, TypeScript users will benefit from `vue-property-decorator` integration:

```js
import { createForm, FormGuardMixin } from "@kendallroth/vue-simple-forms";
import { Component, Mixins } from "vue-property-decorator";

@Component({
template: `
<template>
<ConfirmDialog
v-if="isFormGuardActive"
text="Are you sure? There are unsaved changes!"
@confirm="onFormLeave(true)"
@cancel="onFormLeave(false)"
/>
</template>
`,
})
export default class Form extends Mixins(FormGuardMixin) {
testForm = createForm({ ... });
formGards = [this.testForm]

mounted() {
this.testForm.setValues({ ... });
}
}

```

### API

### Config

`FormLeaveGuardMixin` accepts several arguments to configure the form.
`FormGuardMixin` accepts a configuration `data` variable.

| Property | Type | Default | Description |
| ----------------------------- | ----------------- | ------------------- | ------------------------------------------------------------- |
| `formNames` | `string|string[]` | | Form `data` key name |
| `options` | `Object` | `{}` | Form configuration options |
| `options.activeKey` | `string` | `isLeaveFormActive` | Key name to indicate when form leave guard is active |
| `options.callbackKey` | `string` | `formLeaveCallback` | Key name for route leave confirmation callback |
| `options.onlyPrevent` | `boolean` | `false` | Whether to only prevent leaving form ("activeKey" is useless) |
| `options.onPrevent(callback)` | `function` | `() => {}` | Custom prevention handler (ie. for handling with Vuex, etc) |
| Property | Type | Description |
| ------------ | -------- | ------------------------------------ |
| `formGuards` | `Form[]` | Form objects created by `createForm` |

### Mixin Data

The `FormLeaveGuardMixin` provides a computed property to control a confirmation dialog (or other form) and a callback to handle leaving or remaining at the form.
The `FormGuardMixin` provides a computed property to control a confirmation dialog (or other form) and a callback to handle leaving or remaining at the form.

| Property | Description |
| ---------------------------------- | -------------------------------------------------- |
| `isLeaveFormActive`\* | Whether the leave route protection is active/shown |
| `formLeaveCallback(shouldLeave)`\* | Confirmation callback (from dialog, etc) |
| Property | Description |
| -------------------------- | -------------------------------------------------- |
| `isFormGuardActive` | Whether the leave route protection is active/shown |
| `onFormLeave(shouldLeave)` | Confirmation callback (from dialog, etc) |

> **NOTE:** Since these API names can be configured, use the appropriate names from the mixin constructor.
## [DEPRECATED] `FormLeaveGuardMixin`

> **NOTE:** This has been deprecated in favour of the fully typed `FormGuardMixin`.
## Development

Expand All @@ -170,6 +205,10 @@ This project can be started and will automatically rebuild on file changes:
npm run build:dev
```

See [this link](https://www.typescriptlang.org/docs/handbook/babel-with-typescript.html) for information on using TypeScript with Babel. In summary, TypeScript is used for type checking but Babel is used for transpilation!

> **NOTE:** Coverage tests are currently broken after the switch to TypeScript, and some had to be disabled!
## Miscellaneous

> Project boilerplate from: [`flexdinesh/npm-module-boilerplate`](https://github.com/flexdinesh/npm-module-boilerplate)
37 changes: 14 additions & 23 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
const { BABEL_ENV } = process.env;

const isProduction = BABEL_ENV === "production";

module.exports = {
env: {
development: {
presets: ["@babel/preset-env"],
plugins: ["add-module-exports"],
},
production: {
presets: ["@babel/preset-env", "minify"],
plugins: ["add-module-exports"],
},
test: {
presets: [
[
"@babel/preset-env",
{
targets: {
node: "current",
},
},
],
],
plugins: ["add-module-exports"],
},
},
presets: [
"@babel/preset-env",
"@babel/typescript",
isProduction && "minify",
].filter(Boolean),
plugins: [
["@babel/plugin-proposal-decorators", { legacy: true }],
["@babel/plugin-proposal-class-properties", { loose: true }],
"@babel/proposal-object-rest-spread",
],
};

0 comments on commit d2586e7

Please sign in to comment.