From 54d17571e551a4ab6cbe3089bb54815d4ed4ca19 Mon Sep 17 00:00:00 2001 From: Dylan Clarke Date: Tue, 13 Sep 2022 21:58:12 +0100 Subject: [PATCH] feat(Controller): New SignalEnable and SignalDisable controllers which can enable/disable elements based on whether a value matches a given expression --- .../signal/signal_action_controller.mdx | 14 +++- .../signal/signal_disable_controller.mdx | 75 +++++++++++++++++++ .../signal/signal_enable_controller.mdx | 74 ++++++++++++++++++ src/controllers/signal/events.ts | 5 -- src/controllers/signal/index.ts | 4 +- .../signal/signal_disable_controller.ts | 42 +++++++++++ .../signal/signal_enable_controller.ts | 42 +++++++++++ 7 files changed, 246 insertions(+), 10 deletions(-) create mode 100644 docs/docs/controllers/signal/signal_disable_controller.mdx create mode 100644 docs/docs/controllers/signal/signal_enable_controller.mdx create mode 100644 src/controllers/signal/signal_disable_controller.ts create mode 100644 src/controllers/signal/signal_enable_controller.ts diff --git a/docs/docs/controllers/signal/signal_action_controller.mdx b/docs/docs/controllers/signal/signal_action_controller.mdx index 4925c2ed..d575ad30 100644 --- a/docs/docs/controllers/signal/signal_action_controller.mdx +++ b/docs/docs/controllers/signal/signal_action_controller.mdx @@ -40,10 +40,16 @@ the same `nameValue` as the `nameValue` of this controller. ## Events -| Event | When | Dispatched on | `event.detail` | -|--------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|------------------------------------------------------------------------------| -| `signal:match:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _true_ against the new updated value | The controller root element | `element`: the controller root element,

