Skip to content

Commit

Permalink
feat(menu): cwc menu component
Browse files Browse the repository at this point in the history
  • Loading branch information
sangeethababu9223 committed Apr 24, 2024
1 parent 749ca03 commit 093c596
Show file tree
Hide file tree
Showing 12 changed files with 714 additions and 0 deletions.
15 changes: 15 additions & 0 deletions packages/carbon-web-components/src/components/menu/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* @license
*
* Copyright IBM Corp. 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import './menu';
import './menu-item';
import './menu-item-divider';
import './menu-item-group';
import './menu-item-selectable';
import './menu-item-radio-group';
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @license
*
* Copyright IBM Corp. 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import { LitElement, html } from 'lit';
import { property } from 'lit/decorators.js';
import { prefix } from '../../globals/settings';
import styles from './menu-item.scss?lit';
import { carbonElement as customElement } from '../../globals/decorators/carbon-element';
import { classMap } from 'lit/directives/class-map.js';

/**
* Menu Item.
*
* @element cds-menu-item-divider
*/
@customElement(`${prefix}-menu-item-divider`)
class CDSmenuItemDivider extends LitElement {
render() {
return html`
<li class="${prefix}--menu-item-divider" role="separator"></li>
`;
}
static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader
}
export default CDSmenuItemDivider;
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @license
*
* Copyright IBM Corp. 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import { LitElement, html } from 'lit';
import { property } from 'lit/decorators.js';
import { prefix } from '../../globals/settings';
import styles from './menu-item.scss?lit';
import { carbonElement as customElement } from '../../globals/decorators/carbon-element';
import { classMap } from 'lit/directives/class-map.js';

/**
* Menu Item.
*
* @element cds-menu-item-group
*/
@customElement(`${prefix}-menu-item-group`)
class CDSmenuItemGroup extends LitElement {
/**
* Label for the menu item.
*/
@property({ type: String })
label;

render() {
const { label } = this;
return html`
<li class="${prefix}--menu-item-group" role="none">
<ul role="group" aria-label="${label}">
<slot></slot>
</ul>
</li>
`;
}
static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader
}
export default CDSmenuItemGroup;
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* @license
*
* Copyright IBM Corp. 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import { LitElement, html } from 'lit';
import { property } from 'lit/decorators.js';
import { prefix } from '../../globals/settings';
import styles from './menu-item.scss?lit';
import { carbonElement as customElement } from '../../globals/decorators/carbon-element';
import { classMap } from 'lit/directives/class-map.js';
import { EventHandler } from 'react';

/**
* Menu Item.
*
* @element cds-menu-item-radio-group
*/
@customElement(`${prefix}-menu-item-radio-group`)
class CDSmenuItemRadioGroup extends LitElement {
/**
* Label for the menu item radio group.
*/
@property({ type: String })
label;
/**
* List of items in the radio group.
*/
@property()
items;

/**
* Selected item in the radio group.
*/
@property({ type: String, attribute: true })
selectedItem;

/**
* List of items in the radio group.
*/
itemToString?: (item: Array<String | Number>) => String;
/**
* Provide an optional function to be called when the selection state changes.
*/
onChange?;

_handleClick = (item, e) => {
this.selectedItem = item;
if (this.onChange) {
this.onChange(e);
}
};
render() {
const defaultItemToString = (item) => item.toString();
const {
label,
items,
itemToString = defaultItemToString,
selectedItem,
_handleClick: handleClick,
} = this;
let parsedItems = JSON.parse(items);
return html`
<li class="${prefix}--menu-item-radio-group" role="none">
<ul role="group" label="${label}">
${parsedItems.map(
(item) =>
html`
<cds-menu-item
label="${itemToString(item)}"
role="menuitemradio"
aria-checked="${item === selectedItem}"
renderIcon="${item === selectedItem
? 'checkMark'
: undefined}"
@click="${(e) => {
handleClick(item, e);
}}"></cds-menu-item>
`
)}
</ul>
</li>
`;
}
static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader
}
export default CDSmenuItemRadioGroup;
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* @license
*
* Copyright IBM Corp. 2019, 2023
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import { LitElement, html } from 'lit';
import { property } from 'lit/decorators.js';
import { prefix } from '../../globals/settings';
import styles from './menu-item.scss?lit';
import { carbonElement as customElement } from '../../globals/decorators/carbon-element';
import { classMap } from 'lit/directives/class-map.js';
import Checkmark16 from '@carbon/icons/lib/checkmark/16';
/**
* Menu Item.
*
* @element cds-menu-item
*/
@customElement(`${prefix}-menu-item-selectable`)
class CDSmenuItemSelectable extends LitElement {
/**
* Label for the menu item selectable.
*/
@property({ type: String })
label;
/**
* Whether the menu item is selected or not.
*/
@property({ type: Boolean })
selected = false;

/**
* Provide an optional function to be called when the selection state changes.
*/
onChange?;

_handleClick = (e) => {
this.selected = !this.selected;
if (this.onChange) {
this.onChange(e);
}
};
render() {
const { label, selected, _handleClick: handleClick } = this;
let checked = true;
return html`
<cds-menu-item
label="${label}"
aria-checked="${selected}"
renderIcon="${selected ? 'checkMark' : undefined}"
@click="${handleClick}"></cds-menu-item>
`;
}
static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader
}
export default CDSmenuItemSelectable;
100 changes: 100 additions & 0 deletions packages/carbon-web-components/src/components/menu/menu-item.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// Copyright IBM Corp. 2024
//
// This source code is licensed under the Apache-2.0 license found in the
// LICENSE file in the root directory of this source tree.
//

