mtrl 0.3.3 → 0.3.6
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/package.json +1 -1
- package/src/components/menu/api.ts +143 -268
- package/src/components/menu/config.ts +84 -40
- package/src/components/menu/features/anchor.ts +159 -0
- package/src/components/menu/features/controller.ts +970 -0
- package/src/components/menu/features/index.ts +4 -0
- package/src/components/menu/index.ts +31 -63
- package/src/components/menu/menu.ts +107 -97
- package/src/components/menu/types.ts +263 -447
- package/src/components/segmented-button/config.ts +59 -20
- package/src/components/segmented-button/index.ts +1 -1
- package/src/components/segmented-button/segment.ts +51 -97
- package/src/components/segmented-button/segmented-button.ts +114 -2
- package/src/components/segmented-button/types.ts +52 -0
- package/src/core/compose/features/icon.ts +15 -13
- package/src/core/dom/classes.ts +81 -9
- package/src/core/dom/create.ts +30 -19
- package/src/core/layout/README.md +531 -166
- package/src/core/layout/array.ts +3 -4
- package/src/core/layout/config.ts +193 -0
- package/src/core/layout/create.ts +1 -2
- package/src/core/layout/index.ts +12 -2
- package/src/core/layout/object.ts +2 -3
- package/src/core/layout/processor.ts +60 -12
- package/src/core/layout/result.ts +1 -2
- package/src/core/layout/types.ts +105 -50
- package/src/core/layout/utils.ts +69 -61
- package/src/index.ts +2 -1
- package/src/styles/components/_button.scss +6 -0
- package/src/styles/components/_chip.scss +4 -5
- package/src/styles/components/_menu.scss +20 -8
- package/src/styles/components/_segmented-button.scss +173 -63
- package/src/styles/main.scss +23 -23
- package/src/styles/utilities/_layout.scss +665 -0
- package/src/components/menu/features/items-manager.ts +0 -457
- package/src/components/menu/features/keyboard-navigation.ts +0 -133
- package/src/components/menu/features/positioning.ts +0 -127
- package/src/components/menu/features/visibility.ts +0 -230
- package/src/components/menu/menu-item.ts +0 -86
- package/src/components/menu/utils.ts +0 -67
- /package/src/{core/build → styles/utilities}/_ripple.scss +0 -0
|
@@ -1,26 +1,40 @@
|
|
|
1
|
-
# Layout Module
|
|
2
|
-
|
|
3
|
-
A lightweight, flexible system for creating and managing visual arrangements and component hierarchies.
|
|
1
|
+
# Layout Module Documentation
|
|
4
2
|
|
|
5
3
|
## Overview
|
|
6
4
|
|
|
7
|
-
The Layout Module provides a declarative approach to building UI layouts using either arrays or objects
|
|
5
|
+
The Layout Module is a lightweight, flexible system for creating and managing visual arrangements and component hierarchies. It provides a declarative approach to building UI layouts using either arrays or objects, with efficient DOM operations, component instantiation, and visual arrangement.
|
|
8
6
|
|
|
9
7
|
## Features
|
|
10
8
|
|
|
11
9
|
- **Multiple Schema Formats** - Support for array-based, object-based, and HTML string schemas
|
|
12
10
|
- **Efficient DOM Operations** - Batched DOM manipulations with DocumentFragment
|
|
13
11
|
- **Component Management** - Easy access to component instances via consistent API
|
|
12
|
+
- **Layout System Integration** - Direct access to powerful CSS layout classes
|
|
14
13
|
- **Customizable Creation** - Control class prefixing and specify default creators
|
|
15
14
|
- **Optimized for Bundle Size** - Minimal footprint with maximum functionality
|
|
16
15
|
- **TypeScript Support** - Full type definitions for developer experience
|
|
17
16
|
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install mtrl
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Core Concepts
|
|
24
|
+
|
|
25
|
+
The Layout Module consists of several key parts:
|
|
26
|
+
|
|
27
|
+
1. **Schema Definition** - A declarative way to describe your layout
|
|
28
|
+
2. **Layout Processing** - Converting the schema into DOM elements
|
|
29
|
+
3. **Layout Configuration** - Setting up responsive layouts and grids
|
|
30
|
+
4. **Component Instance Management** - Accessing and controlling created components
|
|
31
|
+
|
|
18
32
|
## Basic Usage
|
|
19
33
|
|
|
20
34
|
### Array-based Layout
|
|
21
35
|
|
|
22
36
|
```javascript
|
|
23
|
-
import { createLayout, createButton, createDialog
|
|
37
|
+
import { createLayout, createButton, createDialog } from 'mtrl';
|
|
24
38
|
|
|
25
39
|
const layout = createLayout([
|
|
26
40
|
// Root level contains primary components
|
|
@@ -34,15 +48,6 @@ const layout = createLayout([
|
|
|
34
48
|
}
|
|
35
49
|
]);
|
|
36
50
|
|
|
37
|
-
// Add content to the dialog separately
|
|
38
|
-
const dialogContent = createLayout([
|
|
39
|
-
createList, 'actionsList', {},
|
|
40
|
-
[
|
|
41
|
-
createListItem, 'confirmAction', { text: 'Confirm', leading: 'check' },
|
|
42
|
-
createListItem, 'cancelAction', { text: 'Cancel', leading: 'close' }
|
|
43
|
-
]
|
|
44
|
-
], layout.get('confirmDialog').contentElement);
|
|
45
|
-
|
|
46
51
|
// Access components
|
|
47
52
|
const submitButton = layout.get('submitButton');
|
|
48
53
|
const confirmDialog = layout.get('confirmDialog');
|
|
@@ -54,7 +59,7 @@ submitButton.on('click', () => confirmDialog.open());
|
|
|
54
59
|
### Object-based Layout
|
|
55
60
|
|
|
56
61
|
```javascript
|
|
57
|
-
import { createLayout, createTopAppBar,
|
|
62
|
+
import { createLayout, createTopAppBar, createList, createListItem } from 'mtrl';
|
|
58
63
|
|
|
59
64
|
const layout = createLayout({
|
|
60
65
|
element: {
|
|
@@ -66,7 +71,16 @@ const layout = createLayout({
|
|
|
66
71
|
children: {
|
|
67
72
|
navigation: {
|
|
68
73
|
creator: createNavigation,
|
|
69
|
-
options: {
|
|
74
|
+
options: {
|
|
75
|
+
variant: 'drawer',
|
|
76
|
+
persistent: true,
|
|
77
|
+
// CSS layout configuration
|
|
78
|
+
layout: {
|
|
79
|
+
type: 'stack',
|
|
80
|
+
gap: 4,
|
|
81
|
+
align: 'stretch'
|
|
82
|
+
}
|
|
83
|
+
},
|
|
70
84
|
children: {
|
|
71
85
|
navList: {
|
|
72
86
|
creator: createList,
|
|
@@ -79,51 +93,33 @@ const layout = createLayout({
|
|
|
79
93
|
settingsLink: {
|
|
80
94
|
creator: createListItem,
|
|
81
95
|
options: { text: 'Settings', leading: 'settings' }
|
|
82
|
-
},
|
|
83
|
-
logoutLink: {
|
|
84
|
-
creator: createListItem,
|
|
85
|
-
options: { text: 'Logout', leading: 'logout' }
|
|
86
96
|
}
|
|
87
97
|
}
|
|
88
98
|
}
|
|
89
99
|
}
|
|
90
100
|
},
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
options: { label: 'Email', type: 'email', required: true }
|
|
102
|
-
},
|
|
103
|
-
saveButton: {
|
|
104
|
-
creator: createButton,
|
|
105
|
-
options: { text: 'Save Changes', variant: 'filled' }
|
|
101
|
+
content: {
|
|
102
|
+
options: {
|
|
103
|
+
tag: 'main',
|
|
104
|
+
className: 'content',
|
|
105
|
+
// Grid layout configuration
|
|
106
|
+
layout: {
|
|
107
|
+
type: 'grid',
|
|
108
|
+
columns: 3,
|
|
109
|
+
gap: 6,
|
|
110
|
+
autoHeight: true
|
|
106
111
|
}
|
|
107
112
|
}
|
|
108
113
|
}
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
});
|
|
112
|
-
|
|
113
|
-
// Access components
|
|
114
|
-
const topAppBar = layout.element;
|
|
115
|
-
const nameField = layout.get('nameField');
|
|
116
|
-
const saveButton = layout.get('saveButton');
|
|
117
|
-
|
|
118
|
-
// Use the components
|
|
119
|
-
nameField.setValue('John Doe');
|
|
120
|
-
saveButton.on('click', () => console.log('Profile updated'));
|
|
121
117
|
```
|
|
122
118
|
|
|
123
119
|
### HTML String Layout
|
|
124
120
|
|
|
125
121
|
```javascript
|
|
126
|
-
import createLayout from '
|
|
122
|
+
import { createLayout } from 'mtrl';
|
|
127
123
|
|
|
128
124
|
const layout = createLayout(`
|
|
129
125
|
<div class="notification">
|
|
@@ -137,173 +133,446 @@ const notification = layout.element;
|
|
|
137
133
|
document.body.appendChild(notification);
|
|
138
134
|
```
|
|
139
135
|
|
|
140
|
-
|
|
136
|
+
## Layout Configuration
|
|
141
137
|
|
|
142
|
-
|
|
143
|
-
import { createLayout, createButton, createTextfield, createCard, createChip, createTopAppBar, createBottomAppBar } from 'mtrl';
|
|
138
|
+
The layout module supports direct integration with the CSS layout system through the `layout` property:
|
|
144
139
|
|
|
145
|
-
|
|
146
|
-
const formLayout = createLayout(
|
|
147
|
-
[
|
|
148
|
-
// Using string keys relies on the default creator
|
|
149
|
-
'nameField', { label: 'Name', required: true },
|
|
150
|
-
'emailField', { label: 'Email', type: 'email', required: true },
|
|
151
|
-
'phoneField', { label: 'Phone', type: 'tel' },
|
|
152
|
-
|
|
153
|
-
// Explicitly override the default creator
|
|
154
|
-
createButton, 'submitButton', { text: 'Submit', variant: 'filled' }
|
|
155
|
-
],
|
|
156
|
-
document.getElementById('form-container'),
|
|
157
|
-
{
|
|
158
|
-
creator: createTextfield, // Default creator for all elements without a specific constructor
|
|
159
|
-
prefix: false // Disable automatic class prefixing
|
|
160
|
-
}
|
|
161
|
-
);
|
|
140
|
+
### Grid Layout
|
|
162
141
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
142
|
+
```javascript
|
|
143
|
+
createLayout({
|
|
144
|
+
gridContainer: {
|
|
145
|
+
options: {
|
|
146
|
+
className: 'container',
|
|
147
|
+
layout: {
|
|
148
|
+
type: 'grid',
|
|
149
|
+
columns: 3, // Number of columns
|
|
150
|
+
gap: 4, // Gap size (using the gap scale)
|
|
151
|
+
autoHeight: true, // Allow natural heights
|
|
152
|
+
dense: true, // Dense packing algorithm
|
|
153
|
+
align: 'center' // Alignment of items
|
|
154
|
+
}
|
|
174
155
|
},
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
156
|
+
children: {
|
|
157
|
+
item1: {
|
|
158
|
+
options: {
|
|
159
|
+
text: 'Item 1',
|
|
160
|
+
// Individual item layout configuration
|
|
161
|
+
layoutItem: {
|
|
162
|
+
span: 2, // Span 2 columns
|
|
163
|
+
rowSpan: 1, // Span 1 row
|
|
164
|
+
align: 'start' // Self-alignment
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Stack Layout (Vertical)
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
createLayout({
|
|
177
|
+
stack: {
|
|
178
|
+
options: {
|
|
179
|
+
layout: {
|
|
180
|
+
type: 'stack',
|
|
181
|
+
gap: 4, // Space between items
|
|
182
|
+
align: 'center', // Center items horizontally
|
|
183
|
+
justify: 'between' // Space between items vertically
|
|
184
|
+
}
|
|
183
185
|
},
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
{ icon: 'search', label: 'Search' },
|
|
189
|
-
{ icon: 'settings', label: 'Settings' }
|
|
190
|
-
]
|
|
186
|
+
children: {
|
|
187
|
+
header: { options: { text: 'Header' } },
|
|
188
|
+
content: { options: { text: 'Content' } },
|
|
189
|
+
footer: { options: { text: 'Footer' } }
|
|
191
190
|
}
|
|
192
|
-
],
|
|
193
|
-
document.getElementById('app'),
|
|
194
|
-
{
|
|
195
|
-
theme: 'dark', // Custom theme option
|
|
196
|
-
density: 'comfortable', // Custom density option
|
|
197
|
-
animations: true // Custom animation option
|
|
198
191
|
}
|
|
199
|
-
);
|
|
192
|
+
});
|
|
193
|
+
```
|
|
200
194
|
|
|
201
|
-
|
|
202
|
-
const nameField = formLayout.get('nameField');
|
|
203
|
-
nameField.setValue('John Doe');
|
|
195
|
+
### Row Layout (Horizontal)
|
|
204
196
|
|
|
205
|
-
|
|
206
|
-
|
|
197
|
+
```javascript
|
|
198
|
+
createLayout({
|
|
199
|
+
row: {
|
|
200
|
+
options: {
|
|
201
|
+
layout: {
|
|
202
|
+
type: 'row',
|
|
203
|
+
gap: 4, // Space between items
|
|
204
|
+
align: 'center', // Center items vertically
|
|
205
|
+
justify: 'between', // Space between items horizontally
|
|
206
|
+
wrap: true, // Allow wrapping
|
|
207
|
+
mobileStack: true // Stack on mobile devices
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
children: {
|
|
211
|
+
// Row items...
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
});
|
|
207
215
|
```
|
|
208
216
|
|
|
209
|
-
##
|
|
217
|
+
## Layout Types
|
|
218
|
+
|
|
219
|
+
The layout system supports several layout types that can be used in the `layout.type` property:
|
|
220
|
+
|
|
221
|
+
| Type | Description | Key Options |
|
|
222
|
+
|------|-------------|------------|
|
|
223
|
+
| `stack` | Vertical column of elements | `align`, `justify`, `gap` |
|
|
224
|
+
| `row` | Horizontal row of elements | `align`, `justify`, `wrap`, `gap`, `mobileStack` |
|
|
225
|
+
| `grid` | CSS Grid-based layout | `columns`, `gap`, `autoHeight`, `dense` |
|
|
226
|
+
| `masonry` | Masonry-style layout | `masonryColumns`, `gap` |
|
|
227
|
+
| `split` | Two-column split layout | `ratio`, `gap` |
|
|
228
|
+
| `sidebar` | Sidebar with main content | `sidebarPosition`, `sidebarWidth` |
|
|
210
229
|
|
|
211
|
-
|
|
230
|
+
## Layout Item Properties
|
|
212
231
|
|
|
213
|
-
|
|
232
|
+
When using the `layoutItem` property to configure individual items:
|
|
233
|
+
|
|
234
|
+
| Property | Description | Example Values |
|
|
235
|
+
|----------|-------------|----------------|
|
|
236
|
+
| `width` | Column width in 12-column grid | `1` through `12` |
|
|
237
|
+
| `span` | Grid column span | `1` through `12` |
|
|
238
|
+
| `rowSpan` | Grid row span | `1` through `12` |
|
|
239
|
+
| `sm`, `md`, `lg`, `xl` | Responsive widths | `1` through `12` |
|
|
240
|
+
| `order` | Item ordering | `'first'`, `'last'`, or a number |
|
|
241
|
+
| `align` | Self-alignment | `'start'`, `'center'`, `'end'`, `'stretch'` |
|
|
242
|
+
| `auto` | Auto width (flex) | `true`, `false` |
|
|
243
|
+
|
|
244
|
+
## Layout Functions
|
|
245
|
+
|
|
246
|
+
### `createLayout(schema, parentElement?, options?)`
|
|
214
247
|
|
|
215
248
|
Creates a layout from a schema definition.
|
|
216
249
|
|
|
217
250
|
- **Parameters**:
|
|
218
251
|
- `schema`: Array, object, HTML string, or function returning one of these
|
|
219
252
|
- `parentElement` (optional): Parent element to attach the layout to
|
|
220
|
-
- `options` (optional): Configuration options for layout creation
|
|
221
|
-
- `creator`: Default creator function to use when not specified in schema
|
|
222
|
-
- `prefix`: Boolean to control whether CSS class prefixing is applied (default: true)
|
|
223
|
-
- Custom options can be added and accessed in component creators
|
|
253
|
+
- `options` (optional): Configuration options for layout creation
|
|
224
254
|
- **Returns**: Layout result object with components and utility methods
|
|
225
255
|
|
|
226
|
-
|
|
256
|
+
```javascript
|
|
257
|
+
const layout = createLayout(schema, document.getElementById('container'), {
|
|
258
|
+
creator: createCard, // Default creator for elements without a specific one
|
|
259
|
+
prefix: true, // Whether to apply automatic class prefixing
|
|
260
|
+
theme: 'dark' // Custom options (passed to components)
|
|
261
|
+
});
|
|
262
|
+
```
|
|
227
263
|
|
|
228
|
-
|
|
264
|
+
### Layout Result Object
|
|
229
265
|
|
|
230
|
-
|
|
231
|
-
- `schema`: Array or object schema
|
|
232
|
-
- `parentElement` (optional): Parent element to attach to
|
|
233
|
-
- `level` (optional): Current recursion level
|
|
234
|
-
- `options` (optional): Layout creation options
|
|
235
|
-
- **Returns**: Layout result object
|
|
266
|
+
The object returned by `createLayout` contains:
|
|
236
267
|
|
|
237
|
-
|
|
268
|
+
- `layout`: Raw layout object with all components
|
|
269
|
+
- `element`: Reference to the root element
|
|
270
|
+
- `component`: Flattened component map for easy access
|
|
271
|
+
- `get(name)`: Function to get a component by name
|
|
272
|
+
- `getAll()`: Function to get all components
|
|
273
|
+
- `destroy()`: Function to clean up the layout
|
|
238
274
|
|
|
239
|
-
|
|
275
|
+
```javascript
|
|
276
|
+
// Access components in different ways
|
|
277
|
+
const header = layout.get('header'); // By name
|
|
278
|
+
const footer = layout.component.footer; // Via flattened map
|
|
279
|
+
const rootElement = layout.element; // Root element
|
|
280
|
+
```
|
|
240
281
|
|
|
241
|
-
|
|
242
|
-
- `Component`: Constructor or factory function
|
|
243
|
-
- `options` (optional): Options to pass to the component
|
|
244
|
-
- `layoutOptions` (optional): Global layout options
|
|
245
|
-
- **Returns**: Component instance
|
|
282
|
+
## Examples
|
|
246
283
|
|
|
247
|
-
###
|
|
284
|
+
### Array Schema Examples
|
|
248
285
|
|
|
249
|
-
####
|
|
286
|
+
#### Grid Layout with Array Schema
|
|
250
287
|
|
|
251
|
-
|
|
288
|
+
```javascript
|
|
289
|
+
import { createLayout, createElement, createCard } from 'mtrl';
|
|
290
|
+
|
|
291
|
+
// Create a grid layout using array syntax
|
|
292
|
+
const dashboard = createLayout([
|
|
293
|
+
// Container element with layout configuration
|
|
294
|
+
'dashboardGrid', {
|
|
295
|
+
className: 'dashboard-grid',
|
|
296
|
+
layout: {
|
|
297
|
+
type: 'grid',
|
|
298
|
+
columns: 3,
|
|
299
|
+
gap: 4,
|
|
300
|
+
autoHeight: true
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
[
|
|
304
|
+
// First card
|
|
305
|
+
createCard, 'statsCard', {
|
|
306
|
+
title: 'Statistics',
|
|
307
|
+
outlined: true,
|
|
308
|
+
layoutItem: {
|
|
309
|
+
span: 2, // Span 2 columns
|
|
310
|
+
sm: 12, // Full width on small screens
|
|
311
|
+
md: 6 // Half width on medium screens
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
// Second card
|
|
315
|
+
createCard, 'activityCard', {
|
|
316
|
+
title: 'Recent Activity',
|
|
317
|
+
outlined: true,
|
|
318
|
+
layoutItem: {
|
|
319
|
+
span: 1, // Span 1 column
|
|
320
|
+
sm: 12, // Full width on small screens
|
|
321
|
+
md: 6 // Half width on medium screens
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
// Third card
|
|
325
|
+
createCard, 'revenueCard', {
|
|
326
|
+
title: 'Revenue',
|
|
327
|
+
outlined: true,
|
|
328
|
+
layoutItem: {
|
|
329
|
+
span: 3, // Full width
|
|
330
|
+
md: 6 // Half width on medium screens
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
]
|
|
334
|
+
]);
|
|
252
335
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
336
|
+
// Access components
|
|
337
|
+
const statsCard = dashboard.get('statsCard');
|
|
338
|
+
statsCard.update({ content: 'Updated statistics data' });
|
|
339
|
+
```
|
|
256
340
|
|
|
257
|
-
####
|
|
341
|
+
#### Application Layout with Array Schema
|
|
258
342
|
|
|
259
|
-
|
|
343
|
+
```javascript
|
|
344
|
+
import { createLayout, createTopAppBar, createDrawer, createList, createListItem, createElement } from 'mtrl';
|
|
260
345
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
346
|
+
// Create an application layout using array syntax
|
|
347
|
+
const appLayout = createLayout([
|
|
348
|
+
// Create a container element
|
|
349
|
+
'appContainer', {
|
|
350
|
+
className: 'app-container',
|
|
351
|
+
layout: { type: 'stack', gap: 0 }
|
|
352
|
+
},
|
|
353
|
+
[
|
|
354
|
+
// Header
|
|
355
|
+
createTopAppBar, 'header', {
|
|
356
|
+
title: 'My Application',
|
|
357
|
+
actions: ['menu', 'account']
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
// Main content area
|
|
361
|
+
'main', {
|
|
362
|
+
className: 'app-main',
|
|
363
|
+
layout: { type: 'row', gap: 0 }
|
|
364
|
+
},
|
|
365
|
+
[
|
|
366
|
+
// Sidebar
|
|
367
|
+
createDrawer, 'sidebar', {
|
|
368
|
+
persistent: true,
|
|
369
|
+
layout: { type: 'stack', gap: 2 }
|
|
370
|
+
},
|
|
371
|
+
[
|
|
372
|
+
// Navigation list
|
|
373
|
+
createList, 'nav', { interactive: true },
|
|
374
|
+
[
|
|
375
|
+
createListItem, 'homeLink', { text: 'Home', leading: 'home' },
|
|
376
|
+
createListItem, 'settingsLink', { text: 'Settings', leading: 'settings' }
|
|
377
|
+
]
|
|
378
|
+
],
|
|
379
|
+
|
|
380
|
+
// Main content
|
|
381
|
+
'content', {
|
|
382
|
+
tag: 'main',
|
|
383
|
+
className: 'app-content',
|
|
384
|
+
layout: {
|
|
385
|
+
type: 'grid',
|
|
386
|
+
columns: 'auto-fit',
|
|
387
|
+
gap: 4
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
]
|
|
391
|
+
]
|
|
392
|
+
]);
|
|
265
393
|
|
|
266
|
-
|
|
394
|
+
// Access and modify components
|
|
395
|
+
const header = appLayout.get('header');
|
|
396
|
+
header.setTitle('Dashboard');
|
|
267
397
|
|
|
268
|
-
|
|
398
|
+
// Add items to the grid content area
|
|
399
|
+
const content = appLayout.get('content');
|
|
400
|
+
const card = createCard({ title: 'Statistics', content: 'App usage data...' });
|
|
401
|
+
content.appendChild(card.element);
|
|
402
|
+
```
|
|
269
403
|
|
|
270
|
-
|
|
271
|
-
- `layout`: Layout object to flatten
|
|
272
|
-
- **Returns**: Flattened layout with components
|
|
404
|
+
#### Form Layout with Array Schema
|
|
273
405
|
|
|
274
|
-
|
|
406
|
+
```javascript
|
|
407
|
+
import { createLayout, createTextfield, createButton } from 'mtrl';
|
|
408
|
+
|
|
409
|
+
// Create a form with fields and submit button using array syntax
|
|
410
|
+
const form = createLayout([
|
|
411
|
+
'formContainer', {
|
|
412
|
+
tag: 'form',
|
|
413
|
+
className: 'login-form',
|
|
414
|
+
layout: { type: 'stack', gap: 4 }
|
|
415
|
+
},
|
|
416
|
+
[
|
|
417
|
+
createTextfield, 'username', {
|
|
418
|
+
label: 'Username',
|
|
419
|
+
required: true,
|
|
420
|
+
layoutItem: {
|
|
421
|
+
width: 12 // Full width
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
createTextfield, 'password', {
|
|
425
|
+
label: 'Password',
|
|
426
|
+
type: 'password',
|
|
427
|
+
required: true,
|
|
428
|
+
layoutItem: {
|
|
429
|
+
width: 12 // Full width
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
'buttonRow', {
|
|
433
|
+
layout: {
|
|
434
|
+
type: 'row',
|
|
435
|
+
justify: 'end',
|
|
436
|
+
gap: 2
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
[
|
|
440
|
+
createButton, 'resetButton', {
|
|
441
|
+
text: 'Reset',
|
|
442
|
+
variant: 'text'
|
|
443
|
+
},
|
|
444
|
+
createButton, 'submitButton', {
|
|
445
|
+
text: 'Login',
|
|
446
|
+
variant: 'filled'
|
|
447
|
+
}
|
|
448
|
+
]
|
|
449
|
+
]
|
|
450
|
+
]);
|
|
275
451
|
|
|
276
|
-
|
|
452
|
+
// Access form elements
|
|
453
|
+
const usernameField = form.get('username');
|
|
454
|
+
const submitButton = form.get('submitButton');
|
|
277
455
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
456
|
+
// Add event handlers
|
|
457
|
+
submitButton.on('click', (e) => {
|
|
458
|
+
e.preventDefault();
|
|
459
|
+
console.log('Username:', usernameField.getValue());
|
|
460
|
+
});
|
|
461
|
+
```
|
|
284
462
|
|
|
285
|
-
|
|
463
|
+
### Object Schema Examples
|
|
286
464
|
|
|
287
|
-
|
|
465
|
+
#### Dashboard Grid with Object Schema
|
|
288
466
|
|
|
289
467
|
```javascript
|
|
290
|
-
import createLayout from '
|
|
291
|
-
|
|
468
|
+
import { createLayout, createElement, createCard } from 'mtrl';
|
|
469
|
+
|
|
470
|
+
const dashboard = createLayout({
|
|
471
|
+
dashboardGrid: {
|
|
472
|
+
options: {
|
|
473
|
+
className: 'dashboard-grid',
|
|
474
|
+
layout: {
|
|
475
|
+
type: 'grid',
|
|
476
|
+
columns: 3,
|
|
477
|
+
gap: 4,
|
|
478
|
+
autoHeight: true
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
children: {
|
|
482
|
+
statsCard: {
|
|
483
|
+
creator: createCard,
|
|
484
|
+
options: {
|
|
485
|
+
title: 'Statistics',
|
|
486
|
+
outlined: true,
|
|
487
|
+
layoutItem: {
|
|
488
|
+
span: 2, // Span 2 columns
|
|
489
|
+
sm: 12, // Full width on small screens
|
|
490
|
+
md: 6 // Half width on medium screens
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
},
|
|
494
|
+
activityCard: {
|
|
495
|
+
creator: createCard,
|
|
496
|
+
options: {
|
|
497
|
+
title: 'Recent Activity',
|
|
498
|
+
outlined: true,
|
|
499
|
+
layoutItem: {
|
|
500
|
+
span: 1, // Span 1 column
|
|
501
|
+
sm: 12, // Full width on small screens
|
|
502
|
+
md: 6 // Half width on medium screens
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
// More dashboard cards...
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
```
|
|
292
511
|
|
|
293
|
-
|
|
294
|
-
const appLayout = createLayout([
|
|
295
|
-
// Application components...
|
|
296
|
-
]);
|
|
512
|
+
#### Application Layout with Object Schema
|
|
297
513
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
layout: appLayout.layout,
|
|
301
|
-
layoutAPI: appLayout
|
|
302
|
-
});
|
|
514
|
+
```javascript
|
|
515
|
+
import { createLayout, createTopAppBar, createDrawer, createList, createListItem, createButton } from 'mtrl';
|
|
303
516
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
517
|
+
const appLayout = createLayout({
|
|
518
|
+
app: {
|
|
519
|
+
options: {
|
|
520
|
+
className: 'app-container',
|
|
521
|
+
layout: { type: 'stack', gap: 0 }
|
|
522
|
+
},
|
|
523
|
+
children: {
|
|
524
|
+
header: {
|
|
525
|
+
creator: createTopAppBar,
|
|
526
|
+
options: {
|
|
527
|
+
title: 'My Application',
|
|
528
|
+
actions: ['menu', 'account']
|
|
529
|
+
}
|
|
530
|
+
},
|
|
531
|
+
main: {
|
|
532
|
+
options: {
|
|
533
|
+
className: 'app-main',
|
|
534
|
+
layout: { type: 'row', gap: 0 }
|
|
535
|
+
},
|
|
536
|
+
children: {
|
|
537
|
+
sidebar: {
|
|
538
|
+
creator: createDrawer,
|
|
539
|
+
options: {
|
|
540
|
+
persistent: true,
|
|
541
|
+
layout: { type: 'stack', gap: 2 }
|
|
542
|
+
},
|
|
543
|
+
children: {
|
|
544
|
+
nav: {
|
|
545
|
+
creator: createList,
|
|
546
|
+
options: { interactive: true },
|
|
547
|
+
children: {
|
|
548
|
+
home: {
|
|
549
|
+
creator: createListItem,
|
|
550
|
+
options: { text: 'Home', leading: 'home' }
|
|
551
|
+
},
|
|
552
|
+
settings: {
|
|
553
|
+
creator: createListItem,
|
|
554
|
+
options: { text: 'Settings', leading: 'settings' }
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
content: {
|
|
561
|
+
options: {
|
|
562
|
+
tag: 'main',
|
|
563
|
+
className: 'app-content',
|
|
564
|
+
layout: {
|
|
565
|
+
type: 'grid',
|
|
566
|
+
columns: 'auto-fit',
|
|
567
|
+
gap: 4
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
});
|
|
307
576
|
```
|
|
308
577
|
|
|
309
578
|
## Performance Considerations
|
|
@@ -341,6 +610,102 @@ layoutManager.setPageTitle('Dashboard');
|
|
|
341
610
|
- Consider memoizing frequently created layouts
|
|
342
611
|
- For large applications, lazy-load secondary layouts
|
|
343
612
|
|
|
613
|
+
## Responsive Design
|
|
614
|
+
|
|
615
|
+
The layout system provides several ways to create responsive designs:
|
|
616
|
+
|
|
617
|
+
### Responsive Grid
|
|
618
|
+
|
|
619
|
+
```javascript
|
|
620
|
+
createLayout({
|
|
621
|
+
grid: {
|
|
622
|
+
options: {
|
|
623
|
+
layout: {
|
|
624
|
+
type: 'grid',
|
|
625
|
+
// Different columns at different breakpoints using CSS media queries
|
|
626
|
+
class: 'md:layout--grid-cols-2 lg:layout--grid-cols-3 xl:layout--grid-cols-4'
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### Layout Items with Responsive Widths
|
|
634
|
+
|
|
635
|
+
```javascript
|
|
636
|
+
createLayout({
|
|
637
|
+
row: {
|
|
638
|
+
options: {
|
|
639
|
+
layout: { type: 'row', gap: 4 }
|
|
640
|
+
},
|
|
641
|
+
children: {
|
|
642
|
+
sidebar: {
|
|
643
|
+
options: {
|
|
644
|
+
layoutItem: {
|
|
645
|
+
width: 3, // Default: 3/12 (25%)
|
|
646
|
+
sm: 12, // Small screens: 12/12 (100%)
|
|
647
|
+
md: 4, // Medium screens: 4/12 (33.3%)
|
|
648
|
+
lg: 3 // Large screens: 3/12 (25%)
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
},
|
|
652
|
+
main: {
|
|
653
|
+
options: {
|
|
654
|
+
layoutItem: {
|
|
655
|
+
width: 9, // Default: 9/12 (75%)
|
|
656
|
+
sm: 12, // Small screens: 12/12 (100%)
|
|
657
|
+
md: 8, // Medium screens: 8/12 (66.6%)
|
|
658
|
+
lg: 9 // Large screens: 9/12 (75%)
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
### Mobile Behavior Options
|
|
668
|
+
|
|
669
|
+
```javascript
|
|
670
|
+
createLayout({
|
|
671
|
+
row: {
|
|
672
|
+
options: {
|
|
673
|
+
layout: {
|
|
674
|
+
type: 'row',
|
|
675
|
+
gap: 4,
|
|
676
|
+
mobileStack: true, // Stack on mobile instead of row
|
|
677
|
+
// OR
|
|
678
|
+
mobileScroll: true // Enable horizontal scrolling on mobile
|
|
679
|
+
}
|
|
680
|
+
},
|
|
681
|
+
children: {
|
|
682
|
+
// Row items...
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
## Layout CSS Classes
|
|
689
|
+
|
|
690
|
+
The layout system uses a consistent naming convention for CSS classes:
|
|
691
|
+
|
|
692
|
+
### Layout Container Classes
|
|
693
|
+
|
|
694
|
+
- **Base Layout**: `.layout--[type]` (e.g., `.layout--stack`, `.layout--grid`)
|
|
695
|
+
- **Alignment**: `.layout--[type]-[align]` (e.g., `.layout--stack-center`)
|
|
696
|
+
- **Justification**: `.layout--[type]-justify-[justify]` (e.g., `.layout--row-justify-between`)
|
|
697
|
+
- **Spacing**: `.layout--[type]-gap-[size]` (e.g., `.layout--grid-gap-4`)
|
|
698
|
+
- **Specific Options**: `.layout--[type]-[option]` (e.g., `.layout--grid-dense`)
|
|
699
|
+
|
|
700
|
+
### Layout Item Classes
|
|
701
|
+
|
|
702
|
+
- **Base Item**: `.layout__item`
|
|
703
|
+
- **Width**: `.layout__item--[width]` (e.g., `.layout__item--4` for 4/12 width)
|
|
704
|
+
- **Responsive Widths**: `.layout__item--[breakpoint]-[width]` (e.g., `.layout__item--md-6`)
|
|
705
|
+
- **Ordering**: `.layout__item--order-[order]` (e.g., `.layout__item--order-first`)
|
|
706
|
+
- **Alignment**: `.layout__item--self-[align]` (e.g., `.layout__item--self-center`)
|
|
707
|
+
- **Grid Span**: `.layout__item--span-[span]` (e.g., `.layout__item--span-2`)
|
|
708
|
+
|
|
344
709
|
## Browser Compatibility
|
|
345
710
|
|
|
346
711
|
The Layout Module is compatible with all modern browsers (Chrome, Firefox, Safari, Edge).
|