Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use custom events for inputs #42

Merged
merged 7 commits into from
Mar 21, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 11 additions & 32 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,11 @@ import {
} from './types/Input';
import {
Option,
Value,
} from 'types/Select';


export namespace Components {

interface CustomPlanFeature {
'feature': Catalog.ExpandedFeature;
'planLabel': string;
'selectedValue': string;
}
interface CustomPlanFeatureAttributes extends StencilHTMLAttributes {
'feature'?: Catalog.ExpandedFeature;
'planLabel'?: string;
'selectedValue'?: string;
}

interface FeaturedService {
'logo': string;
'name': string;
Expand Down Expand Up @@ -193,61 +181,62 @@ export namespace Components {
}

interface MfSelect {
'defaultValue'?: string;
'name': string;
'onChange': (e: UIEvent) => void;
'options': Option[];
'required'?: boolean;
'selectedValue'?: Value;
}
interface MfSelectAttributes extends StencilHTMLAttributes {
'defaultValue'?: string;
'name'?: string;
'onChange'?: (e: UIEvent) => void;
'onUpdateValue'?: (event: CustomEvent) => void;
'options'?: Option[];
'required'?: boolean;
'selectedValue'?: Value;
}

interface MfSlider {
'defaultValue'?: number;
'error'?: string;
'increment': number;
'max': number;
'min': number;
'name': string;
'onChange': (e: Event) => void;
'selectedValue': number;
'suffix': string;
}
interface MfSliderAttributes extends StencilHTMLAttributes {
'defaultValue'?: number;
'error'?: string;
'increment'?: number;
'max'?: number;
'min'?: number;
'name'?: string;
'onChange'?: (e: Event) => void;
'selectedValue'?: number;
'onUpdateValue'?: (event: CustomEvent) => void;
'suffix'?: string;
}

interface MfToggle {
'ariaLabelledby'?: string;
'defaultValue'?: boolean;
'disabled'?: boolean;
'label'?: string;
'name': string;
}
interface MfToggleAttributes extends StencilHTMLAttributes {
'ariaLabelledby'?: string;
'defaultValue'?: boolean;
'disabled'?: boolean;
'label'?: string;
'name'?: string;
'onUpdateValue'?: (event: CustomEvent) => void;
}

interface PlanDetails {
'plan': Catalog.ExpandedPlan;
'product': Catalog.ExpandedProduct;
'product': Catalog.Product;
}
interface PlanDetailsAttributes extends StencilHTMLAttributes {
'plan'?: Catalog.ExpandedPlan;
'product'?: Catalog.ExpandedProduct;
'product'?: Catalog.Product;
}

interface PlanMenu {
Expand Down Expand Up @@ -332,7 +321,6 @@ export namespace Components {

declare global {
interface StencilElementInterfaces {
'CustomPlanFeature': Components.CustomPlanFeature;
'FeaturedService': Components.FeaturedService;
'ImageGallery': Components.ImageGallery;
'LinkButton': Components.LinkButton;
Expand Down Expand Up @@ -360,7 +348,6 @@ declare global {
}

interface StencilIntrinsicElements {
'custom-plan-feature': Components.CustomPlanFeatureAttributes;
'featured-service': Components.FeaturedServiceAttributes;
'image-gallery': Components.ImageGalleryAttributes;
'link-button': Components.LinkButtonAttributes;
Expand Down Expand Up @@ -388,12 +375,6 @@ declare global {
}


interface HTMLCustomPlanFeatureElement extends Components.CustomPlanFeature, HTMLStencilElement {}
var HTMLCustomPlanFeatureElement: {
prototype: HTMLCustomPlanFeatureElement;
new (): HTMLCustomPlanFeatureElement;
};

interface HTMLFeaturedServiceElement extends Components.FeaturedService, HTMLStencilElement {}
var HTMLFeaturedServiceElement: {
prototype: HTMLFeaturedServiceElement;
Expand Down Expand Up @@ -539,7 +520,6 @@ declare global {
};

interface HTMLElementTagNameMap {
'custom-plan-feature': HTMLCustomPlanFeatureElement
'featured-service': HTMLFeaturedServiceElement
'image-gallery': HTMLImageGalleryElement
'link-button': HTMLLinkButtonElement
Expand Down Expand Up @@ -567,7 +547,6 @@ declare global {
}

interface ElementTagNameMap {
'custom-plan-feature': HTMLCustomPlanFeatureElement;
'featured-service': HTMLFeaturedServiceElement;
'image-gallery': HTMLImageGalleryElement;
'link-button': HTMLLinkButtonElement;
Expand Down
73 changes: 0 additions & 73 deletions src/components/custom-plan-feature/custom-plan-feature.tsx

This file was deleted.

19 changes: 0 additions & 19 deletions src/components/custom-plan-feature/readme.md

This file was deleted.

23 changes: 16 additions & 7 deletions src/components/mf-select/mf-select.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
import { Component, Prop } from '@stencil/core';
import { Option, Value } from 'types/Select';
import { Component, Prop, Event, EventEmitter, Watch } from '@stencil/core';
import { Option } from 'types/Select';

@Component({
tag: 'mf-select',
styleUrl: 'mf-select.css',
scoped: true,
})
export class MfSelect {
@Prop() options: Option[] = [];
@Prop() selectedValue?: Value;
@Prop() defaultValue?: string;
Copy link
Contributor Author

@drwpow drwpow Mar 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Borrowed the defaultValue from React. Technically, this works like value, and can overwrite the user’s changes. But the way it’s passed down, it’ll never change so it should allow the user to modify inputs freely (kinda like how HTML works—value only determines the default. Actually there have been discussions to change this in React)

@Prop() name: string;
@Prop() options: Option[] = [];
@Prop() required?: boolean;
@Prop() onChange: (e: UIEvent) => void;
@Event() updateValue: EventEmitter;
@Watch('defaultValue') watchHandler(newVal: string) {
this.updateValue.emit({ name: this.name, value: newVal });
}
Copy link
Contributor Author

@drwpow drwpow Mar 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Watch is necessary here only because of the plan change.

The defaultValue is deterministic, and won’t ever update as the user changes input values. It will change, however, if a user switches plans because each plan can have its own defaults. So this is basically a way of emitting a “reset” event to the listener when the plan changes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was totally wondering if @Watch members allowed you to reference this, because the docs aren't really clear on that. 💯


onChangeHandler = (e: Event) => {
if (!e.target) return;
const { value } = e.target as HTMLSelectElement;
this.updateValue.emit({ name: this.name, value });
};
Copy link
Contributor Author

@drwpow drwpow Mar 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the event details, we’re submitting the name of the input so that above in the listener, we can filter out the events with names we don’t care about.


render() {
return (
<select name={this.name} required={this.required} onChange={this.onChange}>
<select name={this.name} required={this.required} onChange={this.onChangeHandler}>
{this.options.map(({ label, value }) => (
<option value={value} selected={this.selectedValue === value}>
<option value={value} selected={value === this.defaultValue}>
{label}
</option>
))}
Expand Down
20 changes: 13 additions & 7 deletions src/components/mf-select/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@

## Properties

| Property | Attribute | Description | Type | Default |
| --------------- | ---------------- | ----------- | ------------------------------- | ----------- |
| `name` | `name` | | `string` | `undefined` |
| `onChange` | -- | | `(e: UIEvent) => void` | `undefined` |
| `options` | -- | | `Option[]` | `[]` |
| `required` | `required` | | `boolean \| undefined` | `undefined` |
| `selectedValue` | `selected-value` | | `number \| string \| undefined` | `undefined` |
| Property | Attribute | Description | Type | Default |
| -------------- | --------------- | ----------- | ---------------------- | ----------- |
| `defaultValue` | `default-value` | | `string \| undefined` | `undefined` |
| `name` | `name` | | `string` | `undefined` |
| `options` | -- | | `Option[]` | `[]` |
| `required` | `required` | | `boolean \| undefined` | `undefined` |


## Events

| Event | Description | Type |
| ------------- | ----------- | ------------------- |
| `updateValue` | | `CustomEvent<void>` |


----------------------------------------------
Expand Down
32 changes: 21 additions & 11 deletions src/components/mf-slider/mf-slider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Prop } from '@stencil/core';
import { Component, Prop, Event, EventEmitter, Watch } from '@stencil/core';
import { FieldType } from '../../types/Input';

@Component({
Expand All @@ -7,21 +7,33 @@ import { FieldType } from '../../types/Input';
scoped: true,
})
export class MfSlider {
@Prop() min: number = 0;
@Prop() max: number;
@Prop() defaultValue?: number;
@Prop() error?: string;
@Prop() increment: number = 1;
@Prop() max: number;
@Prop() min: number = 0;
@Prop() name: string = '';
@Prop() selectedValue: number;
@Prop() suffix: string = '';
@Prop() onChange: (e: Event) => void;
@Prop() error?: string;
@Event() updateValue: EventEmitter;
@Watch('defaultValue') watchHandler(newVal: number) {
this.updateValue.emit({ name: this.name, value: newVal });
}

onChangeHandler = (e: Event) => {
if (!e.target) return;
const { value } = e.target as HTMLInputElement;
this.updateValue.emit({
name: this.name,
value: parseInt(value, 10),
});
};

get positionCount() {
return (this.max - this.min) / this.increment;
}

render() {
const value = this.selectedValue || this.min;
const value = this.defaultValue || this.min;
return (
<div class="container">
{this.positionCount < 500 ? (
Expand All @@ -32,8 +44,6 @@ export class MfSlider {
min={this.min}
step={this.increment}
value={value}
onInput={e => this.onChange(e)}
onChange={e => this.onChange(e)}
style={{
'--slider-position': `${value / (this.max - this.min)}%`,
}}
Expand All @@ -53,10 +63,10 @@ export class MfSlider {
type={FieldType.Number}
max={this.max}
min={this.min}
value={value}
onChange={e => this.onChange(e)}
onChange={this.onChangeHandler}
required
step={this.increment}
value={value}
/>
<div class="display-units">{this.suffix}</div>
</div>
Expand Down
Loading