$css--plex: true !default;

@use '@carbon/styles/scss/config' as *;
@use '@carbon/styles/scss/spacing' as *;
@use '@carbon/styles/scss/theme' as *;
@use '@carbon/styles/scss/motion' as *;
@use '@carbon/styles/scss/utilities' as *;
@use '@carbon/styles/scss/components/button/tokens' as button-tokens;
@use '@carbon/styles/scss/utilities/convert' as *;

.#{$prefix}--menu-item {
display: grid;
align-items: center;
block-size: 2rem;
color: $text-secondary;
column-gap: $spacing-03;
cursor: pointer;
grid-template-columns: var(--child-grid-template-columns, 1fr max-content);
padding-inline: $spacing-05;
transition: background-color $duration-fast-01 motion(standard, productive);
&:focus {
@include focus-outline('outline');
}

svg {
color: $icon-secondary;
}
}

.#{$prefix}--menu-item:hover {
background-color: $layer-hover;
color: $text-primary;

svg {
color: $icon-primary;
}
}

$supported-sizes: (
'xs': 1.5rem,
'sm': 2rem,
'md': 2.5rem,
'lg': 3rem,
);

@each $size, $value in $supported-sizes {
.#{$prefix}--menu--#{$size} .#{$prefix}--menu-item {
block-size: $value;
}
}
.#{$prefix}--menu-item__label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.#{$prefix}--menu-item__shortcut {
display: flex;
}
.#{$prefix}--menu-item__icon {
display: var(--child-icon-property, none);
}
.#{$prefix}--menu-item--disabled {
color: $text-disabled;
cursor: not-allowed;
}

.#{$prefix}--menu-item--disabled:hover,
.#{$prefix}--menu-item--disabled.#{$prefix}--menu-item--danger:hover {
background-color: $layer;
color: $text-disabled;
}
.#{$prefix}--menu-item--danger:focus,
.#{$prefix}--menu-item--danger:hover {
background-color: button-tokens.$button-danger-primary;
color: $text-on-color;
}
// MenuItemDivider

.#{$prefix}--menu-item-divider {
display: block;
background-color: $border-subtle;
block-size: to-rem(1px);
inline-size: 100%;
margin-block: $spacing-02;
}
.#{$prefix}--menu-item-group > ul,
.#{$prefix}--menu-item-radio-group > ul {
@include component-reset;
}
.#{$prefix}--menu-item-group > ul > .#{$prefix}--menu-item {
grid-template-columns: var(--child-grid-template-columns, 1fr max-content);
}
Loading

0 comments on commit 093c596

Please sign in to comment.