Skip to content

Commit 593705e

Browse files
asynclizcopybara-github
authored andcommitted
feat(labs): add divider utility class component
PiperOrigin-RevId: 897885920
1 parent f077e45 commit 593705e

6 files changed

Lines changed: 267 additions & 0 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//
2+
// Copyright 2026 Google LLC
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
6+
@mixin root {
7+
--color: var(--md-sys-color-outline-variant);
8+
--thickness: 1px;
9+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @license
3+
* Copyright 2026 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import './material-collection.js';
8+
import './index.js';
9+
10+
import {
11+
KnobTypesToKnobs,
12+
MaterialCollection,
13+
materialInitsToStoryInits,
14+
setUpDemo,
15+
} from './material-collection.js';
16+
17+
import {stories, StoryKnobs} from './stories.js';
18+
19+
const collection = new MaterialCollection<KnobTypesToKnobs<StoryKnobs>>(
20+
'Divider',
21+
);
22+
23+
collection.addStories(...materialInitsToStoryInits(stories));
24+
25+
setUpDemo(collection);
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* @license
3+
* Copyright 2026 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import '@material/web/labs/gb/components/divider/md-divider.js';
8+
9+
import {MaterialStoryInit} from './material-collection.js';
10+
import {divider} from '@material/web/labs/gb/components/divider/divider.js';
11+
import {styles as dividerStyles} from '@material/web/labs/gb/components/divider/divider.cssresult.js';
12+
import {adoptStyles} from '@material/web/labs/gb/styles/adopt-styles.js';
13+
import {styles as m3Styles} from '@material/web/labs/gb/styles/m3.cssresult.js';
14+
import {css, html} from 'lit';
15+
16+
/** Knob types for divider stories. */
17+
export interface StoryKnobs {}
18+
19+
adoptStyles(document, [m3Styles]);
20+
21+
const styles = css`
22+
.column,
23+
.row {
24+
display: flex;
25+
gap: 8px;
26+
margin: 16px;
27+
}
28+
.column {
29+
flex-direction: column;
30+
}
31+
.row {
32+
flex-direction: row;
33+
}
34+
`;
35+
36+
const playground: MaterialStoryInit<StoryKnobs> = {
37+
name: 'Playground',
38+
styles,
39+
render(knobs) {
40+
return html`
41+
<div class="column">
42+
<div>Vertical</div>
43+
<md-divider></md-divider>
44+
<div>Items</div>
45+
</div>
46+
47+
<div class="row">
48+
<div>Horizontal</div>
49+
<md-divider vertical></md-divider>
50+
<div>Items</div>
51+
</div>
52+
`;
53+
},
54+
};
55+
56+
const directive: MaterialStoryInit<StoryKnobs> = {
57+
name: 'Directive',
58+
styles: [styles, dividerStyles],
59+
render(knobs) {
60+
return html`
61+
<div class="column">
62+
<div>Vertical</div>
63+
<hr class="${divider()}" />
64+
<div>Items</div>
65+
</div>
66+
67+
<div class="row">
68+
<div>Horizontal</div>
69+
<hr class="${divider({vertical: true})}" />
70+
<div>Items</div>
71+
</div>
72+
`;
73+
},
74+
};
75+
76+
/** Divider stories. */
77+
export const stories = [playground, directive];
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*!
2+
* Copyright 2026 Google LLC
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
// go/keep-sorted start by_regex='(.+) prefix_order=sass:
7+
@use 'divider-tokens';
8+
// go/keep-sorted end
9+
10+
@layer md.sys;
11+
@layer md.comp.divider {
12+
.divider {
13+
& {
14+
@include divider-tokens.root;
15+
16+
box-sizing: border-box;
17+
border: none;
18+
margin: unset; // Remove <hr> margins
19+
}
20+
21+
&:not(.divider-vertical) {
22+
border-bottom: var(--thickness) solid var(--color);
23+
width: 100%;
24+
}
25+
26+
&.divider-vertical {
27+
border-inline-end: var(--thickness) solid var(--color);
28+
min-height: 100%;
29+
}
30+
}
31+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* @license
3+
* Copyright 2026 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import {Directive, directive} from 'lit/directive.js';
8+
import {classMap, type ClassInfo} from 'lit/directives/class-map.js';
9+
10+
/** Divider classes. */
11+
export const DIVIDER_CLASSES = {
12+
divider: 'divider',
13+
dividerVertical: 'divider-vertical',
14+
} as const;
15+
16+
/** The state provided to the `dividerClasses()` function. */
17+
export interface DividerClassesState {
18+
/** Whether the divider is vertical. */
19+
vertical?: boolean;
20+
}
21+
22+
/**
23+
* Returns the divider classes to apply to an element based on the given state.
24+
*
25+
* @param state The state of the divider.
26+
* @return An object of class names and truthy values if they apply.
27+
*/
28+
export function dividerClasses({
29+
vertical = false,
30+
}: DividerClassesState = {}): ClassInfo {
31+
return {
32+
[DIVIDER_CLASSES.divider]: true,
33+
[DIVIDER_CLASSES.dividerVertical]: vertical,
34+
};
35+
}
36+
37+
/** The state provided to the `divider()` directive. */
38+
export interface DividerDirectiveState extends DividerClassesState {
39+
/** Additional classes to apply to the element. */
40+
classes?: ClassInfo;
41+
}
42+
43+
class DividerDirective extends Directive {
44+
render(state: DividerDirectiveState = {}) {
45+
return classMap({
46+
...(state.classes || {}),
47+
...dividerClasses(state),
48+
});
49+
}
50+
}
51+
52+
/**
53+
* A Lit directive that adds divider styling to its element.
54+
*
55+
* @example
56+
* ```ts
57+
* html`
58+
* <div class="flex flex-col">
59+
* <div>Vertical</div>
60+
* <hr class="${divider()}">
61+
* <div>Items</div>
62+
* </div>
63+
*
64+
* <div class="flex flex-row">
65+
* <div>Horizontal</div>
66+
* <hr class="${divider({vertical: true})}">
67+
* <div>Items</div>
68+
* </div>
69+
* `;
70+
* ```
71+
*/
72+
export const divider = directive(DividerDirective);
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @license
3+
* Copyright 2026 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import {css, CSSResultOrNative, html, LitElement} from 'lit';
8+
import {customElement, property} from 'lit/decorators.js';
9+
10+
import dividerStyles from './divider.css' with {type: 'css'}; // github-only
11+
// import {styles as dividerStyles} from './divider.cssresult.js'; // google3-only
12+
13+
import {divider} from './divider.js';
14+
15+
declare global {
16+
interface HTMLElementTagNameMap {
17+
/** A Material Design divider component. */
18+
'md-divider': Divider;
19+
}
20+
}
21+
22+
/**
23+
* A Material Design divider component.
24+
*/
25+
@customElement('md-divider')
26+
export class Divider extends LitElement {
27+
static override styles: CSSResultOrNative[] = [
28+
dividerStyles,
29+
css`
30+
:host {
31+
display: flex;
32+
}
33+
.divider {
34+
flex: 1;
35+
}
36+
:host(:not([vertical])) {
37+
width: 100%;
38+
}
39+
:host([vertical]) {
40+
min-height: 100%;
41+
}
42+
`,
43+
];
44+
45+
/**
46+
* Whether or not the divider is vertical.
47+
*/
48+
@property({type: Boolean, reflect: true}) vertical = false;
49+
50+
protected override render() {
51+
return html`<div part="divider" class="${divider(this)}"></div>`;
52+
}
53+
}

0 commit comments

Comments
 (0)