@api-components/api-form-mixin
Advanced tools
Comparing version
@@ -14,4 +14,2 @@ /** | ||
*/ | ||
import {dedupingMixin} from '../../@polymer/polymer/lib/utils/mixin.js'; | ||
/** | ||
@@ -25,272 +23,321 @@ * A behavior to be implemented to elements that processes AMF data via form | ||
* | ||
* @polymer | ||
* @mixinFunction | ||
* @memberof ArcBehaviors | ||
* @param {Class} base | ||
* @return {Class} | ||
*/ | ||
export const ApiFormMixin = dedupingMixin((base) => { | ||
/** | ||
* @polymer | ||
* @mixinClass | ||
*/ | ||
class AFmixin extends base { | ||
static get properties() { | ||
return { | ||
/** | ||
* View model to use to render the form. | ||
*/ | ||
model: { | ||
type: Array, | ||
notify: true | ||
}, | ||
/** | ||
* Set to true to show optional parameters (not required by the API). | ||
*/ | ||
optionalOpened: { | ||
type: Boolean, | ||
reflectToAttribute: true | ||
}, | ||
/** | ||
* Computed value from `allowHideOptional` and view model. | ||
* `true` if current model has any optional property. | ||
*/ | ||
hasOptional: { | ||
type: Boolean, | ||
computed: '_computeHasOptionalParameters(allowHideOptional, model.*)', | ||
notify: true | ||
}, | ||
/** | ||
* If set it computes `hasOptional` property and shows checkbox in the | ||
* form to show / hide optional properties. | ||
*/ | ||
allowHideOptional: Boolean, | ||
/** | ||
* Computed flag to determine if optional checkbox can be rendered | ||
*/ | ||
renderOptionalCheckbox: { | ||
type: Boolean, | ||
computed: '_computeRenderCheckbox(allowHideOptional, hasOptional)' | ||
}, | ||
/** | ||
* If set, enable / disable param checkbox is rendered next to each | ||
* form item. | ||
*/ | ||
allowDisableParams: Boolean, | ||
/** | ||
* When set, renders "add custom" item button. | ||
* If the element is to be used withouth AMF model this should always | ||
* be enabled. Otherwise users won't be able to add a parameter. | ||
*/ | ||
allowCustom: Boolean, | ||
/** | ||
* Renders items in "narrow" view | ||
*/ | ||
narrow: Boolean, | ||
/** | ||
* Computed value. The form renders empty message (if supported by | ||
* the form element). It occurs when model is not set and allowCustom | ||
* is not set | ||
*/ | ||
renderEmptyMessage: { | ||
type: Boolean, | ||
value: true, | ||
computed: '_computeRenderEmptyMessage(allowCustom, model)' | ||
} | ||
}; | ||
export const ApiFormMixin = (base) => class extends base { | ||
static get properties() { | ||
return { | ||
/** | ||
* View model to use to render the form. | ||
*/ | ||
model: { type: Array }, | ||
/** | ||
* Set to true to show optional parameters (not required by the API). | ||
*/ | ||
optionalOpened: { | ||
type: Boolean, | ||
reflect: true | ||
}, | ||
/** | ||
* Computed value from `allowHideOptional` and view model. | ||
* `true` if current model has any optional property. | ||
*/ | ||
hasOptional: { type: Boolean }, | ||
/** | ||
* If set it computes `hasOptional` property and shows checkbox in the | ||
* form to show / hide optional properties. | ||
*/ | ||
allowHideOptional: { type: Boolean }, | ||
/** | ||
* Computed flag to determine if optional checkbox can be rendered | ||
*/ | ||
renderOptionalCheckbox: { type: Boolean }, | ||
/** | ||
* If set, enable / disable param checkbox is rendered next to each | ||
* form item. | ||
*/ | ||
allowDisableParams: { type: Boolean }, | ||
/** | ||
* When set, renders "add custom" item button. | ||
* If the element is to be used withouth AMF model this should always | ||
* be enabled. Otherwise users won't be able to add a parameter. | ||
*/ | ||
allowCustom: { type: Boolean }, | ||
/** | ||
* Renders items in "narrow" view | ||
*/ | ||
narrow: { type: Boolean }, | ||
/** | ||
* Computed value. The form renders empty message (if supported by | ||
* the form element). It occurs when model is not set and allowCustom | ||
* is not set | ||
*/ | ||
renderEmptyMessage: { type: Boolean } | ||
}; | ||
} | ||
get model() { | ||
return this._model; | ||
} | ||
set model(value) { | ||
if (this._sop('model', value)) { | ||
this._notifyChanged('model', value); | ||
this.renderEmptyMessage = this._computeRenderEmptyMessage(this.allowCustom, value); | ||
this.hasOptional = this._computeHasOptionalParameters(this.allowHideOptional, value); | ||
} | ||
/** | ||
* Computes class name for each form item depending on the item state. | ||
* | ||
* @param {Object} item Model item | ||
* @param {Boolean} allowHideOptional | ||
* @param {Boolean} optionalOpened True if optional parameters are rendered. | ||
* @param {Boolean} allowDisableParams | ||
* @return {String} | ||
*/ | ||
computeFormRowClass(item, allowHideOptional, optionalOpened, allowDisableParams) { | ||
let clazz = 'param-value'; | ||
if (item && item.required) { | ||
clazz += ' required'; | ||
} else if (allowHideOptional) { | ||
clazz += ' optional'; | ||
} | ||
if (optionalOpened) { | ||
clazz += ' with-optional'; | ||
} | ||
if (allowDisableParams) { | ||
clazz += ' has-enable-button'; | ||
} | ||
return clazz; | ||
} | ||
get allowCustom() { | ||
return this._allowCustom; | ||
} | ||
set allowCustom(value) { | ||
if (this._sop('allowCustom', value)) { | ||
this.renderEmptyMessage = this._computeRenderEmptyMessage(value, this.model); | ||
} | ||
/** | ||
* Toggles visibility of optional parameters. | ||
*/ | ||
toggleOptionalParams() { | ||
if (!this.allowHideOptional) { | ||
return; | ||
} | ||
this.optionalOpened = !this.optionalOpened; | ||
} | ||
get allowHideOptional() { | ||
return this._allowHideOptional; | ||
} | ||
set allowHideOptional(value) { | ||
if (this._sop('allowHideOptional', value)) { | ||
this.hasOptional = this._computeHasOptionalParameters(value, this.model); | ||
this.renderOptionalCheckbox = this._computeRenderCheckbox(value, this.hasOptional); | ||
} | ||
} | ||
/** | ||
* Returns a reference to the form element, if the DOM is ready. | ||
* This only works with `iron-form` that is in the DOM. | ||
* | ||
* @return {IronForm} Iron form element. It may be `undefined` if local | ||
* DOM is not yet initialized. | ||
*/ | ||
_getForm() { | ||
if (!this.$.form && this.shadowRoot) { | ||
this.$.form = this.shadowRoot.querySelector('iron-form'); | ||
} | ||
return this.$.form; | ||
get hasOptional() { | ||
return this._hasOptional; | ||
} | ||
set hasOptional(value) { | ||
if (this._sop('hasOptional', value)) { | ||
this._notifyChanged('hasOptional', value); | ||
this.renderOptionalCheckbox = this._computeRenderCheckbox(this.allowHideOptional, value); | ||
} | ||
/** | ||
* Validates the form. It uses `iron-form`'s `validate()` function to | ||
* perform the validation. | ||
* @return {Boolean} Validation result or `true` if DOM is not yet ready. | ||
*/ | ||
_getValidity() { | ||
const form = this._getForm(); | ||
if (!form) { | ||
return true; | ||
} | ||
return form.validate(); | ||
} | ||
constructor() { | ||
super(); | ||
this.renderEmptyMessage = true; | ||
} | ||
_sop(prop, value) { | ||
const key = `_${prop}`; | ||
const old = this[key]; | ||
if (old === value) { | ||
return false; | ||
} | ||
/** | ||
* Link to the form's serialize function. | ||
* @return {Object} Serialized form values or `undefined` if DOM is not ready. | ||
* Note, `undefined` is returned **only** if DOM is not yet ready. | ||
*/ | ||
serializeForm() { | ||
const form = this._getForm(); | ||
if (!form) { | ||
return; | ||
this[key] = value; | ||
this.requestUpdate(prop, old); | ||
return true; | ||
} | ||
_notifyChanged(prop, value) { | ||
this.dispatchEvent(new CustomEvent(prop + '-changed', { | ||
composed: true, | ||
detail: { | ||
value | ||
} | ||
return form.serializeForm(); | ||
})); | ||
} | ||
/** | ||
* Computes class name for each form item depending on the item state. | ||
* | ||
* @param {Object} item Model item | ||
* @param {Boolean} allowHideOptional | ||
* @param {Boolean} optionalOpened True if optional parameters are rendered. | ||
* @param {Boolean} allowDisableParams | ||
* @return {String} | ||
*/ | ||
computeFormRowClass(item, allowHideOptional, optionalOpened, allowDisableParams) { | ||
let clazz = 'param-value'; | ||
if (item && item.required) { | ||
clazz += ' required'; | ||
} else if (allowHideOptional) { | ||
clazz += ' optional'; | ||
} | ||
/** | ||
* Computes if any of the parameters are required. | ||
* It iterates over the model to find any first element that has `required` | ||
* propeerty set to `false`. | ||
* | ||
* @param {Boolean} allowHideOptional State of `allowHideOptional` property. | ||
* If `false` this function always returns `false`. | ||
* @param {Object} record Change record. Note, it does not checks for | ||
* optional parameters each time the model changes. It rescans the model | ||
* when splices changed. | ||
* @return {Boolean} `true` if model has at leas one alement that is not required. | ||
*/ | ||
_computeHasOptionalParameters(allowHideOptional, record) { | ||
if (!allowHideOptional || !record.base || !record.path) { | ||
return false; | ||
} | ||
if (record.path !== 'model' && record.path !== 'model.splices') { | ||
return this.hasOptional; | ||
} | ||
return record.base.some((item) => item.required === false); | ||
if (optionalOpened) { | ||
clazz += ' with-optional'; | ||
} | ||
/** | ||
* Computes value for `renderOptionalCheckbox` property. | ||
* | ||
* @param {Boolean} render Value of `allowHideOptional` property | ||
* @param {Boolean} has Value of `hasOptional` property. | ||
* @return {Boolean} True if both values are `true`. | ||
*/ | ||
_computeRenderCheckbox(render, has) { | ||
return render && has; | ||
if (allowDisableParams) { | ||
clazz += ' has-enable-button'; | ||
} | ||
/** | ||
* Computes if given model item is a custom property (not generated by | ||
* AMF model transformation). | ||
* @param {Object} model Model item. | ||
* @return {Boolean} `true` if `isCustom` property is set on model's schema | ||
* property. | ||
*/ | ||
_computeIsCustom(model) { | ||
if (!model || !model.schema || !model.schema.isCustom) { | ||
return false; | ||
} | ||
return clazz; | ||
} | ||
/** | ||
* Toggles visibility of optional parameters. | ||
*/ | ||
toggleOptionalParams() { | ||
if (!this.allowHideOptional) { | ||
return; | ||
} | ||
this.optionalOpened = !this.optionalOpened; | ||
} | ||
/** | ||
* Returns a reference to the form element, if the DOM is ready. | ||
* This only works with `iron-form` that is in the DOM. | ||
* | ||
* @return {IronForm} Iron form element. It may be `undefined` if local | ||
* DOM is not yet initialized. | ||
*/ | ||
_getForm() { | ||
if (!this.__form && this.shadowRoot) { | ||
this.__form = this.shadowRoot.querySelector('iron-form'); | ||
} | ||
return this.__form; | ||
} | ||
/** | ||
* Validates the form. It uses `iron-form`'s `validate()` function to | ||
* perform the validation. | ||
* @return {Boolean} Validation result or `true` if DOM is not yet ready. | ||
*/ | ||
_getValidity() { | ||
const form = this._getForm(); | ||
if (!form) { | ||
return true; | ||
} | ||
/** | ||
* Adds empty custom property to the list. | ||
* | ||
* It dispatches `api-property-model-build` custom event that is handled by | ||
* `api-view-model-transformer` to build model item. | ||
* This assumem that the transformer element is already in the DOM. | ||
* | ||
* After the transformation the element pushes or sets the data to the | ||
* `model`. | ||
* | ||
* @param {String} binding Value if the `binding` property. | ||
* @param {Object} opts Additional options: | ||
* - inputLabel {String} - Forces a label of the input | ||
*/ | ||
addCustom(binding, opts) { | ||
if (!opts) { | ||
opts = {}; | ||
} | ||
const e = new CustomEvent('api-property-model-build', { | ||
bubbles: true, | ||
composed: true, | ||
cancelable: true, | ||
detail: { | ||
name: opts.name || '', | ||
value: opts.value || '', | ||
binding: binding, | ||
schema: { | ||
enabled: true, | ||
isCustom: true, | ||
inputLabel: opts.inputLabel || undefined | ||
} | ||
return form.validate(); | ||
} | ||
/** | ||
* Link to the form's serialize function. | ||
* @return {Object} Serialized form values or `undefined` if DOM is not ready. | ||
* Note, `undefined` is returned **only** if DOM is not yet ready. | ||
*/ | ||
serializeForm() { | ||
const form = this._getForm(); | ||
if (!form) { | ||
return; | ||
} | ||
return form.serializeForm(); | ||
} | ||
/** | ||
* Computes if any of the parameters are required. | ||
* It iterates over the model to find any first element that has `required` | ||
* propeerty set to `false`. | ||
* | ||
* @param {Boolean} allowHideOptional State of `allowHideOptional` property. | ||
* If `false` this function always returns `false`. | ||
* @param {Object} model Current model | ||
* @return {Boolean} `true` if model has at leas one alement that is not required. | ||
*/ | ||
_computeHasOptionalParameters(allowHideOptional, model) { | ||
if (!allowHideOptional || !model) { | ||
return false; | ||
} | ||
return model.some((item) => item.required === false); | ||
} | ||
/** | ||
* Computes value for `renderOptionalCheckbox` property. | ||
* | ||
* @param {Boolean} render Value of `allowHideOptional` property | ||
* @param {Boolean} has Value of `hasOptional` property. | ||
* @return {Boolean} True if both values are `true`. | ||
*/ | ||
_computeRenderCheckbox(render, has) { | ||
return render && has; | ||
} | ||
/** | ||
* Computes if given model item is a custom property (not generated by | ||
* AMF model transformation). | ||
* @param {Object} model Model item. | ||
* @return {Boolean} `true` if `isCustom` property is set on model's schema | ||
* property. | ||
*/ | ||
_computeIsCustom(model) { | ||
if (!model || !model.schema || !model.schema.isCustom) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
/** | ||
* Adds empty custom property to the list. | ||
* | ||
* It dispatches `api-property-model-build` custom event that is handled by | ||
* `api-view-model-transformer` to build model item. | ||
* This assumem that the transformer element is already in the DOM. | ||
* | ||
* After the transformation the element pushes or sets the data to the | ||
* `model`. | ||
* | ||
* @param {String} binding Value if the `binding` property. | ||
* @param {Object} opts Additional options: | ||
* - inputLabel {String} - Forces a label of the input | ||
*/ | ||
addCustom(binding, opts) { | ||
if (!opts) { | ||
opts = {}; | ||
} | ||
const e = new CustomEvent('api-property-model-build', { | ||
bubbles: true, | ||
composed: true, | ||
cancelable: true, | ||
detail: { | ||
name: opts.name || '', | ||
value: opts.value || '', | ||
binding: binding, | ||
schema: { | ||
enabled: true, | ||
isCustom: true, | ||
inputLabel: opts.inputLabel || undefined | ||
} | ||
}); | ||
this.dispatchEvent(e); | ||
if (this.model) { | ||
this.push('model', e.detail); | ||
} else { | ||
this.set('model', [e.detail]); | ||
} | ||
this.optionalOpened = true; | ||
}); | ||
this.dispatchEvent(e); | ||
const model = this.model || []; | ||
this.model = [...model, e.detail]; | ||
this.optionalOpened = true; | ||
} | ||
/** | ||
* Removes custom item from the UI. | ||
* This can only be called from `dom-repeat` element so it contain's | ||
* `model` property. | ||
* | ||
* @param {CustomEvent} e | ||
*/ | ||
_removeCustom(e) { | ||
const index = Number(e.target.dataset.index); | ||
if (index !== index) { | ||
return; | ||
} | ||
/** | ||
* Removes custom item from the UI. | ||
* This can only be called from `dom-repeat` element so it contain's | ||
* `model` property. | ||
* | ||
* @param {CustomEvent} e | ||
*/ | ||
_removeCustom(e) { | ||
this.splice('model', e.model.get('index'), 1); | ||
const model = this.model; | ||
if (!model || !model.length) { | ||
return; | ||
} | ||
/** | ||
* Computes if model item is optional. | ||
* The items is always optional if is not required and when `hasOptional` | ||
* is set to `true`. | ||
* | ||
* @param {Boolean} hasOptional [description] | ||
* @param {Object} model Model item. | ||
* @return {Boolean} `true` if the model item is optional in the form. | ||
*/ | ||
computeIsOptional(hasOptional, model) { | ||
if (!hasOptional) { | ||
return false; | ||
} | ||
if (!model || !model.required) { | ||
return true; | ||
} | ||
model.splice(index, 1); | ||
this.model = Array.from(model); | ||
} | ||
/** | ||
* Computes if model item is optional. | ||
* The items is always optional if is not required and when `hasOptional` | ||
* is set to `true`. | ||
* | ||
* @param {Boolean} hasOptional [description] | ||
* @param {Object} model Model item. | ||
* @return {Boolean} `true` if the model item is optional in the form. | ||
*/ | ||
computeIsOptional(hasOptional, model) { | ||
if (!hasOptional) { | ||
return false; | ||
} | ||
/** | ||
* Computes value for `renderEmptyMessage`. | ||
* | ||
* @param {Boolean} allowCustom True if the form allows to add custom values. | ||
* @param {?Array} model Current model | ||
* @return {Boolean} `true` when allowCustom is falsy set and model is empty | ||
*/ | ||
_computeRenderEmptyMessage(allowCustom, model) { | ||
return !allowCustom && !model; | ||
if (!model || !model.required) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
return AFmixin; | ||
}); | ||
/** | ||
* Computes value for `renderEmptyMessage`. | ||
* | ||
* @param {Boolean} allowCustom True if the form allows to add custom values. | ||
* @param {?Array} model Current model | ||
* @return {Boolean} `true` when allowCustom is falsy set and model is empty | ||
*/ | ||
_computeRenderEmptyMessage(allowCustom, model) { | ||
return !allowCustom && !model; | ||
} | ||
}; |
@@ -1,3 +0,2 @@ | ||
import '../../@polymer/polymer/polymer-element.js'; | ||
const $documentContainer = document.createElement('template'); | ||
import { css } from 'lit-element'; | ||
@@ -9,18 +8,8 @@ /** | ||
----------------|-------------|---------- | ||
`--api-form-row` | Mixin applied to API form rows. Each row already applies `--layout-horizontal` and `--layout-start` | `{}` | ||
`--api-form-row-narrow` | Mixin applied to API form rows when `narrow` property is set | `{}` | ||
`--api-form-row-optional` | Mixin applied to optional row of the form (not required). By default this form row is hidden from the view | `{}` | ||
`--api-form-row-optional-visible` | Mixin applied to optional row of the form when it becomes visible | `{}` | ||
`--api-form-action-button-color` | Color of the action button in the form. Action buttons should perform form's primary actions like "submit" or "add new". Use `--api-form-action-icon-*` for icons related styling | `--secondary-button-color` or `--accent-color` | ||
`--api-form-action-button-background-color` | Similar to `--api-form-action-button-color` but it's background color | `--secondary-button-background` | ||
`--secondary-button` | Mixin applied to the action button. This is more general theme element. This values can be overriten by `--api-form-action-button` | `{}` | ||
`--api-form-action-button` | Mixin applied to the action button | `{}` | ||
`--api-form-action-button-hover-color` | Color of the action button in the form when hovering. | `--secondary-button-color` or `--accent-color` | ||
`--api-form-action-button-hover-background-color` | Similar to `--api-form-action-button-hover-color` but it's background color | `--secondary-button-background` | ||
`--secondary-button-hover` | Mixin applied to the action button when hovered. This is more general theme element. This values can be overriten by `--api-form-action-button` | `{}` | ||
`--api-form-action-button-hover` | Mixin applied to the action button when hovered. | `{}` | ||
`--hint-trigger-color` | Color of the form action icon button to dispay documentation for the item. | `rgba(0, 0, 0, 0.74)` | ||
`--icon-button` | Mixin applied to the icon button to dispay documentation for the item | `{}` | ||
`--hint-trigger-hover-color` | Color of the form action icon button to dispay documentation for the item when hovered | `rgba(0, 0, 0, 0.74)` | ||
`--icon-button-hover` | Mixin applied to the icon button to dispay documentation for the item when hovered | `{}` | ||
`--api-form-action-icon-color` | Color of any other than documentation icon button in form row | `--icon-button-color` or `rgba(0, 0, 0, 0.74)` | ||
@@ -33,101 +22,88 @@ `--api-form-action-icon-hover-color` | Color of any other than documentation icon button in form row when hovering | `--accent-color` or `rgba(0, 0, 0, 0.88)` | ||
$documentContainer.innerHTML = `<dom-module id="api-form-styles"> | ||
<template> | ||
<style> | ||
.form-item { | ||
@apply --layout-horizontal; | ||
@apply --layout-start; | ||
@apply --api-form-row; | ||
} | ||
export default css` | ||
.form-item { | ||
display: flex; | ||
flex-direction: row; | ||
align-items: flex-start; | ||
} | ||
:host([narrow]) .form-item, | ||
.narrow .form-item { | ||
display: block; | ||
@apply --api-form-row-narrow; | ||
} | ||
:host([narrow]) .form-item, | ||
.narrow .form-item { | ||
display: block; | ||
} | ||
.form-item[data-optional] { | ||
display: none; | ||
@apply --api-form-row-optional; | ||
} | ||
.form-item[data-optional] { | ||
display: none; | ||
} | ||
:host([optional-opened]) [data-optional] { | ||
@apply --layout-horizontal; | ||
@apply --api-form-row-optional-visible; | ||
} | ||
/* General action button like "add property" etc */ | ||
.action-button { | ||
transition: color 0.25s ease-in-out, background-color 0.25s ease-in-out; | ||
margin: var(--api-form-action-button-margin-top, 0); | ||
color: var(--api-form-action-button-color, var(--secondary-button-color, var(--accent-color))); | ||
background-color: var(--api-form-action-button-background-color, var(--secondary-button-background)); | ||
@apply --secondary-button; | ||
@apply --api-form-action-button; | ||
} | ||
:host([optional-opened]) [data-optional] { | ||
display: flex; | ||
flex-direction: row; | ||
} | ||
/* General action button like "add property" etc */ | ||
.action-button { | ||
transition: color 0.25s ease-in-out, background-color 0.25s ease-in-out; | ||
margin: var(--api-form-action-button-margin-top, 0); | ||
color: var(--api-form-action-button-color, var(--secondary-button-color, var(--accent-color))); | ||
background-color: var(--api-form-action-button-background-color, var(--secondary-button-background)); | ||
} | ||
.action-button:hover { | ||
color: var(--api-form-action-button-hover-color, var(--secondary-button-color, var(--accent-color))); | ||
background-color: var(--api-form-action-button-hover-background-color, var(--secondary-button-background)); | ||
@apply --secondary-button-hover; | ||
@apply --api-form-action-button-hover; | ||
} | ||
/* Any icon element inside the action button should inherit the same styles */ | ||
.action-button .action-icon { | ||
margin-right: 12px; | ||
color: var(--api-form-action-button-color, var(--secondary-button-color, var(--accent-color))); | ||
} | ||
.action-button:hover { | ||
color: var(--api-form-action-button-hover-color, var(--secondary-button-color, var(--accent-color))); | ||
background-color: var(--api-form-action-button-hover-background-color, var(--secondary-button-background)); | ||
} | ||
/* Any icon element inside the action button should inherit the same styles */ | ||
.action-button .action-icon { | ||
margin-right: 12px; | ||
color: var(--api-form-action-button-color, var(--secondary-button-color, var(--accent-color))); | ||
} | ||
.action-button:hover .action-icon { | ||
color: var(--api-form-action-button-hover-color, var(--secondary-button-color, var(--accent-color))); | ||
} | ||
.action-button:hover .action-icon { | ||
color: var(--api-form-action-button-hover-color, var(--secondary-button-color, var(--accent-color))); | ||
} | ||
/* Icons that provide additional documentation to the form item */ | ||
.hint-icon { | ||
color: var(--hint-trigger-color, rgba(0, 0, 0, 0.74)); | ||
transition: color 0.25s ease-in-out; | ||
@apply --icon-button; | ||
} | ||
/* Icons that provide additional documentation to the form item */ | ||
.hint-icon { | ||
color: var(--hint-trigger-color, rgba(0, 0, 0, 0.74)); | ||
transition: color 0.25s ease-in-out; | ||
} | ||
.hint-icon:hover { | ||
color: var(--hint-trigger-hover-color, var(--accent-color, rgba(0, 0, 0, 0.88))); | ||
@apply --icon-button-hover; | ||
} | ||
/* An icon in the form row that performs some action other than documentation. */ | ||
.action-icon { | ||
color: var(--api-form-action-icon-color, var(--icon-button-color, rgba(0, 0, 0, 0.74))); | ||
transition: color 0.2s ease-in-out; | ||
} | ||
.hint-icon:hover { | ||
color: var(--hint-trigger-hover-color, var(--accent-color, rgba(0, 0, 0, 0.88))); | ||
} | ||
/* An icon in the form row that performs some action other than documentation. */ | ||
.action-icon { | ||
color: var(--api-form-action-icon-color, var(--icon-button-color, rgba(0, 0, 0, 0.74))); | ||
transition: color 0.2s ease-in-out; | ||
} | ||
.action-icon:hover { | ||
color: var(--api-form-action-icon-hover-color, var(--accent-color, rgba(0, 0, 0, 0.88))); | ||
} | ||
/* styling form inline markdown */ | ||
marked-element { | ||
background-color: var(--inline-documentation-background-color, #FFF3E0); | ||
padding: 4px; | ||
} | ||
/* wrapped for \`marked-element\` */ | ||
.docs { | ||
@apply --arc-font-body1; | ||
color: var(--inline-documentation-color, rgba(0, 0, 0, 0.87)); | ||
margin-right: 40px; | ||
} | ||
.action-icon:hover { | ||
color: var(--api-form-action-icon-hover-color, var(--accent-color, rgba(0, 0, 0, 0.88))); | ||
} | ||
/* styling form inline markdown */ | ||
arc-marked { | ||
background-color: var(--inline-documentation-background-color, #FFF3E0); | ||
padding: 4px; | ||
} | ||
/* wrapped for \`arc-marked\` */ | ||
.docs { | ||
font-size: var(--arc-font-body1-font-size); | ||
font-weight: var(--arc-font-body1-font-weight); | ||
line-height: var(--arc-font-body1-line-height); | ||
color: var(--inline-documentation-color, rgba(0, 0, 0, 0.87)); | ||
margin-right: 40px; | ||
} | ||
.markdown-body * { | ||
font-size: var(--inline-documentation-font-size, 13px) !important; | ||
} | ||
.markdown-body * { | ||
font-size: var(--inline-documentation-font-size, 13px) !important; | ||
} | ||
.markdown-body p:first-child { | ||
margin-top: 0; | ||
padding-top: 0; | ||
} | ||
.markdown-body p:first-child { | ||
margin-top: 0; | ||
padding-top: 0; | ||
} | ||
.markdown-body p:last-child { | ||
margin-bottom: 0; | ||
padding-bottom: 0; | ||
} | ||
</style> | ||
</template> | ||
</dom-module>`; | ||
document.head.appendChild($documentContainer.content); | ||
.markdown-body p:last-child { | ||
margin-bottom: 0; | ||
padding-bottom: 0; | ||
}`; |
@@ -15,14 +15,13 @@ { | ||
"name": "@api-components/api-form-mixin", | ||
"version": "3.0.0-preview.2", | ||
"version": "3.0.0-preview.3", | ||
"license": "Apache-2.0", | ||
"devDependencies": { | ||
"@polymer/gen-typescript-declarations": "^1.6.0", | ||
"@polymer/iron-demo-helpers": "^3.0.0", | ||
"@webcomponents/webcomponentsjs": "^2.0.0", | ||
"@polymer/iron-component-page": "^4.0.0", | ||
"@advanced-rest-client/arc-demo-helper": "^1.0.3", | ||
"@advanced-rest-client/testing-karma-sl": "^1.0.2", | ||
"@open-wc/testing": "^0.11.1", | ||
"@open-wc/testing-karma": "^2.0.6", | ||
"@polymer/gen-typescript-declarations": "^1.6.2", | ||
"@polymer/iron-form": "^3.0.0", | ||
"@polymer/test-fixture": "^4.0.2", | ||
"chai": "^4.2.0", | ||
"mocha": "^5.2.0", | ||
"wct-mocha": "^1.0.0" | ||
"@webcomponents/webcomponentsjs": "^2.2.10", | ||
"lit-element": "^2.0.1" | ||
}, | ||
@@ -35,5 +34,7 @@ "main": "api-form-mixin.js", | ||
"scripts": { | ||
"lint": "polymer lint api-form-mixin.html", | ||
"test-sauce": "polymer test --plugin sauce --job-name \"api-form-mixin:local-test\"", | ||
"test": "polymer test --plugin local", | ||
"test": "karma start --coverage", | ||
"test:watch": "karma start --auto-watch=true --single-run=false", | ||
"test:legacy": "karma start --legacy --coverage", | ||
"test:legacy:watch": "karma start --legacy --auto-watch=true --single-run=false", | ||
"test:sl": "karma start karma.sl.config.js --legacy --coverage", | ||
"update-types": "gen-typescript-declarations --deleteExisting --outDir ." | ||
@@ -50,4 +51,4 @@ }, | ||
"dependencies": { | ||
"@polymer/polymer": "^3.0.0" | ||
"lit-element": "^2.0.1" | ||
} | ||
} |
@@ -7,11 +7,85 @@ [](https://travis-ci.org/advanced-rest-client/api-form-mixin) | ||
A behavior to be implemented to elements that processes AMF data via form data model and displays forms from the model. | ||
A mixin to be used with elements that processes AMF data via form data model and displays forms from the model. | ||
It contains common methods used in forms. | ||
Use `api-form-styles` from this package to include common styles. | ||
### API components | ||
This components is a part of [API components ecosystem](https://elements.advancedrestclient.com/) | ||
### API components | ||
## Usage | ||
This components is a part of API components ecosystem: https://elements.advancedrestclient.com/ | ||
### Installation | ||
``` | ||
npm install --save @api-components/api-form-mixin | ||
``` | ||
### In a LitElement | ||
```js | ||
import { LitElement, html, css } from 'lit-element'; | ||
import { ApiFormMixin } from '@api-components/api-form-mixin/api-form-mixin.js'; | ||
import styles from '@api-components/api-form-mixin/api-form-styles.js'; | ||
import '@polymer/iron-form/iron-form.js'; | ||
class SampleElement extends PolymerElement { | ||
static get styles() { | ||
return [ | ||
styles, | ||
css`:host { | ||
display: block; | ||
}` | ||
]; | ||
} | ||
render() { | ||
const { model: items, allowHideOptional, optionalOpened, allowDisableParams } = this; | ||
return html` | ||
<h1>Form</h1> | ||
<iron-form> | ||
<form enctype="application/json"> | ||
${items ? items.map((item, index) => html`<div class="form-item"> | ||
<div class="${this.computeFormRowClass(item, allowHideOptional, optionalOpened, allowDisableParams)}"> | ||
<input | ||
data-index="${index}" | ||
type="text" | ||
name="${item.name}" | ||
?required="${item.required}" | ||
.value="${item.value}" | ||
@change="${this._modelValueChanged}"> | ||
</div> | ||
</div>`) : undefined} | ||
</form> | ||
</iron-form>`; | ||
} | ||
_modelValueChanged(e) { | ||
const index = Number(e.target.dataset.index); | ||
if (index !== index) { | ||
return; | ||
} | ||
this.model[index].value = e.target.value; | ||
this._requestRender(); | ||
} | ||
} | ||
customElements.define('sample-element', SampleElement); | ||
``` | ||
### Installation | ||
```sh | ||
git clone https://github.com/advanced-rest-client/api-form-mixin | ||
cd api-form-mixin | ||
npm install | ||
``` | ||
### Running the demo locally | ||
```sh | ||
npm start | ||
``` | ||
### Running the tests | ||
```sh | ||
npm test | ||
``` |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
27809
8.46%8
-11.11%9
28.57%667
12.29%91
435.29%5
Infinity%+ Added
+ Added
+ Added
- Removed
- Removed
- Removed