`value`: the changed value | -| `signal:no-match:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _false_ against the new updated value | The controller root element | `element`: the controller root element,

`value`: the changed value | +| Event | When | Dispatched on | `event.detail` | | +|--------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|----------------|---------------------------------------------------------------| +| `signal:match:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _true_ against the new updated value | The controller root element | | | +| | | | `element` | the controller root element | +| | | | `predicate` | the expression the controller used to try and match the value | +| | | | `value` | the value that was received | +| `signal:no-match:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _false_ against the new updated value | The controller root element | | | +| | | | `element` | the controller root element | +| | | | `predicate` | the expression the controller used to try and match the value | +| | | | `value` | the value that was received | ## Side Effects diff --git a/docs/docs/controllers/signal/signal_disable_controller.mdx b/docs/docs/controllers/signal/signal_disable_controller.mdx new file mode 100644 index 00000000..a9febbdc --- /dev/null +++ b/docs/docs/controllers/signal/signal_disable_controller.mdx @@ -0,0 +1,75 @@ +--- +id: SignalDisableController +title: SignalDisableController +--- + + +import NoTargets from "../../_partials/no-targets.md"; +import NoActions from "../../_partials/no-actions.md"; +import NoSideEffects from "../../_partials/no-side-effects.md"; +import Expressions from "../../_partials/expressions.md"; +import NoClasses from "../../_partials/no-classes.md"; + +## Purpose + +A controller that responds to SignalInputController notifications. +This controller adds the `disabled` attribute from an element when a value-change notification evaluates to +false against the expression given in `whenValue` evaluate to true, and removes `disabled` when it evaluates to false. + +This controller can be anywhere in the DOM tree and it will receive notifications from any SignalInputController with +the same `nameValue` as the `nameValue` of this controller. + +### Example Use Cases +- Turn off inputs in a form when another input has a certain value, See also: SignalVisibiityController to hide elements when they are not needed. + +## [Actions](https://stimulus.hotwire.dev/reference/actions) + + +## [Targets](https://stimulus.hotwire.dev/reference/targets) + + +## [Classes](https://stimulus.hotwire.dev/reference/classes) + + +## [Values](https://stimulus.hotwire.dev/reference/values) + +| Value | Type | Description | Default | +|--------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------| +| `name` | String | The name of the input value whose value to react to. This name should be the same as the `nameValue` of the SignalInputController you want to sync with. | `-` | +| `when` | String | A simple _expression_ which will be evaluated against the value received from SignalInputController. If the expression evaluates to true, the controller will add the `disabled` attribute to the controller element, otherwise it will remove it . | `-` | + + + + +## Events + +| Event | When | Dispatched on | `event.detail` | | +|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|----------------|---------------------------------------------------------------| +| `signal:disable:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _true_ against the new updated value | The controller root element | | | +| | | | `element` | the controller root element | +| | | | `predicate` | the expression the controller used to try and match the value | +| | | | `value` | the value that was received | +| `signal:enable:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _false_ against the new updated value | The controller root element | | | +| | | | `element` | the controller root element | +| | | | `predicate` | the expression the controller used to try and match the value | +| | | | `value` | the value that was received | + + +## Side Effects + + +## How to Use + +```html + + + +
+ +
+ +``` diff --git a/docs/docs/controllers/signal/signal_enable_controller.mdx b/docs/docs/controllers/signal/signal_enable_controller.mdx new file mode 100644 index 00000000..f8effe86 --- /dev/null +++ b/docs/docs/controllers/signal/signal_enable_controller.mdx @@ -0,0 +1,74 @@ +--- +id: SignalEnableController +title: SignalEnableController +--- + +import NoTargets from "../../_partials/no-targets.md"; +import NoActions from "../../_partials/no-actions.md"; +import NoSideEffects from "../../_partials/no-side-effects.md"; +import Expressions from "../../_partials/expressions.md"; +import NoClasses from "../../_partials/no-classes.md"; + +## Purpose + +A controller that responds to SignalInputController notifications. +This controller removes the `disabled` attribute from an element when a value-change notification evaluates to +false against the expression given in `whenValue` evaluate to true, and adds `disabled="true"` when it evaluates to false. + +This controller can be anywhere in the DOM tree and it will receive notifications from any SignalInputController with +the same `nameValue` as the `nameValue` of this controller. + +### Example Use Cases +- Turn off inputs in a form when another input has a certain value, See also: SignalVisibiityController to hide elements when they are not needed. + +## [Actions](https://stimulus.hotwire.dev/reference/actions) + + +## [Targets](https://stimulus.hotwire.dev/reference/targets) + + +## [Classes](https://stimulus.hotwire.dev/reference/classes) + + +## [Values](https://stimulus.hotwire.dev/reference/values) + +| Value | Type | Description | Default | +|--------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------| +| `name` | String | The name of the input value whose value to react to. This name should be the same as the `nameValue` of the SignalInputController you want to sync with. | `-` | +| `when` | String | A simple _expression_ which will be evaluated against the value received from SignalInputController. If the expression evaluates to false, the controller will add the `disabled` attribute to the controller element, otherwise it will remove it. | `-` | + + + + +## Events + +| Event | When | Dispatched on | `event.detail` | | +|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|----------------|---------------------------------------------------------------| +| `signal:enable:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _true_ against the new updated value | The controller root element | | | +| | | | `element` | the controller root element | +| | | | `predicate` | the expression the controller used to try and match the value | +| | | | `value` | the value that was received | +| `signal:disable:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _false_ against the new updated value | The controller root element | | | +| | | | `element` | the controller root element | +| | | | `predicate` | the expression the controller used to try and match the value | +| | | | `value` | the value that was received | + + +## Side Effects + + +## How to Use + +```html + + + +
+ +
+ +``` diff --git a/src/controllers/signal/events.ts b/src/controllers/signal/events.ts index 6c4eacf2..bb1ab1cb 100644 --- a/src/controllers/signal/events.ts +++ b/src/controllers/signal/events.ts @@ -9,8 +9,3 @@ export function signalConnectEvent(name: string): string { export function signalValueEvent(name: string): string { return signalEventName(name, 'value'); } - -export function signalVisibilityEvent(name: string, action: "hide" | "show"): string { - return signalEventName(`${name}:${action}`, 'visibility'); -} - diff --git a/src/controllers/signal/index.ts b/src/controllers/signal/index.ts index 7e687b9d..c1e0fb9c 100644 --- a/src/controllers/signal/index.ts +++ b/src/controllers/signal/index.ts @@ -1,4 +1,6 @@ export * from './signal_action_controller'; +export * from './signal_disable_controller'; export * from './signal_dom_children_controller'; +export * from './signal_enable_controller'; export * from './signal_input_controller'; -export * from './signal_visibility_controller'; \ No newline at end of file +export * from './signal_visibility_controller'; diff --git a/src/controllers/signal/signal_disable_controller.ts b/src/controllers/signal/signal_disable_controller.ts new file mode 100644 index 00000000..0d18f54e --- /dev/null +++ b/src/controllers/signal/signal_disable_controller.ts @@ -0,0 +1,42 @@ +import {SignalPayload} from "src/*"; +import {signalEnableDisableEvent, signalEventName} from "./events"; +import {SignalBaseController} from "./base_controller"; + +export class SignalDisableController extends SignalBaseController { + + static values = { + name: String, + when: String, + }; + + declare nameValue: string; + declare whenValue: string; + + disable() { + this.el.setAttribute("disabled", "true"); + } + + enable() { + this.el.removeAttribute("disabled"); + } + + _onSignal(payload: SignalPayload) { + let value = payload.value; + if (this.whenValue == "default") { + if (value == "") { + this.disable(); + } else { + this.enable(); + } + return; + } + if (this.allPredicatesMatch(value)) { + this.dispatchEvent(this.el, signalEventName(this.nameValue, "disable"), {detail: {predicate: this.whenValue, value}}); + this.disable(); + } else { + this.dispatchEvent(this.el, signalEventName(this.nameValue, "enable"), {detail: {predicate: this.whenValue, value}}); + this.enable(); + } + } + +} diff --git a/src/controllers/signal/signal_enable_controller.ts b/src/controllers/signal/signal_enable_controller.ts new file mode 100644 index 00000000..6527dd0c --- /dev/null +++ b/src/controllers/signal/signal_enable_controller.ts @@ -0,0 +1,42 @@ +import {SignalPayload} from "src/*"; +import {signalEventName} from "./events"; +import {SignalBaseController} from "./base_controller"; + +export class SignalEnableController extends SignalBaseController { + + static values = { + name: String, + when: String, + }; + + declare nameValue: string; + declare whenValue: string; + + disable() { + this.el.setAttribute("disabled", "true"); + } + + enable() { + this.el.removeAttribute("disabled"); + } + + _onSignal(payload: SignalPayload) { + let value = payload.value; + if (this.whenValue == "default") { + if (value == "") { + this.enable(); + } else { + this.disable(); + } + return; + } + if (this.allPredicatesMatch(value)) { + this.dispatchEvent(this.el, signalEventName(this.nameValue, "enable"), {detail: {predicate: this.whenValue, value}}); + this.enable(); + } else { + this.dispatchEvent(this.el, signalEventName(this.nameValue, "disable"), {detail: {predicate: this.whenValue, value}}); + this.disable(); + } + } + +}