diff --git a/__snapshots__/Action-Group.md b/__snapshots__/Action-Group.md new file mode 100644 index 000000000..03f557630 --- /dev/null +++ b/__snapshots__/Action-Group.md @@ -0,0 +1,12 @@ +# `Action-Group` + +#### `should internal contents` + +```html +
+ + +
+ +``` + diff --git a/components/action-group/package.json b/components/action-group/package.json new file mode 100644 index 000000000..561b8bb10 --- /dev/null +++ b/components/action-group/package.json @@ -0,0 +1,42 @@ +{ + "name": "@vonage/vwc-action-group", + "version": "2.30.3", + "description": "action-group component", + "homepage": "https://github.com/Vonage/vivid/tree/master/components/action-group#readme", + "license": "ISC", + "main": "vwc-action-group.js", + "module": "vwc-action-group.js", + "files": [ + "src", + "*.js", + "*.ts", + "*.map" + ], + "repository": { + "type": "git", + "url": "https://github.com/vonage/vivid.git", + "directory": "components/action-group" + }, + "scripts": { + "test": "echo \"Error: run tests from root\" && exit 1", + "build:typescript": "tsc -b", + "build:styles": "umbrella-style-modules", + "build": "yarn run build:styles && yarn run build:typescript" + }, + "bugs": { + "url": "https://github.com/Vonage/vivid/issues" + }, + "dependencies": { + "@vonage/vvd-core": "2.31.0", + "@vonage/vvd-foundation": "2.31.0", + "lit-element": "^2.4.0", + "tslib": "^2.3.0" + }, + "devDependencies": { + "@vonage/vvd-design-tokens": "2.31.0", + "@vonage/vvd-typography": "2.31.0", + "@vonage/vvd-umbrella": "2.31.0", + "lit-html": "^1.3.0", + "typescript": "^4.3.2" + } +} diff --git a/components/action-group/src/vwc-action-group-base.ts b/components/action-group/src/vwc-action-group-base.ts new file mode 100644 index 000000000..49bc121ab --- /dev/null +++ b/components/action-group/src/vwc-action-group-base.ts @@ -0,0 +1,44 @@ +import { + html, LitElement, property, TemplateResult +} from 'lit-element'; +import { classMap } from 'lit-html/directives/class-map.js'; +import type { ClassInfo } from 'lit-html/directives/class-map.js'; +import type { Shape, Layout } from '@vonage/vvd-foundation/constants.js'; + +type ActionGroupLayout = Extract< + Layout, + Layout.Outlined | Layout.Ghost +>; + +type ActionGroupShape = Extract; + + +/** + * @slot - This is a default/unnamed slot to assign text content. *deprecated* please use _text_ property instead + */ +export class VWCActionGroupBase extends LitElement { + @property({ type: String, reflect: true }) + shape?: ActionGroupShape; + + @property({ type: String, reflect: true }) + layout?: ActionGroupLayout; + + @property({ type: Boolean, reflect: true }) + tight = false; + + protected getRenderClasses(): ClassInfo { + return { + [`shape-${this.shape}`]: !!this.shape, + [`layout-${this.layout}`]: !!this.layout, + ['tight']: !!this.tight, + }; + } + + protected override render(): TemplateResult { + return html` +
+ + +
`; + } +} diff --git a/components/action-group/src/vwc-action-group.scss b/components/action-group/src/vwc-action-group.scss new file mode 100644 index 000000000..30a0d10d8 --- /dev/null +++ b/components/action-group/src/vwc-action-group.scss @@ -0,0 +1,54 @@ +@use '@vonage/vvd-design-tokens/build/scss/semantic-variables/scheme-variables' as scheme-variables; + +@use '@vonage/vvd-foundation/scss/mixins/layout/config' as layout-config with ( + $layout-set: outlined ghost, + $default: ghost, +); +@use '@vonage/vvd-foundation/scss/mixins/layout' as layout; + + +.vwc-action-group { + @include layout.layout; + + display: inline-flex; + box-sizing: border-box; + align-items: center; + color: var(#{scheme-variables.$vvd-color-on-canvas}); + vertical-align: middle; + + /* Shape */ + &:not(.shape-pill) { + border-radius: 6px; + } + + &.shape-pill { + border-radius: 24px; + } + /* Appearance */ + &.layout-outlined { + position: relative; + background-color: var(#{scheme-variables.$vvd-color-canvas}); + &::before { + position: absolute; + z-index: 1; + border-radius: inherit; + box-shadow: inset 0 0 0 1px var(#{scheme-variables.$vvd-color-neutral-50}); + content: ''; + inset: 0; + pointer-events: none; + } + } + + /* Tight */ + &:not(.tight) { + padding: 4px; + column-gap: 4px; + } +} + +::slotted([role='separator']) { + width: 1px; + align-self: stretch; + background-color: var(#{scheme-variables.$vvd-color-neutral-30}); + margin-block: 4px; +} diff --git a/components/action-group/src/vwc-action-group.ts b/components/action-group/src/vwc-action-group.ts new file mode 100644 index 000000000..05b130ea4 --- /dev/null +++ b/components/action-group/src/vwc-action-group.ts @@ -0,0 +1,20 @@ +import '@vonage/vvd-core'; +import { customElement } from 'lit-element'; + +import { VWCActionGroupBase } from './vwc-action-group-base.js'; +import { style } from './vwc-action-group.css.js'; + +/** + * Represents an action-group custom element. + */ + +@customElement('vwc-action-group') +export class VWCActionGroup extends VWCActionGroupBase { + static override styles = style; +} + +declare global { + interface HTMLElementTagNameMap { + 'vwc-action-group': VWCActionGroup; + } +} diff --git a/components/action-group/stories/action-group.stories.js b/components/action-group/stories/action-group.stories.js new file mode 100644 index 000000000..e48456ca9 --- /dev/null +++ b/components/action-group/stories/action-group.stories.js @@ -0,0 +1,77 @@ +import '@vonage/vwc-action-group/vwc-action-group.js'; +import { html } from 'lit-element'; +import { spread } from '@open-wc/lit-helpers'; +import { argTypes } from './arg-types.js'; + +export default { + title: 'Alpha/Components/ActionGroup', + component: 'vwc-action-group', + argTypes +}; + +const ActionGroupOutlinedTemplate = args => html` + + + + + `; + +export const Outlined = ActionGroupOutlinedTemplate.bind({}); +Outlined.args = { layout: 'outlined' }; + +const ActionGroupGhostTemplate = args => html` + + + + + `; + +export const Ghost = ActionGroupGhostTemplate.bind({}); +Ghost.args = { }; + +const ActionGroupPillTemplate = args => html` + + + + + `; + +export const PillShape = ActionGroupPillTemplate.bind({}); +PillShape.args = { layout: 'outlined', shape: 'pill' }; + +const ActionGroupSeparatorTemplate = args => html` + +

