@trimble-oss/moduswebcomponents
Version:
Modus Web Components is a modern, accessible UI library built with Stencil JS that provides reusable web components following Trimble's Modus design system. This updated version focuses on improved flexibility, enhanced theming options, comprehensive cust
355 lines (354 loc) • 13.1 kB
JavaScript
import { h, Host, } from "@stencil/core";
import { handleShadowDOMStyles } from "../base-component";
import { inheritAriaAttributes } from "../utils";
/**
* A customizable buttongroup component that groups multiple Modus buttons together.
*
* The component supports a `<slot>` for injecting content within the buttongroup.
*/
export class ModusWcButtonGroup {
constructor() {
this.inheritedAttributes = {};
this.selectedButtons = [];
/** Style variant to apply to all buttons within the button group */
this.variant = 'outlined';
/** Disables all buttons within the button group */
this.disabled = false;
/** Orientation of the button group: horizontal or vertical */
this.orientation = 'horizontal';
/** Selection type for button group */
this.selectionType = 'default';
}
componentWillLoad() {
handleShadowDOMStyles(this.el);
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
componentDidLoad() {
this.buttonElements = this.el.querySelectorAll('modus-wc-button');
this.syncButtonStates();
this.initializeSelectedButtons();
}
handlePropChange() {
this.syncButtonStates();
}
handleSelectionTypeChange() {
this.resetAllSelections();
}
handleButtonClick(event) {
const clickedButton = event.target;
if (this.selectionType === 'default') {
this.buttonGroupClick.emit({
button: clickedButton,
isSelected: false,
});
return;
}
switch (this.selectionType) {
case 'single':
void this.toggleSingleSelect(clickedButton);
break;
case 'multiple':
void this.toggleMultiSelect(clickedButton);
break;
}
}
handleSlotChange() {
this.buttonElements = this.el.querySelectorAll('modus-wc-button');
this.syncButtonStates();
this.initializeSelectedButtons();
}
initializeSelectedButtons() {
if (!this.buttonElements || !this.buttonElements.length)
return;
this.selectedButtons = [];
const pressedButtons = [];
Array.from(this.buttonElements).forEach((button) => {
if (button.hasAttribute('pressed')) {
pressedButtons.push(button);
}
});
if (this.selectionType === 'single' && pressedButtons.length > 0) {
const firstSelected = pressedButtons[0];
this.selectedButtons = [firstSelected];
// Remove pressed attribute from other buttons
pressedButtons.slice(1).forEach((button) => {
button.removeAttribute('pressed');
});
}
else if (this.selectionType === 'multiple') {
// For multiple selection, keep all pressed buttons
this.selectedButtons = pressedButtons;
}
}
syncButtonStates() {
if (!this.buttonElements || !this.buttonElements.length)
return;
this.setButtonAttribute('variant', this.variant);
this.setButtonAttribute('color', this.color || null);
this.setButtonAttribute('disabled', this.disabled ? 'true' : null);
}
setButtonAttribute(name, value) {
this.buttonElements.forEach((button) => {
if (value !== null && value !== undefined) {
button.setAttribute(name, value);
}
else {
button.removeAttribute(name);
}
});
}
toggleSingleSelect(clickedButton) {
const isCurrentlySelected = this.selectedButtons.includes(clickedButton);
// In single selection mode, clicking an already selected button does nothing
if (isCurrentlySelected) {
return;
}
// Deactivate all buttons
Array.from(this.buttonElements).forEach((button) => {
button.removeAttribute('pressed');
});
// Activate the clicked button
clickedButton.setAttribute('pressed', '');
this.selectedButtons = [clickedButton];
this.buttonGroupClick.emit({
button: clickedButton,
isSelected: true,
});
this.buttonSelectionChange.emit({
selectedButtons: this.selectedButtons,
});
}
toggleMultiSelect(clickedButton) {
const isCurrentlySelected = this.selectedButtons.includes(clickedButton);
if (isCurrentlySelected) {
// Deactivate and remove from selection
clickedButton.removeAttribute('pressed');
this.selectedButtons = this.selectedButtons.filter((btn) => btn !== clickedButton);
}
else {
// Activate and add to selection
clickedButton.setAttribute('pressed', '');
this.selectedButtons = [...this.selectedButtons, clickedButton];
}
this.buttonGroupClick.emit({
button: clickedButton,
isSelected: !isCurrentlySelected,
});
this.buttonSelectionChange.emit({
selectedButtons: this.selectedButtons,
});
}
resetAllSelections() {
if (!this.buttonElements)
return;
Array.from(this.buttonElements).forEach((button) => {
button.removeAttribute('pressed');
});
this.selectedButtons = [];
}
getClasses() {
const classList = ['modus-wc-button-group'];
// Add vertical class if needed
if (this.orientation === 'vertical') {
classList.push('modus-wc-join-vertical');
}
return classList.join(' ');
}
render() {
return (h(Host, Object.assign({ key: 'f42ba438e89b39f40ac45d5653cb38b6a80930d5' }, this.inheritedAttributes, { role: "group", class: this.getClasses() }), h("slot", { key: 'ed6fe4d9cfc9a7d8e694bbc40a36e3bf5f6869d5' })));
}
static get is() { return "modus-wc-button-group"; }
static get originalStyleUrls() {
return {
"$": ["modus-wc-button-group.scss"]
};
}
static get styleUrls() {
return {
"$": ["modus-wc-button-group.css"]
};
}
static get properties() {
return {
"variant": {
"type": "string",
"attribute": "variant",
"mutable": false,
"complexType": {
"original": "'borderless' | 'filled' | 'outlined'",
"resolved": "\"borderless\" | \"filled\" | \"outlined\"",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Style variant to apply to all buttons within the button group"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "'outlined'"
},
"color": {
"type": "string",
"attribute": "color",
"mutable": false,
"complexType": {
"original": "| 'primary'\n | 'secondary'\n | 'tertiary'\n | 'warning'\n | 'danger'\n | 'neutral'",
"resolved": "\"danger\" | \"neutral\" | \"primary\" | \"secondary\" | \"tertiary\" | \"warning\" | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Color to apply to all buttons within the button group"
},
"getter": false,
"setter": false,
"reflect": false
},
"disabled": {
"type": "boolean",
"attribute": "disabled",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Disables all buttons within the button group"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "false"
},
"orientation": {
"type": "string",
"attribute": "orientation",
"mutable": false,
"complexType": {
"original": "Orientation",
"resolved": "\"horizontal\" | \"vertical\" | undefined",
"references": {
"Orientation": {
"location": "import",
"path": "../types",
"id": "src/components/types.ts::Orientation"
}
}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Orientation of the button group: horizontal or vertical"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "'horizontal'"
},
"selectionType": {
"type": "string",
"attribute": "selection-type",
"mutable": false,
"complexType": {
"original": "'default' | 'single' | 'multiple'",
"resolved": "\"default\" | \"multiple\" | \"single\" | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Selection type for button group"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "'default'"
}
};
}
static get events() {
return [{
"method": "buttonGroupClick",
"name": "buttonGroupClick",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": "Event emitted when any button in the group is clicked"
},
"complexType": {
"original": "{\n button: HTMLElement;\n isSelected: boolean;\n }",
"resolved": "{ button: HTMLElement; isSelected: boolean; }",
"references": {
"HTMLElement": {
"location": "global",
"id": "global::HTMLElement"
}
}
}
}, {
"method": "buttonSelectionChange",
"name": "buttonSelectionChange",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": "Event emitted when button selection changes"
},
"complexType": {
"original": "{\n selectedButtons: HTMLElement[];\n }",
"resolved": "{ selectedButtons: HTMLElement[]; }",
"references": {
"HTMLElement": {
"location": "global",
"id": "global::HTMLElement"
}
}
}
}];
}
static get elementRef() { return "el"; }
static get watchers() {
return [{
"propName": "variant",
"methodName": "handlePropChange"
}, {
"propName": "color",
"methodName": "handlePropChange"
}, {
"propName": "disabled",
"methodName": "handlePropChange"
}, {
"propName": "selectionType",
"methodName": "handleSelectionTypeChange"
}];
}
static get listeners() {
return [{
"name": "buttonClick",
"method": "handleButtonClick",
"target": undefined,
"capture": false,
"passive": false
}, {
"name": "slotchange",
"method": "handleSlotChange",
"target": undefined,
"capture": false,
"passive": false
}];
}
}