diff --git a/.vscode/settings.json b/.vscode/settings.json index 7fe963abab..7fea7d4d06 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,5 +11,6 @@ "tools/**/*.dev.js": { "when": "$(basename).js" }, "tools/**/*.d.ts": { "when": "$(basename).ts" }, "**/*.test-vrt.ts": true - } + }, + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/packages/number-field/README.md b/packages/number-field/README.md index 4109d7ec4d..50922cdd6b 100644 --- a/packages/number-field/README.md +++ b/packages/number-field/README.md @@ -24,16 +24,63 @@ When looking to leverage the `NumberField` base class as a type and/or for exten import { NumberField } from '@spectrum-web-components/number-field'; ``` -## Example +## Sizes + + +Small + ```html +``` + + +Medium + + +```html + ``` + +Large + + +```html + +``` + + +Extra Large + + +```html + +``` + + + + ## Number formatting An `` element will process its numeric value with `new Intl.NumberFormat(this.resolvedLanguage, this.formatOptions).format(this.value)` in order to prepare it for visual delivery in the input. In order to customize this processing supply your own `Intl.NumberFormatOptions` via the `formatOptions` property, or `format-options` attribute as seen below. diff --git a/packages/number-field/src/NumberField.ts b/packages/number-field/src/NumberField.ts index 4d4f584055..02b34734e8 100644 --- a/packages/number-field/src/NumberField.ts +++ b/packages/number-field/src/NumberField.ts @@ -28,6 +28,8 @@ import { streamingListener } from '@spectrum-web-components/base/src/streaming-l import { NumberFormatter, NumberParser } from '@internationalized/number'; import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron75.js'; +import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron100.js'; +import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron200.js'; import '@spectrum-web-components/action-button/sp-action-button.js'; import { isAndroid, @@ -61,6 +63,33 @@ export const remapMultiByteCharacters: Record = { ー: '-', }; +const chevronIcon: Record TemplateResult> = { + s: (dir) => html` + + `, + m: (dir) => html` + + `, + l: (dir) => html` + + `, + xl: (dir) => html` + + `, +}; + /** * @element sp-number-field * @slot help-text - default or non-negative help text to associate to your form element @@ -557,7 +586,7 @@ export class NumberField extends TextfieldBase { })} > - + ${chevronIcon[this.size]('Up')} - + ${chevronIcon[this.size]('Down')} `} diff --git a/packages/number-field/src/number-field.css b/packages/number-field/src/number-field.css index 19d00b5a84..7c0b469a96 100644 --- a/packages/number-field/src/number-field.css +++ b/packages/number-field/src/number-field.css @@ -16,6 +16,22 @@ governing permissions and limitations under the License. inline-size: var(--mod-stepper-width, var(--spectrum-stepper-width)); } +:host([size='s']) { + --spectrum-stepper-width: calc( + var(--spectrum-stepper-width-medium) / 5 * 4 + ); +} + +:host([size='l']) { + --spectrum-stepper-width: calc(var(--spectrum-stepper-width-medium) * 1.25); +} + +:host([size='xl']) { + --spectrum-stepper-width: calc( + var(--spectrum-stepper-width-medium) * 1.25 * 1.25 + ); +} + #textfield { inline-size: 100%; } @@ -35,6 +51,25 @@ sp-field-button { ); flex-shrink: 0; + block-size: var(--mod-textfield-height, var(--spectrum-textfield-height)); + inline-size: calc( + var(--mod-textfield-height, var(--spectrum-textfield-height)) * 3 / 4 + ); + padding-block: var(--spectrum-stepper-button-gap); +} + +.step-up, +.step-down { + width: 100%; + height: 50%; + overflow: hidden; + padding: 0; +} + +.step-down .stepper-icon, +.step-up .stepper-icon { + margin-inline-start: 0; + translate: 5%; } :host([readonly]) .buttons { diff --git a/packages/number-field/src/spectrum-config.js b/packages/number-field/src/spectrum-config.js index 108fa5d852..df3a5bea8d 100644 --- a/packages/number-field/src/spectrum-config.js +++ b/packages/number-field/src/spectrum-config.js @@ -236,8 +236,11 @@ const config = { 'keyboard-focused' ), converter.classToClass('spectrum-Stepper-buttons', 'buttons'), - converter.classToClass('spectrum-Stepper-stepDown', 'stepDown'), - converter.classToClass('spectrum-Stepper-stepUp', 'stepUp'), + converter.classToClass( + 'spectrum-Stepper-stepDown', + 'step-down' + ), + converter.classToClass('spectrum-Stepper-stepUp', 'step-up'), converter.classToClass( 'spectrum-Stepper-textfield', 'textfield' diff --git a/packages/number-field/src/spectrum-number-field.css b/packages/number-field/src/spectrum-number-field.css index 4ca255b839..49df747fc5 100644 --- a/packages/number-field/src/spectrum-number-field.css +++ b/packages/number-field/src/spectrum-number-field.css @@ -120,10 +120,10 @@ governing permissions and limitations under the License. .input, :host(:hover:not([disabled]):not([invalid]):not([focused])) #textfield:not(.is-keyboardFocused) - .stepDown, + .step-down, :host(:hover:not([disabled]):not([invalid]):not([focused])) #textfield:not(.is-keyboardFocused) - .stepUp { + .step-up { border-color: var( --highcontrast-stepper-border-color-hover, var( @@ -137,8 +137,8 @@ governing permissions and limitations under the License. } :host([focused]) #textfield .buttons, :host([focused]) #textfield .input, -:host([focused]) #textfield .stepDown, -:host([focused]) #textfield .stepUp { +:host([focused]) #textfield .step-down, +:host([focused]) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-focus, var( @@ -147,8 +147,8 @@ governing permissions and limitations under the License. ) ); } -:host([focused]) #textfield .stepDown, -:host([focused]) #textfield .stepUp { +:host([focused]) #textfield .step-down, +:host([focused]) #textfield .step-up { background-color: var( --highcontrast-stepper-button-background-color-focus, var( @@ -159,8 +159,8 @@ governing permissions and limitations under the License. } :host([focused]:hover) #textfield .buttons, :host([focused]:hover) #textfield .input, -:host([focused]:hover) #textfield .stepDown, -:host([focused]:hover) #textfield .stepUp { +:host([focused]:hover) #textfield .step-down, +:host([focused]:hover) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-focus-hover, var( @@ -171,8 +171,8 @@ governing permissions and limitations under the License. } :host([focused][invalid]) #textfield .buttons, :host([focused][invalid]) #textfield .input, -:host([focused][invalid]) #textfield .stepDown, -:host([focused][invalid]) #textfield .stepUp { +:host([focused][invalid]) #textfield .step-down, +:host([focused][invalid]) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-invalid-focus, var( @@ -229,12 +229,12 @@ governing permissions and limitations under the License. } #textfield.focus-visible .buttons, #textfield.focus-visible .input, -#textfield.focus-visible .stepDown, -#textfield.focus-visible .stepUp, +#textfield.focus-visible .step-down, +#textfield.focus-visible .step-up, :host([keyboard-focused]) #textfield .buttons, :host([keyboard-focused]) #textfield .input, -:host([keyboard-focused]) #textfield .stepDown, -:host([keyboard-focused]) #textfield .stepUp { +:host([keyboard-focused]) #textfield .step-down, +:host([keyboard-focused]) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-keyboard-focus, var( @@ -245,12 +245,12 @@ governing permissions and limitations under the License. } #textfield:focus-visible .buttons, #textfield:focus-visible .input, -#textfield:focus-visible .stepDown, -#textfield:focus-visible .stepUp, +#textfield:focus-visible .step-down, +#textfield:focus-visible .step-up, :host([keyboard-focused]) #textfield .buttons, :host([keyboard-focused]) #textfield .input, -:host([keyboard-focused]) #textfield .stepDown, -:host([keyboard-focused]) #textfield .stepUp { +:host([keyboard-focused]) #textfield .step-down, +:host([keyboard-focused]) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-keyboard-focus, var( @@ -259,10 +259,10 @@ governing permissions and limitations under the License. ) ); } -#textfield.focus-visible .stepDown, -#textfield.focus-visible .stepUp, -:host([keyboard-focused]) #textfield .stepDown, -:host([keyboard-focused]) #textfield .stepUp { +#textfield.focus-visible .step-down, +#textfield.focus-visible .step-up, +:host([keyboard-focused]) #textfield .step-down, +:host([keyboard-focused]) #textfield .step-up { background-color: var( --highcontrast-stepper-button-background-color-keyboard-focus, var( @@ -271,10 +271,10 @@ governing permissions and limitations under the License. ) ); } -#textfield:focus-visible .stepDown, -#textfield:focus-visible .stepUp, -:host([keyboard-focused]) #textfield .stepDown, -:host([keyboard-focused]) #textfield .stepUp { +#textfield:focus-visible .step-down, +#textfield:focus-visible .step-up, +:host([keyboard-focused]) #textfield .step-down, +:host([keyboard-focused]) #textfield .step-up { background-color: var( --highcontrast-stepper-button-background-color-keyboard-focus, var( @@ -285,12 +285,12 @@ governing permissions and limitations under the License. } :host([invalid]) #textfield.focus-visible .buttons, :host([invalid]) #textfield.focus-visible .input, -:host([invalid]) #textfield.focus-visible .stepDown, -:host([invalid]) #textfield.focus-visible .stepUp, +:host([invalid]) #textfield.focus-visible .step-down, +:host([invalid]) #textfield.focus-visible .step-up, :host([keyboard-focused][invalid]) #textfield .buttons, :host([keyboard-focused][invalid]) #textfield .input, -:host([keyboard-focused][invalid]) #textfield .stepDown, -:host([keyboard-focused][invalid]) #textfield .stepUp { +:host([keyboard-focused][invalid]) #textfield .step-down, +:host([keyboard-focused][invalid]) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-invalid-keyboard-focus, var( @@ -301,12 +301,12 @@ governing permissions and limitations under the License. } :host([invalid]) #textfield:focus-visible .buttons, :host([invalid]) #textfield:focus-visible .input, -:host([invalid]) #textfield:focus-visible .stepDown, -:host([invalid]) #textfield:focus-visible .stepUp, +:host([invalid]) #textfield:focus-visible .step-down, +:host([invalid]) #textfield:focus-visible .step-up, :host([keyboard-focused][invalid]) #textfield .buttons, :host([keyboard-focused][invalid]) #textfield .input, -:host([keyboard-focused][invalid]) #textfield .stepDown, -:host([keyboard-focused][invalid]) #textfield .stepUp { +:host([keyboard-focused][invalid]) #textfield .step-down, +:host([keyboard-focused][invalid]) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-invalid-keyboard-focus, var( @@ -317,8 +317,8 @@ governing permissions and limitations under the License. } :host([invalid]) #textfield .buttons, :host([invalid]) #textfield .input, -:host([invalid]) #textfield .stepDown, -:host([invalid]) #textfield .stepUp { +:host([invalid]) #textfield .step-down, +:host([invalid]) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-invalid-default, var( @@ -329,8 +329,8 @@ governing permissions and limitations under the License. } :host([invalid]:hover) #textfield .buttons, :host([invalid]:hover) #textfield .input, -:host([invalid]:hover) #textfield .stepDown, -:host([invalid]:hover) #textfield .stepUp { +:host([invalid]:hover) #textfield .step-down, +:host([invalid]:hover) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-invalid-hover, var( @@ -341,8 +341,8 @@ governing permissions and limitations under the License. } :host([invalid][focused]) #textfield .buttons, :host([invalid][focused]) #textfield .input, -:host([invalid][focused]) #textfield .stepDown, -:host([invalid][focused]) #textfield .stepUp { +:host([invalid][focused]) #textfield .step-down, +:host([invalid][focused]) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-invalid-focus, var( @@ -353,8 +353,8 @@ governing permissions and limitations under the License. } :host([invalid][focused]:hover) #textfield .buttons, :host([invalid][focused]:hover) #textfield .input, -:host([invalid][focused]:hover) #textfield .stepDown, -:host([invalid][focused]:hover) #textfield .stepUp { +:host([invalid][focused]:hover) #textfield .step-down, +:host([invalid][focused]:hover) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-invalid-focus-hover, var( @@ -365,8 +365,8 @@ governing permissions and limitations under the License. } :host([invalid][keyboard-focused]) #textfield .buttons, :host([invalid][keyboard-focused]) #textfield .input, -:host([invalid][keyboard-focused]) #textfield .stepDown, -:host([invalid][keyboard-focused]) #textfield .stepUp { +:host([invalid][keyboard-focused]) #textfield .step-down, +:host([invalid][keyboard-focused]) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-invalid-keyboard-focus, var( @@ -377,8 +377,8 @@ governing permissions and limitations under the License. } :host([disabled]) #textfield .buttons, :host([disabled]) #textfield .input, -:host([disabled]) #textfield .stepDown, -:host([disabled]) #textfield .stepUp { +:host([disabled]) #textfield .step-down, +:host([disabled]) #textfield .step-up { border-color: var( --highcontrast-stepper-border-color-disabled, var( @@ -387,8 +387,8 @@ governing permissions and limitations under the License. ) ); } -:host([disabled]) #textfield .stepDown, -:host([disabled]) #textfield .stepUp { +:host([disabled]) #textfield .step-down, +:host([disabled]) #textfield .step-up { background-color: #0000; } :host([disabled]) #textfield .buttons { @@ -428,8 +428,8 @@ governing permissions and limitations under the License. border-width: 0 0 var(--mod-stepper-border-width, var(--spectrum-stepper-border-width)) 0; } -:host([quiet]) .stepDown, -:host([quiet]) .stepUp { +:host([quiet]) .step-down, +:host([quiet]) .step-up { border-block-start-color: currentColor; border-block-start-style: none; border-inline-color: currentColor; @@ -444,8 +444,8 @@ governing permissions and limitations under the License. min-inline-size: 0; padding-inline-end: 0; } -:host([quiet]) .stepDown:after, -:host([quiet]) .stepUp:after { +:host([quiet]) .step-down:after, +:host([quiet]) .step-up:after { block-size: 100%; content: ''; inline-size: var( @@ -460,17 +460,17 @@ governing permissions and limitations under the License. } :host([quiet]) .buttons, :host([quiet]) .input, -:host([quiet]) .stepDown, -:host([quiet]) .stepUp, +:host([quiet]) .step-down, +:host([quiet]) .step-up, :host([quiet]:hover) .buttons, -:host([quiet]:hover) .stepDown, -:host([quiet]:hover) .stepUp { +:host([quiet]:hover) .step-down, +:host([quiet]:hover) .step-up { background-color: #0000; } :host([quiet][disabled]) #textfield .buttons, :host([quiet][disabled]) #textfield .input, -:host([quiet][disabled]) #textfield .stepDown, -:host([quiet][disabled]) #textfield .stepUp { +:host([quiet][disabled]) #textfield .step-down, +:host([quiet][disabled]) #textfield .step-up { background-color: #0000; border-color: var( --highcontrast-stepper-border-color-quiet-disabled, @@ -482,7 +482,7 @@ governing permissions and limitations under the License. } :host([quiet][invalid]) .buttons, :host([quiet][invalid]) .input, -:host([quiet][invalid]) .stepDown { +:host([quiet][invalid]) .step-down { border-color: var( --highcontrast-stepper-border-color-invalid-default, var( @@ -491,13 +491,13 @@ governing permissions and limitations under the License. ) ); } -:host([quiet][invalid]) .stepDown, -:host([quiet][invalid]) .stepUp { +:host([quiet][invalid]) .step-down, +:host([quiet][invalid]) .step-up { background-color: #0000; } :host([quiet][focused]) .buttons, :host([quiet][focused]) .input, -:host([quiet][focused]) .stepDown { +:host([quiet][focused]) .step-down { border-color: var( --highcontrast-stepper-border-color-focus, var( @@ -506,14 +506,14 @@ governing permissions and limitations under the License. ) ); } -:host([quiet][focused]) .stepDown, -:host([quiet][focused]) .stepUp { +:host([quiet][focused]) .step-down, +:host([quiet][focused]) .step-up { background-color: #0000; } :host([quiet][focused]:hover) .buttons, :host([quiet][focused]:hover) .input, -:host([quiet][focused]:hover) .stepDown, -:host([quiet][focused]:hover) .stepUp { +:host([quiet][focused]:hover) .step-down, +:host([quiet][focused]:hover) .step-up { border-color: var( --highcontrast-stepper-border-color-focus-hover, var( @@ -524,7 +524,7 @@ governing permissions and limitations under the License. } :host([quiet][focused][invalid]) .buttons, :host([quiet][focused][invalid]) .input, -:host([quiet][focused][invalid]) .stepDown { +:host([quiet][focused][invalid]) .step-down { border-color: var( --highcontrast-stepper-border-color-invalid-focus, var( @@ -545,12 +545,12 @@ governing permissions and limitations under the License. ) ); } -:host([quiet][keyboard-focused]) .stepDown, -:host([quiet][keyboard-focused]) .stepUp { +:host([quiet][keyboard-focused]) .step-down, +:host([quiet][keyboard-focused]) .step-up { background-color: #0000; } :host([quiet][keyboard-focused]) .buttons, -:host([quiet][keyboard-focused]) .stepDown { +:host([quiet][keyboard-focused]) .step-down { border-color: var( --highcontrast-stepper-border-color-keyboard-focus, var( @@ -561,7 +561,7 @@ governing permissions and limitations under the License. } :host([quiet][keyboard-focused][invalid]) .buttons, :host([quiet][keyboard-focused][invalid]) .input, -:host([quiet][keyboard-focused][invalid]) .stepDown { +:host([quiet][keyboard-focused][invalid]) .step-down { border-color: var( --highcontrast-stepper-border-color-invalid-keyboard-focus, var( @@ -625,13 +625,13 @@ governing permissions and limitations under the License. ease-in-out; } .buttons, -.stepDown, -.stepUp { +.step-down, +.step-up { box-sizing: border-box; display: flex; } -.stepDown, -.stepUp { +.step-down, +.step-up { background-color: var( --highcontrast-stepper-button-background-color-default, var( @@ -664,14 +664,14 @@ governing permissions and limitations under the License. ); position: relative; } -.stepDown .stepper-icon, -.stepUp .stepper-icon { +.step-down .stepper-icon, +.step-up .stepper-icon { margin: 0; margin-inline-start: var(--spectrum-stepper-button-icon-nudge); opacity: 1; } -:host(:hover) .stepDown, -:host(:hover) .stepUp { +:host(:hover) .step-down, +:host(:hover) .step-up { background-color: var( --highcontrast-stepper-button-background-color-hover, var( @@ -680,11 +680,11 @@ governing permissions and limitations under the License. ) ); } -.stepDown:disabled, -.stepUp:disabled { +.step-down:disabled, +.step-up:disabled { border-color: #0000; } -.stepUp { +.step-up { border-end-end-radius: 0; border-end-start-radius: 0; border-start-end-radius: var(--spectrum-stepper-button-border-radius-reset); @@ -697,7 +697,7 @@ governing permissions and limitations under the License. var(--spectrum-stepper-icon-nudge-start) ); } -.stepDown { +.step-down { border-block-start-color: var( --highcontrast-stepper-border-color, var(--mod-stepper-border-color, var(--spectrum-stepper-border-color)) diff --git a/packages/number-field/stories/number-field-sizes.stories.ts b/packages/number-field/stories/number-field-sizes.stories.ts new file mode 100644 index 0000000000..d61a7f9cfb --- /dev/null +++ b/packages/number-field/stories/number-field-sizes.stories.ts @@ -0,0 +1,44 @@ +/* +Copyright 2018 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +import { html, TemplateResult } from '@spectrum-web-components/base'; + +import '@spectrum-web-components/number-field/sp-number-field.js'; +import '@spectrum-web-components/field-label/sp-field-label.js'; +import { ifDefined } from '@spectrum-web-components/base/src/directives.js'; + +export default { + component: 'sp-number-field', + title: 'Number Field/Sizes', +}; + +const template = ({ + size, +}: { + size?: 's' | 'm' | 'l' | 'xl'; +} = {}): TemplateResult => { + return html` + + Pick a number + + + `; +}; + +export const s = (): TemplateResult => template({ size: 's' }); +export const noSize = (): TemplateResult => template(); +export const m = (): TemplateResult => template({ size: 'm' }); +export const l = (): TemplateResult => template({ size: 'l' }); +export const XL = (): TemplateResult => template({ size: 'xl' }); diff --git a/packages/number-field/test/number-field.test.ts b/packages/number-field/test/number-field.test.ts index 90b0114d86..3df4d8ecad 100644 --- a/packages/number-field/test/number-field.test.ts +++ b/packages/number-field/test/number-field.test.ts @@ -73,6 +73,7 @@ describe('NumberField', () => { describe('receives input', () => { it('without language context', async () => { const el = await getElFrom(Default({ value: 1337 })); + el.size = 's'; expect(el.formattedValue).to.equal('1,337'); expect(el.valueAsString).to.equal('1337'); expect(el.value).to.equal(1337); @@ -92,6 +93,7 @@ describe('NumberField', () => { ${Default({ value: 1337 })} `); + el.size = 'l'; expect(el.formattedValue).to.equal('1 337'); expect(el.valueAsString).to.equal('1337'); expect(el.value).to.equal(1337); @@ -115,6 +117,7 @@ describe('NumberField', () => { value: 5, }) ); + el.size = 'xl'; expect(el.value).to.equal(5); expect(el.formattedValue).to.equal('5'); expect(el.valueAsString).to.equal('5'); @@ -129,17 +132,17 @@ describe('NumberField', () => { expect(el.valueAsString).to.equal('NaN'); }); it('via pointer, only "left" button', async () => { - await clickBySelector(el, '.stepUp', { button: 'middle' }); + await clickBySelector(el, '.step-up', { button: 'middle' }); expect(el.formattedValue).to.equal(''); expect(el.valueAsString).to.equal('NaN'); expect(el.value).to.be.NaN; }); it('via pointer', async () => { - await clickBySelector(el, '.stepUp'); + await clickBySelector(el, '.step-up'); expect(el.formattedValue).to.equal('0'); expect(el.valueAsString).to.equal('0'); expect(el.value).to.equal(0); - await clickBySelector(el, '.stepUp'); + await clickBySelector(el, '.step-up'); expect(el.formattedValue).to.equal('1'); expect(el.valueAsString).to.equal('1'); expect(el.value).to.equal(1); @@ -238,17 +241,17 @@ describe('NumberField', () => { expect(el.valueAsString).to.equal('NaN'); }); it('via pointer, only "left" button', async () => { - await clickBySelector(el, '.stepDown', { button: 'middle' }); + await clickBySelector(el, '.step-down', { button: 'middle' }); expect(el.formattedValue).to.equal(''); expect(el.valueAsString).to.equal('NaN'); expect(el.value).to.be.NaN; }); it('via pointer', async () => { - await clickBySelector(el, '.stepDown'); + await clickBySelector(el, '.step-down'); expect(el.formattedValue).to.equal('0'); expect(el.valueAsString).to.equal('0'); expect(el.value).to.equal(0); - await clickBySelector(el, '.stepDown'); + await clickBySelector(el, '.step-down'); expect(el.formattedValue).to.equal('-1'); expect(el.valueAsString).to.equal('-1'); expect(el.value).to.equal(-1); @@ -445,17 +448,17 @@ describe('NumberField', () => { expect(el.value).to.equal(50); }); it('one input/one change for each click', async () => { - await clickBySelector(el, '.stepUp'); + await clickBySelector(el, '.step-up'); expect(inputSpy.callCount).to.equal(1); expect(changeSpy.callCount).to.equal(1); expect(el.value).to.equal(51); - await clickBySelector(el, '.stepDown'); + await clickBySelector(el, '.step-down'); expect(inputSpy.callCount).to.equal(2); expect(changeSpy.callCount).to.equal(2); expect(el.value).to.equal(50); }); it('click with modifier key', async () => { - let target = el.shadowRoot.querySelector('.stepUp') as HTMLElement; + let target = el.shadowRoot.querySelector('.step-up') as HTMLElement; const stepUpRect = target.getBoundingClientRect(); const options = { bubbles: true, @@ -485,7 +488,7 @@ describe('NumberField', () => { expect(inputSpy.callCount).to.equal(1); expect(changeSpy.callCount).to.equal(1); expect(el.value).to.equal(60); - target = el.shadowRoot.querySelector('.stepDown') as HTMLElement; + target = el.shadowRoot.querySelector('.step-down') as HTMLElement; const stepDownRect = target.getBoundingClientRect(); options.clientX = stepDownRect.x + 1; options.clientY = stepDownRect.y + 1; @@ -499,7 +502,7 @@ describe('NumberField', () => { }); it('many input, but one change', async () => { const buttonUp = el.shadowRoot.querySelector( - '.stepUp' + '.step-up' ) as HTMLElement; const buttonUpRect = buttonUp.getBoundingClientRect(); const buttonUpPosition: [number, number] = [ @@ -507,7 +510,7 @@ describe('NumberField', () => { buttonUpRect.y + buttonUpRect.height / 2, ]; const buttonDown = el.shadowRoot.querySelector( - '.stepDown' + '.step-down' ) as HTMLElement; const buttonDownRect = buttonDown.getBoundingClientRect(); const buttonDownPosition: [number, number] = [ @@ -567,14 +570,14 @@ describe('NumberField', () => { expect(el.formattedValue).to.equal('50'); expect(el.valueAsString).to.equal('50'); expect(el.value).to.equal(50); - const buttonUp = el.shadowRoot.querySelector('.stepUp') as HTMLElement; + const buttonUp = el.shadowRoot.querySelector('.step-up') as HTMLElement; const buttonUpRect = buttonUp.getBoundingClientRect(); const buttonUpPosition: [number, number] = [ buttonUpRect.x + buttonUpRect.width / 2, buttonUpRect.y + buttonUpRect.height / 2, ]; const buttonDown = el.shadowRoot.querySelector( - '.stepDown' + '.step-down' ) as HTMLElement; const buttonDownRect = buttonDown.getBoundingClientRect(); const buttonDownPosition: [number, number] = [ @@ -678,12 +681,12 @@ describe('NumberField', () => { expect(el.formattedValue).to.equal('45%'); expect(el.valueAsString).to.equal('0.45'); expect(el.value).to.equal(0.45); - await clickBySelector(el, '.stepDown'); + await clickBySelector(el, '.step-down'); await elementUpdated(el); expect(el.formattedValue).to.equal('44%'); expect(el.valueAsString).to.equal('0.44'); expect(el.value).to.equal(0.44); - await clickBySelector(el, '.stepUp'); + await clickBySelector(el, '.step-up'); await elementUpdated(el); expect(el.formattedValue).to.equal('45%'); expect(el.valueAsString).to.equal('0.45'); @@ -764,7 +767,7 @@ describe('NumberField', () => { expect(el.value).to.equal(10); }); it('disabled `stepUp` button', async () => { - await clickBySelector(el, '.stepUp'); + await clickBySelector(el, '.step-up'); expect(el.formattedValue).to.equal('10'); expect(el.valueAsString).to.equal('10'); expect(el.value).to.equal(10); @@ -862,7 +865,7 @@ describe('NumberField', () => { expect(el.value).to.equal(100); }); it('disabled `stepDown` button', async () => { - await clickBySelector(el, '.stepDown'); + await clickBySelector(el, '.step-down'); expect(el.formattedValue).to.equal('10'); expect(el.valueAsString).to.equal('10'); expect(el.value).to.equal(10); @@ -902,13 +905,13 @@ describe('NumberField', () => { expect(el.value).to.equal(5); }); it('step up via pointer', async () => { - await clickBySelector(el, '.stepUp'); + await clickBySelector(el, '.step-up'); expect(el.formattedValue).to.equal('15'); expect(el.valueAsString).to.equal('15'); expect(el.value).to.equal(15); }); it('step down via pointer', async () => { - await clickBySelector(el, '.stepDown'); + await clickBySelector(el, '.step-down'); expect(el.formattedValue).to.equal('5'); expect(el.valueAsString).to.equal('5'); expect(el.value).to.equal(5); @@ -1109,10 +1112,10 @@ describe('NumberField', () => { (el as unknown as { displayValue: string }).displayValue ).to.equal('101'); }); - it('starts from `value` on click `.stepUp`', async () => { + it('starts from `value` on click `.step-up`', async () => { el.focus(); await elementUpdated(el); - await clickBySelector(el, '.stepUp'); + await clickBySelector(el, '.step-up'); await elementUpdated(el); expect(el.formattedValue).to.equal('101'); expect(el.valueAsString).to.equal('101'); @@ -1149,10 +1152,10 @@ describe('NumberField', () => { (el as unknown as { displayValue: string }).displayValue ).to.equal('99'); }); - it('starts from `value` on click `.stepDown`', async () => { + it('starts from `value` on click `.step-down`', async () => { el.focus(); await elementUpdated(el); - await clickBySelector(el, '.stepDown'); + await clickBySelector(el, '.step-down'); await elementUpdated(el); expect(el.formattedValue).to.equal('99'); expect(el.valueAsString).to.equal('99'); @@ -1172,8 +1175,8 @@ describe('NumberField', () => { }); it('removes the stepper UI with [hide-stepper]', async () => { const el = await getElFrom(Default({ hideStepper: true })); - const stepUp = el.shadowRoot.querySelector('.stepUp'); - const stepDown = el.shadowRoot.querySelector('.stepDown'); + const stepUp = el.shadowRoot.querySelector('.step-up'); + const stepDown = el.shadowRoot.querySelector('.step-down'); expect(stepUp).to.be.null; expect(stepDown).to.be.null; }); @@ -1211,10 +1214,10 @@ describe('NumberField', () => { el.dispatchEvent(new WheelEvent('wheel', { deltaY: -1 })); }); it('prevents increment via stepper button', async () => { - await clickBySelector(el, '.stepUp'); + await clickBySelector(el, '.step-up'); }); it('prevents decrement via stepper button', async () => { - await clickBySelector(el, '.stepDown'); + await clickBySelector(el, '.step-down'); }); }); describe('Readonly', () => { @@ -1251,10 +1254,10 @@ describe('NumberField', () => { el.dispatchEvent(new WheelEvent('wheel', { deltaY: -1 })); }); it('prevents increment via stepper button', async () => { - await clickBySelector(el, '.stepUp'); + await clickBySelector(el, '.step-up'); }); it('prevents decrement via stepper button', async () => { - await clickBySelector(el, '.stepDown'); + await clickBySelector(el, '.step-down'); }); }); }); diff --git a/packages/search/README.md b/packages/search/README.md index 3fdaba81ab..7e4581666c 100644 --- a/packages/search/README.md +++ b/packages/search/README.md @@ -24,13 +24,47 @@ When looking to leverage the `Search` base class as a type and/or for extension import { Search } from '@spectrum-web-components/search'; ``` -## Example +## Sizes + + +Small + + +```html + + +``` + + +Medium + ```html ``` + +Large + + +```html + + +``` + + +Extra Large + + +```html + + +``` + + + + ## Variants ### Quiet diff --git a/packages/search/src/Search.ts b/packages/search/src/Search.ts index 56444a5d31..9b776b0d34 100644 --- a/packages/search/src/Search.ts +++ b/packages/search/src/Search.ts @@ -118,6 +118,7 @@ export class Search extends Textfield { label="Reset" tabindex="-1" type="reset" + size=${ifDefined(this.size)} @keydown=${stopPropagation} > ` diff --git a/packages/search/src/search.css b/packages/search/src/search.css index 0c779466f5..a325f29062 100644 --- a/packages/search/src/search.css +++ b/packages/search/src/search.css @@ -21,3 +21,63 @@ governing permissions and limitations under the License. input::-webkit-search-cancel-button { display: none; } + +:host([size='s']) { + --spectrum-icon-tshirt-size-height: var( + --spectrum-alias-workflow-icon-size-s + ); + --spectrum-icon-tshirt-size-width: var( + --spectrum-alias-workflow-icon-size-s + ); + --spectrum-ui-icon-tshirt-size-height: var( + --spectrum-alias-ui-icon-cornertriangle-size-75 + ); + --spectrum-ui-icon-tshirt-size-width: var( + --spectrum-alias-ui-icon-cornertriangle-size-75 + ); +} + +:host([size='m']) { + --spectrum-icon-tshirt-size-height: var( + --spectrum-alias-workflow-icon-size-m + ); + --spectrum-icon-tshirt-size-width: var( + --spectrum-alias-workflow-icon-size-m + ); + --spectrum-ui-icon-tshirt-size-height: var( + --spectrum-alias-ui-icon-cornertriangle-size-100 + ); + --spectrum-ui-icon-tshirt-size-width: var( + --spectrum-alias-ui-icon-cornertriangle-size-100 + ); +} + +:host([size='l']) { + --spectrum-icon-tshirt-size-height: var( + --spectrum-alias-workflow-icon-size-l + ); + --spectrum-icon-tshirt-size-width: var( + --spectrum-alias-workflow-icon-size-l + ); + --spectrum-ui-icon-tshirt-size-height: var( + --spectrum-alias-ui-icon-cornertriangle-size-200 + ); + --spectrum-ui-icon-tshirt-size-width: var( + --spectrum-alias-ui-icon-cornertriangle-size-200 + ); +} + +:host([size='xl']) { + --spectrum-icon-tshirt-size-height: var( + --spectrum-alias-workflow-icon-size-xl + ); + --spectrum-icon-tshirt-size-width: var( + --spectrum-alias-workflow-icon-size-xl + ); + --spectrum-ui-icon-tshirt-size-height: var( + --spectrum-alias-ui-icon-cornertriangle-size-300 + ); + --spectrum-ui-icon-tshirt-size-width: var( + --spectrum-alias-ui-icon-cornertriangle-size-300 + ); +} diff --git a/packages/search/src/spectrum-config.js b/packages/search/src/spectrum-config.js index a83fc09ad1..0c503d00dd 100644 --- a/packages/search/src/spectrum-config.js +++ b/packages/search/src/spectrum-config.js @@ -36,6 +36,15 @@ const config = { converter.classToAttribute('spectrum-Search--quiet', 'quiet'), converter.classToId('spectrum-Search-clearButton', 'button'), converter.classToId('spectrum-Search-textfield', 'textfield'), + ...converter.enumerateAttributes( + [ + ['spectrum-Search--sizeS', 's'], + ['spectrum-Search--sizeM', 'm'], + ['spectrum-Search--sizeL', 'l'], + ['spectrum-Search--sizeXL', 'xl'], + ], + 'size' + ), { find: { type: 'pseudo-class', diff --git a/packages/search/src/spectrum-search.css b/packages/search/src/spectrum-search.css index 66cd0bc976..09bc8f177f 100644 --- a/packages/search/src/spectrum-search.css +++ b/packages/search/src/spectrum-search.css @@ -142,17 +142,17 @@ governing permissions and limitations under the License. var(--spectrum-search-background-color-disabled) ); } -.spectrum-Search--sizeS { +:host([size='s']) { --spectrum-search-block-size: var(--spectrum-component-height-75); --spectrum-search-icon-size: var(--spectrum-workflow-icon-size-75); --spectrum-search-text-to-icon: var(--spectrum-text-to-visual-75); } -.spectrum-Search--sizeL { +:host([size='l']) { --spectrum-search-block-size: var(--spectrum-component-height-200); --spectrum-search-icon-size: var(--spectrum-workflow-icon-size-200); --spectrum-search-text-to-icon: var(--spectrum-text-to-visual-200); } -.spectrum-Search--sizeXL { +:host([size='xl']) { --spectrum-search-block-size: var(--spectrum-component-height-300); --spectrum-search-icon-size: var(--spectrum-workflow-icon-size-300); --spectrum-search-text-to-icon: var(--spectrum-text-to-visual-300); @@ -372,7 +372,7 @@ governing permissions and limitations under the License. --system-spectrum-search-border-color-key-focus ); } -.spectrum-Search--sizeS { +:host([size='s']) { --spectrum-search-border-radius: var( --system-spectrum-search-sizes-border-radius ); @@ -380,7 +380,7 @@ governing permissions and limitations under the License. --system-spectrum-search-sizes-edge-to-visual ); } -.spectrum-Search--sizeM { +:host([size='m']) { --spectrum-search-border-radius: var( --system-spectrum-search-sizem-border-radius ); @@ -388,7 +388,7 @@ governing permissions and limitations under the License. --system-spectrum-search-sizem-edge-to-visual ); } -.spectrum-Search--sizeL { +:host([size='l']) { --spectrum-search-border-radius: var( --system-spectrum-search-sizel-border-radius ); @@ -396,7 +396,7 @@ governing permissions and limitations under the License. --system-spectrum-search-sizel-edge-to-visual ); } -.spectrum-Search--sizeXL { +:host([size='xl']) { --spectrum-search-border-radius: var( --system-spectrum-search-sizexl-border-radius ); diff --git a/packages/search/stories/search-sizes.stories.ts b/packages/search/stories/search-sizes.stories.ts new file mode 100644 index 0000000000..abb37cf6a9 --- /dev/null +++ b/packages/search/stories/search-sizes.stories.ts @@ -0,0 +1,45 @@ +/* +Copyright 2018 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +import { html, TemplateResult } from '@spectrum-web-components/base'; + +import '@spectrum-web-components/search/sp-search.js'; +import '@spectrum-web-components/field-label/sp-field-label.js'; +import '@spectrum-web-components/help-text/sp-help-text.js'; +import { ifDefined } from '@spectrum-web-components/base/src/directives.js'; + +export default { + component: 'sp-search', + title: 'Search/Sizes', +}; + +const template = ({ + size, +}: { + size?: 's' | 'm' | 'l' | 'xl'; +} = {}): TemplateResult => { + return html` + + What would you like to find? + + + + Anything within reason... + + + `; +}; + +export const s = (): TemplateResult => template({ size: 's' }); +export const noSize = (): TemplateResult => template(); +export const m = (): TemplateResult => template({ size: 'm' }); +export const l = (): TemplateResult => template({ size: 'l' }); +export const XL = (): TemplateResult => template({ size: 'xl' }); diff --git a/packages/textfield/README.md b/packages/textfield/README.md index 4eacac550e..3ca16bd19a 100644 --- a/packages/textfield/README.md +++ b/packages/textfield/README.md @@ -24,13 +24,59 @@ When looking to leverage the `Textfield` base class as a type and/or for extensi import { Textfield } from '@spectrum-web-components/textfield'; ``` -## Example +## Sizes + + +Small + + +```html +Name + +``` + + +Medium + + +```html +Name + +``` + + +Large + ```html -Name - +Name + +``` + + +Extra Large + + +```html +Name + ``` + + + ## Variants ### Valid diff --git a/packages/textfield/src/Textfield.ts b/packages/textfield/src/Textfield.ts index e91b55d339..946c8f8afe 100644 --- a/packages/textfield/src/Textfield.ts +++ b/packages/textfield/src/Textfield.ts @@ -15,6 +15,7 @@ import { html, nothing, PropertyValues, + SizedMixin, TemplateResult, } from '@spectrum-web-components/base'; import { @@ -42,7 +43,11 @@ export type TextfieldType = typeof textfieldTypes[number]; * @fires input - The value of the element has changed. * @fires change - An alteration to the value of the element has been committed by the user. */ -export class TextfieldBase extends ManageHelpText(Focusable) { +export class TextfieldBase extends ManageHelpText( + SizedMixin(Focusable, { + noDefaultSize: true, + }) +) { public static override get styles(): CSSResultArray { return [textfieldStyles, checkmarkStyles]; } diff --git a/packages/textfield/src/spectrum-config.js b/packages/textfield/src/spectrum-config.js index bcb5d56fc9..730a3934e3 100644 --- a/packages/textfield/src/spectrum-config.js +++ b/packages/textfield/src/spectrum-config.js @@ -43,6 +43,15 @@ export default { ], hoist: false, }, + ...converter.enumerateAttributes( + [ + ['spectrum-Textfield--sizeS', 's'], + ['spectrum-Textfield--sizeM', 'm'], + ['spectrum-Textfield--sizeL', 'l'], + ['spectrum-Textfield--sizeXL', 'xl'], + ], + 'size' + ), converter.classToClass( 'spectrum-Textfield-validationIcon', 'icon' diff --git a/packages/textfield/src/spectrum-textfield.css b/packages/textfield/src/spectrum-textfield.css index d75e35985a..c17f166620 100644 --- a/packages/textfield/src/spectrum-textfield.css +++ b/packages/textfield/src/spectrum-textfield.css @@ -176,7 +176,7 @@ governing permissions and limitations under the License. --spectrum-component-height-100 ); } -.spectrum-Textfield--sizeS { +:host([size='s']) { --spectrum-textfield-height: var(--spectrum-component-height-75); --spectrum-textfield-label-spacing-block-quiet: var( --spectrum-field-label-to-component-quiet-small @@ -225,7 +225,7 @@ governing permissions and limitations under the License. --spectrum-component-height-75 ); } -.spectrum-Textfield--sizeM { +:host([size='m']) { --spectrum-textfield-height: var(--spectrum-component-height-100); --spectrum-textfield-label-spacing-block-quiet: var( --spectrum-field-label-to-component-quiet-medium @@ -274,7 +274,7 @@ governing permissions and limitations under the License. --spectrum-component-height-100 ); } -.spectrum-Textfield--sizeL { +:host([size='l']) { --spectrum-textfield-height: var(--spectrum-component-height-200); --spectrum-textfield-label-spacing-block-quiet: var( --spectrum-field-label-to-component-quiet-large @@ -323,7 +323,7 @@ governing permissions and limitations under the License. --spectrum-component-height-200 ); } -.spectrum-Textfield--sizeXL { +:host([size='xl']) { --spectrum-textfield-height: var(--spectrum-component-height-300); --spectrum-textfield-label-spacing-block-quiet: var( --spectrum-field-label-to-component-quiet-extra-large diff --git a/packages/textfield/stories/textarea-sizes.stories.ts b/packages/textfield/stories/textarea-sizes.stories.ts new file mode 100644 index 0000000000..0873fe009a --- /dev/null +++ b/packages/textfield/stories/textarea-sizes.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2018 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +import { html, TemplateResult } from '@spectrum-web-components/base'; + +import '@spectrum-web-components/textfield/sp-textfield.js'; +import '@spectrum-web-components/field-label/sp-field-label.js'; +import '@spectrum-web-components/help-text/sp-help-text.js'; +import { ifDefined } from '@spectrum-web-components/base/src/directives.js'; + +export default { + component: 'sp-textfield', + title: 'Textarea/Sizes', +}; + +const template = ({ + size, +}: { + size?: 's' | 'm' | 'l' | 'xl'; +} = {}): TemplateResult => { + return html` + + Enter your life story + + + + Spare no expense. + + + `; +}; + +export const s = (): TemplateResult => template({ size: 's' }); +export const noSize = (): TemplateResult => template(); +export const m = (): TemplateResult => template({ size: 'm' }); +export const l = (): TemplateResult => template({ size: 'l' }); +export const XL = (): TemplateResult => template({ size: 'xl' }); diff --git a/packages/textfield/stories/textfield-sizes.stories.ts b/packages/textfield/stories/textfield-sizes.stories.ts new file mode 100644 index 0000000000..98646304f5 --- /dev/null +++ b/packages/textfield/stories/textfield-sizes.stories.ts @@ -0,0 +1,45 @@ +/* +Copyright 2018 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +import { html, TemplateResult } from '@spectrum-web-components/base'; + +import '@spectrum-web-components/textfield/sp-textfield.js'; +import '@spectrum-web-components/field-label/sp-field-label.js'; +import '@spectrum-web-components/help-text/sp-help-text.js'; +import { ifDefined } from '@spectrum-web-components/base/src/directives.js'; + +export default { + component: 'sp-textfield', + title: 'Textfield/Sizes', +}; + +const template = ({ + size, +}: { + size?: 's' | 'm' | 'l' | 'xl'; +} = {}): TemplateResult => { + return html` + + Enter your name + + + + This is for the whole enchilada. + + + `; +}; + +export const s = (): TemplateResult => template({ size: 's' }); +export const noSize = (): TemplateResult => template(); +export const m = (): TemplateResult => template({ size: 'm' }); +export const l = (): TemplateResult => template({ size: 'l' }); +export const XL = (): TemplateResult => template({ size: 'xl' }); diff --git a/packages/textfield/textarea.md b/packages/textfield/textarea.md index 6bb7f76991..a5473c7e66 100644 --- a/packages/textfield/textarea.md +++ b/packages/textfield/textarea.md @@ -24,17 +24,66 @@ When looking to leverage the `Textfield` base class as a type and/or for extensi import { Textfield } from '@spectrum-web-components/textfield'; ``` -## Example +## Sizes + + +Small + + +```html +Background + +``` + + +Medium + ```html -Background +Background ``` + +Large + + +```html +Background + +``` + + +Extra Large + + +```html +Background + +``` + + + + ## Variants ### Valid