@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
246 lines (234 loc) • 8.68 kB
JavaScript
import { html, unsafeCSS } from "lit";
import { ifDefined } from "lit/directives/if-defined.js";
import { keyed } from "lit/directives/keyed.js";
// Shared styles for story demos
const storyStyles = unsafeCSS(`
.handle-demo-container {
display: flex;
gap: 0;
}
.handle-demo-container.horizontal {
height: 300px;
}
.handle-demo-container.vertical {
flex-direction: column;
height: 500px;
}
.handle-demo-panel {
background-color: var(--modus-wc-color-base-100);
overflow: auto;
}
.handle-demo-panel.initial-size-200 {
width: 200px;
}
.handle-demo-panel.initial-height-200 {
height: 200px;
}
.handle-demo-panel.initial-size-400 {
width: 400px;
}
.handle-demo-panel.flex-fill {
flex: 1;
}
.handle-demo-right-container {
flex: 1;
display: flex;
flex-direction: column;
gap: 0;
}
`);
const meta = {
title: 'Components/Handle',
component: 'modus-wc-handle',
args: {
'button-color': 'tertiary',
'button-size': 'md',
'button-variant': 'filled',
'custom-class': '',
'default-split': 50,
density: 'comfortable',
'left-target': '',
orientation: 'vertical',
'right-target': '',
size: 'default',
type: 'bar',
},
argTypes: {
'custom-class': {
control: 'text',
},
'default-split': {
control: { type: 'range', min: 1, max: 100, step: 1 },
},
density: {
control: { type: 'select' },
options: ['compact', 'comfortable', 'relaxed'],
},
'button-size': {
control: { type: 'select' },
options: ['sm', 'md', 'lg', 'xl'],
},
'button-color': {
control: { type: 'select' },
options: ['primary', 'secondary', 'tertiary', 'warning', 'danger'],
},
'button-variant': {
control: { type: 'select' },
options: ['borderless', 'filled', 'outlined'],
},
'left-target': {
control: 'text',
},
orientation: {
control: { type: 'select' },
options: ['horizontal', 'vertical'],
},
'right-target': {
control: 'text',
},
size: {
control: { type: 'select' },
options: ['default', 'lg', 'xl', '2xl'],
},
type: {
control: { type: 'select' },
options: ['bar', 'button'],
},
},
parameters: {
layout: 'padded',
},
};
export default meta;
const HandleTemplate = (args) =>
// prettier-ignore
html `
<modus-wc-handle
custom-class="${ifDefined(args === null || args === void 0 ? void 0 : args['custom-class'])}"
default-split="${args === null || args === void 0 ? void 0 : args['default-split']}"
density="${args === null || args === void 0 ? void 0 : args.density}"
button-size="${args === null || args === void 0 ? void 0 : args['button-size']}"
button-color="${args === null || args === void 0 ? void 0 : args['button-color']}"
button-variant="${args === null || args === void 0 ? void 0 : args['button-variant']}"
left-target="${ifDefined(args === null || args === void 0 ? void 0 : args['left-target'])}"
orientation="${ifDefined(args === null || args === void 0 ? void 0 : args.orientation)}"
right-target="${ifDefined(args === null || args === void 0 ? void 0 : args['right-target'])}"
size="${args === null || args === void 0 ? void 0 : args.size}"
type="${args === null || args === void 0 ? void 0 : args.type}"
></modus-wc-handle>
`;
// Helper templates for panels
const PanelTemplate = (id, title, content, className = '') =>
// prettier-ignore
html `
<div id="${id}" class="handle-demo-panel ${className}">
<h3>${title}</h3>
<p>${content}</p>
</div>
`;
const PanelWithKeyboardInfo = (id, title, content, keyboardInfo, className = '') =>
// prettier-ignore
html `
<div id="${id}" class="handle-demo-panel ${className}">
<h3>${title}</h3>
<p>${content}</p>
<p><strong>Keyboard:</strong> ${keyboardInfo}</p>
</div>
`;
// Generate unique ID for each render to avoid conflicts on docs page
const generateUniqueId = () => Math.random().toString(36).substring(2, 9);
// Reusable render function for demos
const Template = (args) => {
var _a, _b, _c, _d, _e;
const orientation = (_a = args === null || args === void 0 ? void 0 : args.orientation) !== null && _a !== void 0 ? _a : 'horizontal';
const type = (_b = args === null || args === void 0 ? void 0 : args.type) !== null && _b !== void 0 ? _b : 'bar';
const isHorizontal = orientation === 'horizontal';
const uniqueId = generateUniqueId();
const leftId = `panel-left-${uniqueId}`;
const rightId = `panel-right-${uniqueId}`;
// prettier-ignore
return html `
<style>${storyStyles}</style>
${keyed(orientation, html `
<div class="handle-demo-container ${isHorizontal ? 'horizontal' : 'vertical'}">
${PanelWithKeyboardInfo(leftId, isHorizontal ? 'Left Panel' : 'Top Panel', 'Drag the handle to resize this panel.', `Focus the handle and use ${isHorizontal ? 'Left/Right' : 'Up/Down'} arrow keys to resize (5px per press, 15px with Shift).`, isHorizontal ? 'initial-size-200' : 'initial-height-200')}
${HandleTemplate({
orientation: orientation,
size: (_c = args === null || args === void 0 ? void 0 : args.size) !== null && _c !== void 0 ? _c : 'default',
density: (_d = args === null || args === void 0 ? void 0 : args.density) !== null && _d !== void 0 ? _d : 'comfortable',
type: type,
'default-split': (_e = args === null || args === void 0 ? void 0 : args['default-split']) !== null && _e !== void 0 ? _e : 50,
'custom-class': args === null || args === void 0 ? void 0 : args['custom-class'],
'button-size': args === null || args === void 0 ? void 0 : args['button-size'],
'button-color': args === null || args === void 0 ? void 0 : args['button-color'],
'button-variant': args === null || args === void 0 ? void 0 : args['button-variant'],
'left-target': `#${leftId}`,
'right-target': `#${rightId}`,
})}
${PanelTemplate(rightId, isHorizontal ? 'Right Panel' : 'Bottom Panel', 'This panel will resize automatically when you drag the handle.', 'flex-fill')}
</div>
`)}`;
};
export const Default = {
render: (args) => Template(args),
};
export const ButtonVariant = {
render: (args) => {
var _a, _b, _c;
return Template(Object.assign(Object.assign({}, args), { orientation: (_a = args === null || args === void 0 ? void 0 : args.orientation) !== null && _a !== void 0 ? _a : 'horizontal', size: (_b = args === null || args === void 0 ? void 0 : args.size) !== null && _b !== void 0 ? _b : 'default', density: (_c = args === null || args === void 0 ? void 0 : args.density) !== null && _c !== void 0 ? _c : 'comfortable', type: 'button' }));
},
args: {
type: 'button',
},
parameters: {
docs: {
description: {
story: `
Button type handle with customizable button properties.
**Button Properties Available:**
- \`button-size\`: sm, md, lg
- \`button-color\`: primary, secondary, tertiary, warning, danger
- \`button-variant\`: borderless, filled, outlined
**Keyboard Navigation:**
- Arrow keys: Move 5px per press
- Shift + Arrow keys: Move 15px per press
The button handle provides a more prominent visual indicator compared to the bar type.
`,
},
},
},
};
export const MultipleHandlesNested = {
render: () => {
// prettier-ignore
return html `
<style>${storyStyles}</style>
<div class="handle-demo-container" style="height: 600px;">
${PanelTemplate('panel-one', 'One', 'Large left panel', 'initial-size-400')}
${HandleTemplate({
orientation: 'horizontal',
size: 'default',
density: 'comfortable',
type: 'bar',
'left-target': '#panel-one',
'right-target': '#right-container',
})}
<div id="right-container" class="handle-demo-right-container">
${PanelTemplate('panel-two', 'Two', 'Top right panel', 'initial-height-200')}
${HandleTemplate({
orientation: 'vertical',
size: 'default',
density: 'comfortable',
type: 'bar',
'left-target': '#panel-two',
'right-target': '#panel-three',
})}
${PanelTemplate('panel-three', 'Three', 'Bottom right panel', 'flex-fill')}
</div>
</div>
`;
},
};
export const ShadowDomParent = {
render: (args) => Template(args),
};