@boostdev/design-system-components 2.1.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -1
- package/README.md +40 -0
- package/dist/client.cjs +308 -60
- package/dist/client.css +568 -527
- package/dist/client.d.cts +39 -1
- package/dist/client.d.ts +39 -1
- package/dist/client.js +314 -60
- package/dist/index.cjs +308 -60
- package/dist/index.css +568 -527
- package/dist/index.d.cts +39 -1
- package/dist/index.d.ts +39 -1
- package/dist/index.js +314 -60
- package/dist/web-components/index.d.ts +129 -1
- package/dist/web-components/index.js +313 -0
- package/package.json +1 -1
- package/src/components/layout/Grid/Grid.mdx +244 -0
- package/src/components/layout/Grid/Grid.module.css +59 -0
- package/src/components/layout/Grid/Grid.spec.tsx +415 -0
- package/src/components/layout/Grid/Grid.stories.tsx +160 -0
- package/src/components/layout/Grid/Grid.tsx +92 -0
- package/src/components/layout/Grid/GridItem.tsx +150 -0
- package/src/components/layout/Grid/autoSpan.ts +77 -0
- package/src/components/layout/Grid/index.ts +4 -0
- package/src/components/layout/Grid/masonry.ts +139 -0
- package/src/index.ts +2 -0
- package/src/web-components/index.ts +4 -0
- package/src/web-components/layout/BdsGrid.mdx +210 -0
- package/src/web-components/layout/BdsGrid.stories.tsx +209 -0
- package/src/web-components/layout/BdsGridItem.mdx +52 -0
- package/src/web-components/layout/BdsGridItem.stories.tsx +72 -0
- package/src/web-components/layout/bds-grid-item.spec.ts +102 -0
- package/src/web-components/layout/bds-grid-item.ts +177 -0
- package/src/web-components/layout/bds-grid.spec.ts +62 -0
- package/src/web-components/layout/bds-grid.ts +184 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { LitElement, css, html } from 'lit';
|
|
2
|
+
import { applyMasonryLayout, clearMasonryLayout, supportsNativeMasonry } from '../../components/layout/Grid/masonry';
|
|
3
|
+
|
|
4
|
+
export type GridVariant = 'main' | 'page' | 'funnel' | 'custom';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `<bds-grid>` — framework-agnostic Grid layout custom element.
|
|
8
|
+
*
|
|
9
|
+
* Attributes:
|
|
10
|
+
* variant — "main" (default) | "page" | "funnel" | "custom"
|
|
11
|
+
* columns — number; column count when variant="custom"
|
|
12
|
+
* is-centered — boolean; centers the grid and caps width via --bds-container_max-width
|
|
13
|
+
* is-masonry — boolean; enables masonry layout per CSS Grid Level 3.
|
|
14
|
+
* Uses native `display: grid-lanes` / `grid-template-rows: masonry`
|
|
15
|
+
* when supported, otherwise runs a JS polyfill.
|
|
16
|
+
* auto-span-media — boolean; child `<bds-grid-item>`s without a `column-span`
|
|
17
|
+
* attribute resolve their span from the intrinsic aspect
|
|
18
|
+
* ratio of their first `<img>`/`<video>` child.
|
|
19
|
+
*
|
|
20
|
+
* Slots:
|
|
21
|
+
* (default) — grid content; typically `<bds-grid-item>` children
|
|
22
|
+
*/
|
|
23
|
+
export class BdsGrid extends LitElement {
|
|
24
|
+
static styles = css`
|
|
25
|
+
:host {
|
|
26
|
+
display: block;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.grid {
|
|
30
|
+
display: grid;
|
|
31
|
+
gap: var(--grid_gap, var(--bds-grid_gap));
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.grid.--main {
|
|
36
|
+
grid-template-columns: var(--bds-grid_template-columns);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.grid.--page {
|
|
40
|
+
grid-template-columns: 1fr;
|
|
41
|
+
grid-column: 1 / -1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.grid.--funnel {
|
|
45
|
+
grid-template-columns: var(--bds-grid_template-columns);
|
|
46
|
+
max-inline-size: var(--bds-container_max-width--narrow);
|
|
47
|
+
margin-inline: auto;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.grid.--custom {
|
|
51
|
+
grid-template-columns: repeat(var(--grid_columns, 4), minmax(0, 1fr));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.grid.--centered {
|
|
55
|
+
margin-inline: auto;
|
|
56
|
+
max-inline-size: var(--bds-container_max-width);
|
|
57
|
+
padding-inline: var(--bds-container_spacing-inline);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@supports (grid-template-rows: masonry) {
|
|
61
|
+
.grid.--masonry {
|
|
62
|
+
grid-template-rows: masonry;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@supports (display: grid-lanes) {
|
|
67
|
+
.grid.--masonry {
|
|
68
|
+
display: grid-lanes;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
static properties = {
|
|
74
|
+
variant: { type: String, reflect: true },
|
|
75
|
+
columns: { type: Number, reflect: true },
|
|
76
|
+
isCentered: { type: Boolean, attribute: 'is-centered', reflect: true },
|
|
77
|
+
isMasonry: { type: Boolean, attribute: 'is-masonry', reflect: true },
|
|
78
|
+
autoSpanMedia: { type: Boolean, attribute: 'auto-span-media', reflect: true },
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
declare variant: GridVariant;
|
|
82
|
+
declare columns: number | undefined;
|
|
83
|
+
declare isCentered: boolean;
|
|
84
|
+
declare isMasonry: boolean;
|
|
85
|
+
declare autoSpanMedia: boolean;
|
|
86
|
+
|
|
87
|
+
private _ro?: ResizeObserver;
|
|
88
|
+
private _mo?: MutationObserver;
|
|
89
|
+
private _frame = 0;
|
|
90
|
+
|
|
91
|
+
constructor() {
|
|
92
|
+
super();
|
|
93
|
+
this.variant = 'main';
|
|
94
|
+
this.columns = undefined;
|
|
95
|
+
this.isCentered = false;
|
|
96
|
+
this.isMasonry = false;
|
|
97
|
+
this.autoSpanMedia = false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
disconnectedCallback() {
|
|
101
|
+
super.disconnectedCallback();
|
|
102
|
+
this._teardownMasonry();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
updated() {
|
|
106
|
+
if (this.isMasonry && !supportsNativeMasonry()) {
|
|
107
|
+
this._setupMasonry();
|
|
108
|
+
this._scheduleMasonry();
|
|
109
|
+
} else {
|
|
110
|
+
this._teardownMasonry();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private _gridEl(): HTMLElement | null {
|
|
115
|
+
return this.renderRoot.querySelector<HTMLElement>('.grid');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private _items(): HTMLElement[] {
|
|
119
|
+
return (Array.from(this.children) as HTMLElement[]).filter((el) => el.nodeType === 1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private _setupMasonry() {
|
|
123
|
+
if (this._ro || this._mo) return;
|
|
124
|
+
const container = this._gridEl();
|
|
125
|
+
if (!container) return;
|
|
126
|
+
|
|
127
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
128
|
+
this._ro = new ResizeObserver(() => this._scheduleMasonry());
|
|
129
|
+
// Only observe children, not the container — container block-size changes when
|
|
130
|
+
// we apply row-spans, which would loop back through the observer.
|
|
131
|
+
for (const child of this._items()) this._ro.observe(child);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
135
|
+
this._mo = new MutationObserver(() => {
|
|
136
|
+
if (this._ro) for (const child of this._items()) this._ro.observe(child);
|
|
137
|
+
this._scheduleMasonry();
|
|
138
|
+
});
|
|
139
|
+
this._mo.observe(this, { childList: true });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private _scheduleMasonry() {
|
|
144
|
+
cancelAnimationFrame(this._frame);
|
|
145
|
+
this._frame = requestAnimationFrame(() => {
|
|
146
|
+
const container = this._gridEl();
|
|
147
|
+
if (container) applyMasonryLayout(container, this._items());
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private _teardownMasonry() {
|
|
152
|
+
cancelAnimationFrame(this._frame);
|
|
153
|
+
this._ro?.disconnect();
|
|
154
|
+
this._mo?.disconnect();
|
|
155
|
+
this._ro = undefined;
|
|
156
|
+
this._mo = undefined;
|
|
157
|
+
const container = this._gridEl();
|
|
158
|
+
if (container) clearMasonryLayout(container, this._items());
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
render() {
|
|
162
|
+
const classes = [
|
|
163
|
+
'grid',
|
|
164
|
+
`--${this.variant}`,
|
|
165
|
+
this.isCentered ? '--centered' : '',
|
|
166
|
+
this.isMasonry ? '--masonry' : '',
|
|
167
|
+
].filter(Boolean).join(' ');
|
|
168
|
+
|
|
169
|
+
const styleAttr =
|
|
170
|
+
this.variant === 'custom' && this.columns !== undefined
|
|
171
|
+
? `--grid_columns: ${this.columns}`
|
|
172
|
+
: '';
|
|
173
|
+
|
|
174
|
+
return html`<div class=${classes} style=${styleAttr}><slot></slot></div>`;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
customElements.define('bds-grid', BdsGrid);
|
|
179
|
+
|
|
180
|
+
declare global {
|
|
181
|
+
interface HTMLElementTagNameMap {
|
|
182
|
+
'bds-grid': BdsGrid;
|
|
183
|
+
}
|
|
184
|
+
}
|