Skip to content

Commit

Permalink
Merge b1ee00d into b9c114c
Browse files Browse the repository at this point in the history
  • Loading branch information
rob2d committed Jun 1, 2021
2 parents b9c114c + b1ee00d commit 7a3965d
Show file tree
Hide file tree
Showing 27 changed files with 1,141 additions and 16 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ module.exports = {
'prefer-destructuring': ['off', { }],
// Allow i++
'no-plusplus': ['off', { }],
// valid for readability in async tests
'no-await-in-loop': ['off', { }],
// Allow console.info
'no-console': ['error', { allow: ['error', 'info'] }],
'template-curly-spacing': ['off'],
Expand Down
13 changes: 13 additions & 0 deletions app/ids-spinbox/demo.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ids-spinbox-demo {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
margin-left: 16px;

@media (max-width: 600px) {
grid-template-columns: 1fr 1fr;
}
}

ids-spinbox {
margin-bottom: 8px;
}
36 changes: 36 additions & 0 deletions app/ids-spinbox/example.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<ids-layout-grid>
<ids-text font-size="12" type="h1">Spinbox</ids-text>
</ids-layout-grid>
<div id="ids-spinbox-demo">
<ids-spinbox value="0" label="Basic Spinbox"></ids-spinbox>
<ids-spinbox value="0" min="0" max="5" label="Enter an int from 0 to 5" placeholder="0=>5"></ids-spinbox>
<ids-spinbox value="0" min="-25" max="25" step="5" label="Jumps 5 from -25 to 25" placeholder="-25=>25"></ids-spinbox>
<ids-spinbox
dirty-tracker value="0"
min="-25"
max="25"
step="5"
label="w/ Dirty Tracking"
placeholder="Dirty"
></ids-spinbox>
<ids-spinbox
value="0"
min="-25"
max="25"
step="5"
label="Disabled"
placeholder="N/A"
disabled
></ids-spinbox>
<ids-spinbox
value="0"
min="-25"
max="25"
step="5"
label="Required"
placeholder="N/A"
validate="required"
label-required
></ids-spinbox>
</div>

Empty file added app/ids-spinbox/example.js
Empty file.
3 changes: 3 additions & 0 deletions app/ids-spinbox/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{{> ../layouts/head.html }}
{{> example.html }}
{{> ../layouts/footer.html }}
2 changes: 2 additions & 0 deletions app/ids-spinbox/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import IdsSpinbox from '../../src/ids-spinbox';
import './demo.scss';
1 change: 1 addition & 0 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
{{> ids-upload-advanced/example.html }}
{{> ids-wizard/example.html }}
{{> ids-tabs/example.html }}
{{> ids-spinbox/example.html }}
{{> ids-trigger-field/example.html }}
{{> ids-expandable-area/example.html }}
{{> ids-card/example.html }}
Expand Down
2 changes: 2 additions & 0 deletions app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import IdsContainer from '../src/ids-container/ids-container';
import IdsThemeSwitcher from '../src/ids-theme-switcher/ids-theme-switcher';
import IdsRating from '../src/ids-rating/ids-rating';
import IdsWizard, { IdsWizardStep } from '../src/ids-wizard';
import IdsSpinbox from '../src/ids-spinbox';
import IdsModal, { IdsOverlay } from '../src/ids-modal';
import IdsTabs, { IdsTab } from '../src/ids-tabs';

Expand Down Expand Up @@ -65,4 +66,5 @@ import './ids-textarea/example';
import './ids-block-grid/index';
import './ids-counts/index';
import './ids-wizard/index';
import './ids-spinbox/index';
import './ids-tabs/index';
4 changes: 4 additions & 0 deletions doc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@
- `[RenderLoop]` The RenderLoop component has been implemented as a mixin.
- Added `IdsRenderLoopMixin` for access to a global renderLoop instance from within WebComponents.
- API has been simplified and made more user-friendly.
- `[Spinbox]` The spinbox component has been changed to a web component and renamed to ids-spinbox.
- Markup has changed to a custom element `<ids-spinbox></ids-spinbox>`
- If using events, events are now plain JS events.
- Can now be imported as a single JS file and used with encapsulated styles
- `[Switch]` The Switch component has been changed to a web component and renamed to ids-switch.
- Markup has changed to a custom element `<ids-switch></ids-switch>`
- If using events, events are now plain JS events.
Expand Down
2 changes: 2 additions & 0 deletions src/ids-base/ids-constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export const props = {
MAXLENGTH: 'maxlength',
MENU: 'menu',
METHOD: 'method',
MIN: 'min',
MODE: 'mode',
MULTIPLE: 'multiple',
NO_MARGINS: 'no-margins',
Expand All @@ -95,6 +96,7 @@ export const props = {
SHAPE: 'shape',
SHOW_BROWSE_LINK: 'show-browse-link',
SIZE: 'size',
STEP: 'step',
STEP_NUMBER: 'step-number',
SUBMENU: 'submenu',
TABBABLE: 'tabbable',
Expand Down
1 change: 0 additions & 1 deletion src/ids-button/ids-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,6 @@ class IdsButton extends mix(IdsElement).with(
rippleEl.classList.add('ripple-effect');
rippleEl.setAttribute('aria-hidden', 'true');
rippleEl.setAttribute('focusable', 'false');
rippleEl.setAttribute('role', 'presentation');

this.button.prepend(rippleEl);
rippleEl.style.left = `${btnOffsets.x}px`;
Expand Down
6 changes: 4 additions & 2 deletions src/ids-input/ids-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ import {
IdsTooltipMixin
} from '../ids-mixins';

let instanceCounter = 0;

// Properties observed by the Input
const INPUT_PROPS = [
props.AUTOSELECT,
Expand Down Expand Up @@ -104,6 +102,8 @@ const appliedMixins = [
IdsTooltipMixin
];

let instanceCounter = 0;

/**
* IDS Input Component
* @type {IdsInput}
Expand Down Expand Up @@ -142,6 +142,7 @@ class IdsInput extends mix(IdsElement).with(...appliedMixins) {
*/
connectedCallback() {
super.connectedCallback?.();

this.handleEvents();
this.handleAutoselect();
this.handleClearable();
Expand Down Expand Up @@ -566,6 +567,7 @@ class IdsInput extends mix(IdsElement).with(...appliedMixins) {
*/
set labelRequired(value) {
const val = stringUtils.stringToBool(value);

if (val) {
this.setAttribute(props.LABEL_REQUIRED, val.toString());
} else {
Expand Down
8 changes: 6 additions & 2 deletions src/ids-mixins/ids-keyboard-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,17 @@ const IdsKeyboardMixin = (superclass) => class extends superclass {
}

/**
* Add a listener for a key or key code combination
* Add a listener for a key or set of keys
* @param {Array|string} keycode An array of all matchinng keycodes
* @param {HTMLElement} elem The object with the listener attached
* @param {Function} callback The call back when this combination is met
*/
listen(keycode, elem, callback) {
this.hotkeys.set(`${keycode}`, callback);
const keycodes = Array.isArray(keycode) ? keycode : [keycode];

for (const c of keycodes) {
this.hotkeys.set(`${c}`, callback);
}
}

/**
Expand Down
37 changes: 29 additions & 8 deletions src/ids-mixins/ids-validation-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ const IdsValidationMixin = (superclass) => class extends superclass {
if (this.labelEl && this.input && typeof this.validate === 'string' && canRadio) {
const isCheckbox = this.input?.getAttribute('type') === 'checkbox';
const defaultEvents = (isCheckbox || isRadioGroup) ? 'change' : 'blur';
const events = this.validationEvents && typeof this.validationEvents === 'string' ? this.validationEvents : defaultEvents;
const events = (this.validationEvents && typeof this.validationEvents === 'string')
? this.validationEvents : defaultEvents;
this.validationEventsList = [...new Set(events.split(' '))];
const getRule = (/** @type {string} */ id) => ({ id, rule: this.rules[id] });
let isRulesAdded = false;
Expand Down Expand Up @@ -118,12 +119,12 @@ const IdsValidationMixin = (superclass) => class extends superclass {
icon
} = settings;

if (!id) {
if (!id && !this.#externalValidationEl) {
return;
}

let elem = this.shadowRoot.querySelector(`[validation-id="${id}"]`);
if (elem) {
let elem = this.#externalValidationEl || this.shadowRoot.querySelector(`[validation-id="${id}"]`);
if (elem && !this.#externalValidationEl) {
// Already has this message
return;
}
Expand All @@ -147,7 +148,13 @@ const IdsValidationMixin = (superclass) => class extends superclass {
const iconHtml = iconName ? `<ids-icon icon="${iconName}" class="ids-icon"></ids-icon>` : '';

// Add error message div and associated aria
elem = document.createElement('div');
/* istanbul ignore else */
if (!this.#externalValidationEl) {
elem = document.createElement('div');
} else {
elem = this.#externalValidationEl;
}

elem.setAttribute('id', messageId);
elem.setAttribute('validation-id', id);
elem.setAttribute('type', type);
Expand All @@ -159,7 +166,10 @@ const IdsValidationMixin = (superclass) => class extends superclass {

const rootEl = this.shadowRoot.querySelector('.ids-input, .ids-textarea, .ids-checkbox');
const parent = rootEl || this.shadowRoot;
parent.appendChild(elem);

if (!this.#externalValidationEl) {
parent.appendChild(elem);
}

// Add extra classes for radios
const isRadioGroup = this.input?.classList.contains('ids-radio-group');
Expand All @@ -176,9 +186,14 @@ const IdsValidationMixin = (superclass) => class extends superclass {
*/
removeMessage(settings) {
const { id, type } = settings;
const elem = this.shadowRoot.querySelector(`[validation-id="${id}"]`);

elem?.remove();
if (!this.#externalValidationEl) {
this.shadowRoot.querySelector(`[validation-id="${id}"]`)?.remove?.();
} else {
/* istanbul ignore next */
this.#externalValidationEl.innerHTML = '';
}

if (this.isTypeNotValid && !this.isTypeNotValid[type]) {
this.input?.classList.remove(type);
this.input.removeAttribute('aria-describedby');
Expand Down Expand Up @@ -290,6 +305,12 @@ const IdsValidationMixin = (superclass) => class extends superclass {
id: 'email'
}
}

setValidationElement(el) {
this.#externalValidationEl = el;
}

#externalValidationEl;
};

export default IdsValidationMixin;
93 changes: 93 additions & 0 deletions src/ids-spinbox/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Ids Spinbox Component

## Description
Allows a user to input a value that goes up/down in specific intervals, and also optionally within a range of integers.

## Use Cases
- a normal input that goes up or down specific increments by it's nature.

## Themeable Parts
- `container` the overall spinbox container
- `input` the spinbox center input
- `button` increment/decrement buttons
- `label` the label above the input
- `validation` the validation message that pops up if any errors exist

## Features (With Code Examples)

Spinbox with a minimum and maximum

```html
<ids-spinbox
value="0"
min="0"
max="5"
label="Enter an int from 0 to 5"
placeholder="0=>5"
></ids-spinbox>
```

Spinbox which increments in intervals of 5
```html
<ids-spinbox
value="0"
min="-25"
max="25"
step="5"
label="Jumps 5 from -25 to 25"
></ids-spinbox>
```

Spinbox which shows a marker with changes, and no range limits

```html
<ids-spinbox
value="0"
label="Unbounded Spinbox"
dirty-marker="true"
></ids-spinbox>
```

Spinbox which is required to have a value set when tabbed off of or `this.handleValidation()` called.

```html
<ids-spinbox
value=""
label="Value Is Required"
validation="required"
></ids-spinbox>
```

## Settings and Attributes

`value` `{number}` the current number assigned to the step box

`max` `{number}` maximum/ceiling value possible to assign to `value`

`min` `{number}` minimum/floor value possible to assign to `value`

`label` `{string}` label shown above the spinbox

`placeholder` `{string}` text shown as a hint when user clears text on the input

`validate` `{string}` validation message text; set to `required` to require validation.

## Keyboard Guidelines
- TAB should move off of the component to the next focusable element on page.
- SHIFT + TAB should move to previous focusable element on the page.
- UP/DOWN arrow keys should increment, and decrement the ids-spinbox value.

## Responsive Guidelines

N/A

## Converting from Previous Versions

TODO

## Accessibility Guidelines
- 1.4.3 Contrast (Minimum) - there should be enough contrast on the background which the wizard resides on in the page.
- Be sure to provide labels that provide clear intent as to the representation of the value which the spinbox controls.

## Regional Considerations
Label text should be localized in the current language. All elements will flip to the alternate side in Right To Left mode. Consider that in some languages text may be a lot longer (German). And in some cases it cant be wrapped (Thai). For some of these cases text-ellipsis is supported.
1 change: 1 addition & 0 deletions src/ids-spinbox/TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# TODO for Ids-Spinbox
31 changes: 31 additions & 0 deletions src/ids-spinbox/ids-spinbox.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { IdsElement } from '../ids-base';

export default class IdsSpinbox extends IdsElement {
/**
* the maximum value the spinbox' input can be set to
*/
max: number | string;

/**
* the minimum value the spinbox' input can be set to
*/
min: number | string;

/** spinbox' current input value */
value: number | string;

/** hint shown when a user has cleared the spinbox value */
placeholder?: string;

/** label text describing the spinbox value */
label: string;

/** whether the dirty tracker has been enabled */
dirtyTracker: boolean | string;

/** whether or not content is interactive */
disabled: boolean | string;

/** validation message text; set to `required` to require validation. */
validate?: string;
}
Loading

0 comments on commit 7a3965d

Please sign in to comment.