Use a <span> tag with role="separator" for adding separator between the action elements

+ + + + + + + + + + `; + +export const Separator = ActionGroupSeparatorTemplate.bind({}); +Separator.args = { layout: 'outlined' }; + +const ActionGroupTightTemplate = args => html` +
+ + + +1 + + + + + + + +
`; + +export const tight = ActionGroupTightTemplate.bind({}); +tight.args = { layout: 'outlined', tight }; + + + diff --git a/components/action-group/stories/arg-types.js b/components/action-group/stories/arg-types.js new file mode 100644 index 000000000..9f01e3065 --- /dev/null +++ b/components/action-group/stories/arg-types.js @@ -0,0 +1,4 @@ +export const argTypes = { + +}; + diff --git a/components/action-group/test/action-group.test.js b/components/action-group/test/action-group.test.js new file mode 100644 index 000000000..ff9934f0a --- /dev/null +++ b/components/action-group/test/action-group.test.js @@ -0,0 +1,63 @@ +import '../vwc-action-group.js'; +import { + isolatedElementsCreation, textToDomToParent +} from '../../../test/test-helpers.js'; +import { chaiDomDiff } from '@open-wc/semantic-dom-diff'; +import {VWCActionGroup} from '../vwc-action-group.js'; + +chai.use(chaiDomDiff); + +const COMPONENT_NAME = 'vwc-action-group'; + +describe ('Action-Group', () => { + let addElement = isolatedElementsCreation(); + let element; + + beforeEach(async function () { + [element] = ( + textToDomToParent(`<${COMPONENT_NAME}>Content`) + ); + await element.updateComplete; + }); + + it(`${COMPONENT_NAME} is defined as a custom element`, async () => { + assert.exists( + customElements.get(COMPONENT_NAME) + ); + }); + + it('should internal contents', async () => { + await element.updateComplete; + expect(element.shadowRoot.innerHTML).to.equalSnapshot(); + }); + + describe('basic', () => { + it('should be initialized as a vwc-action-group', async () => { + expect(element instanceof VWCActionGroup).to.equal(true); + }); + }); + + describe('layout', function () { + it('should set the outline class on the base', async function () { + const control = element.shadowRoot?.querySelector('.vwc-action-group'); + const layout = 'outlined'; + element.layout = layout; + await element.updateComplete; + + expect(control?.classList.contains(`layout-${layout}`)) + .to.equal(true); + }); + }); + + describe('shape', function () { + it('should set the shape class on the base', async function () { + const control = element.shadowRoot?.querySelector('.vwc-action-group'); + const shape = 'pill'; + element.shape = shape; + await element.updateComplete; + + expect(control?.classList.contains(`shape-${shape}`)) + .to.equal(true); + }); + }); +}); diff --git a/components/action-group/tsconfig.json b/components/action-group/tsconfig.json new file mode 100644 index 000000000..b81b6b34f --- /dev/null +++ b/components/action-group/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@vonage/vvd-umbrella/configs/tsconfig.json", + "compilerOptions": { + "composite": true, + "rootDir": "src", + "outDir": ".", + "tsBuildInfoFile": ".tsbuildinfo" + }, + "include": [ + "src/*.ts" + ], + "exclude": [ + "src/test/*.ts" + ] +} \ No newline at end of file diff --git a/ui-tests/snapshots/vwc-action-group.png b/ui-tests/snapshots/vwc-action-group.png new file mode 100644 index 000000000..1ed453b9f Binary files /dev/null and b/ui-tests/snapshots/vwc-action-group.png differ diff --git a/ui-tests/tests/vwc-action-group/index.js b/ui-tests/tests/vwc-action-group/index.js new file mode 100644 index 000000000..1b05642b9 --- /dev/null +++ b/ui-tests/tests/vwc-action-group/index.js @@ -0,0 +1,62 @@ +import '@vonage/vwc-action-group'; +import '@vonage/vwc-button'; +import '@vonage/vwc-icon-button'; +import '@vonage/vwc-textfield'; +import '@vonage/vwc-icon'; + + +export async function createElementVariations(wrapper) { + const actionGroupWrapper = document.createElement('div'); + actionGroupWrapper.innerHTML = + ` + + + + + +
+ + + + + +
+ + + + + +
+ + + + + + + + + + +
+ + + + + + +
+ + + +1 + + + + + + +
+ `; + wrapper.appendChild(actionGroupWrapper); +} + +