@mmlogic/components 0.1.9 → 0.1.11
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/README.md +196 -61
- package/dist/cjs/format-DBr-GTvS.js +308 -0
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/mosterdcomponents.cjs.js +1 -1
- package/dist/cjs/mrd-boolean-field_16.cjs.entry.js +108 -117
- package/dist/cjs/mrd-table.cjs.entry.js +318 -62
- package/dist/collection/components/mrd-field/mrd-field.js +26 -2
- package/dist/collection/components/mrd-file-field/mrd-file-field.js +70 -2
- package/dist/collection/components/mrd-file-field/mrd-file-field.scss +13 -0
- package/dist/collection/components/mrd-form/mrd-form.js +28 -1
- package/dist/collection/components/mrd-image-field/mrd-image-field.js +71 -2
- package/dist/collection/components/mrd-image-field/mrd-image-field.scss +26 -2
- package/dist/collection/components/mrd-table/mrd-table.js +386 -62
- package/dist/collection/components/mrd-table/mrd-table.scss +388 -0
- package/dist/collection/dev/app.js +48 -4
- package/dist/collection/dev/sprites.svg +55 -0
- package/dist/collection/utils/i18n.js +144 -0
- package/dist/components/i18n.js +1 -1
- package/dist/components/mrd-field2.js +1 -1
- package/dist/components/mrd-file-field2.js +1 -1
- package/dist/components/mrd-form.js +1 -1
- package/dist/components/mrd-image-field2.js +1 -1
- package/dist/components/mrd-table.js +1 -1
- package/dist/esm/format-EzhfM0uw.js +299 -0
- package/dist/esm/loader.js +1 -1
- package/dist/esm/mosterdcomponents.js +1 -1
- package/dist/esm/mrd-boolean-field_16.entry.js +82 -91
- package/dist/esm/mrd-table.entry.js +318 -62
- package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
- package/dist/mosterdcomponents/p-27f6947a.entry.js +1 -0
- package/dist/mosterdcomponents/p-EzhfM0uw.js +1 -0
- package/dist/mosterdcomponents/p-ca5f9919.entry.js +1 -0
- package/dist/types/components/mrd-field/mrd-field.d.ts +5 -0
- package/dist/types/components/mrd-file-field/mrd-file-field.d.ts +10 -0
- package/dist/types/components/mrd-form/mrd-form.d.ts +5 -0
- package/dist/types/components/mrd-image-field/mrd-image-field.d.ts +10 -0
- package/dist/types/components/mrd-table/mrd-table.d.ts +52 -18
- package/dist/types/components.d.ts +53 -3
- package/dist/types/utils/cell-renderer.d.ts +27 -0
- package/package.json +1 -1
- package/dist/cjs/format-CDw-zie_.js +0 -82
- package/dist/esm/format-Dt-aHxkM.js +0 -74
- package/dist/mosterdcomponents/p-2a8cb2eb.entry.js +0 -1
- package/dist/mosterdcomponents/p-Dt-aHxkM.js +0 -1
- package/dist/mosterdcomponents/p-baf08615.entry.js +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @mmlogic/components
|
|
2
2
|
|
|
3
|
-
A **Stencil.js v4** web component library for rendering dynamic forms and paginated data tables from API descriptors. Components are framework-agnostic
|
|
3
|
+
A **Stencil.js v4** web component library for rendering dynamic forms and paginated data tables from API descriptors. Components are framework-agnostic (plain HTML/JS) and an Angular output target is included.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -13,7 +13,8 @@ npm install @mmlogic/components
|
|
|
13
13
|
### Vanilla HTML / JS
|
|
14
14
|
|
|
15
15
|
```html
|
|
16
|
-
<
|
|
16
|
+
<link rel="stylesheet" href="node_modules/@mmlogic/components/dist/mosterdcomponents/mosterdcomponents.css" />
|
|
17
|
+
<script type="module" src="node_modules/@mmlogic/components/dist/mosterdcomponents/mosterdcomponents.esm.js"></script>
|
|
17
18
|
|
|
18
19
|
<mrd-form id="my-form"></mrd-form>
|
|
19
20
|
|
|
@@ -28,7 +29,8 @@ npm install @mmlogic/components
|
|
|
28
29
|
### Via CDN (unpkg)
|
|
29
30
|
|
|
30
31
|
```html
|
|
31
|
-
<
|
|
32
|
+
<link rel="stylesheet" href="https://unpkg.com/@mmlogic/components/dist/mosterdcomponents/mosterdcomponents.css" />
|
|
33
|
+
<script type="module" src="https://unpkg.com/@mmlogic/components/dist/mosterdcomponents/mosterdcomponents.esm.js"></script>
|
|
32
34
|
```
|
|
33
35
|
|
|
34
36
|
### Angular
|
|
@@ -50,45 +52,118 @@ export class AppModule {}
|
|
|
50
52
|
|
|
51
53
|
### `<mrd-form>`
|
|
52
54
|
|
|
53
|
-
Renders a complete form from a layout descriptor. Handles validation, RTL layout (Arabic locale), and
|
|
55
|
+
Renders a complete form from a layout descriptor. Handles validation, RTL layout (Arabic locale), and orchestrates file uploads, relation search, and dependent dropdowns.
|
|
54
56
|
|
|
55
57
|
```html
|
|
56
|
-
<mrd-form id="form" locale="nl-NL"></mrd-form>
|
|
58
|
+
<mrd-form id="form" locale="nl-NL" show-cancel></mrd-form>
|
|
57
59
|
```
|
|
58
60
|
|
|
59
61
|
```js
|
|
62
|
+
const form = document.getElementById('form');
|
|
63
|
+
|
|
60
64
|
form.layout = {
|
|
61
|
-
title: 'New
|
|
65
|
+
title: 'New invoice',
|
|
62
66
|
items: [
|
|
63
|
-
{ type: 'FIELD', field: { name: '
|
|
67
|
+
{ type: 'FIELD', field: { name: 'description', label: 'Description', dataType: 'TEXT', required: true } },
|
|
64
68
|
{ type: 'FIELD', field: { name: 'amount', label: 'Amount', dataType: 'CURRENCY' } },
|
|
65
69
|
]
|
|
66
70
|
};
|
|
67
|
-
|
|
68
|
-
form.addEventListener('
|
|
71
|
+
|
|
72
|
+
form.addEventListener('mrdSubmit', e => console.log(e.detail));
|
|
73
|
+
form.addEventListener('mrdCancel', () => history.back());
|
|
69
74
|
```
|
|
70
75
|
|
|
71
|
-
|
|
76
|
+
#### Props
|
|
72
77
|
|
|
73
|
-
| Prop | Type | Description |
|
|
74
|
-
|
|
75
|
-
| `layout` | `ClientLayout` | Form descriptor with title and items |
|
|
76
|
-
| `values` | `Record<string, any>` | Initial field values |
|
|
77
|
-
| `locale` | `string` | BCP 47 locale
|
|
78
|
-
| `
|
|
78
|
+
| Prop | Type | Default | Description |
|
|
79
|
+
|---|---|---|---|
|
|
80
|
+
| `layout` | `ClientLayout` | required | Form descriptor with `title` and `items[]` |
|
|
81
|
+
| `values` | `Record<string, any>` | `{}` | Initial field values; re-setting this prop re-fills the form (edit mode) |
|
|
82
|
+
| `locale` | `string` | `navigator.language` | BCP 47 locale for labels, validation messages, and formatting |
|
|
83
|
+
| `referenceHref` | `string` | `''` | Absolute href of a parent/context object. Combined with `referenceClass`, `mrd-form` automatically pre-fills the matching relation field so dependent dropdowns load without any host-side form logic. |
|
|
84
|
+
| `referenceClass` | `string` | `''` | `mostSignificantClass` of the parent object (e.g. `'clientAgreements'`). Used to locate the relation field to pre-fill. |
|
|
85
|
+
| `showCancel` | `boolean` | `false` | When `true`, shows a Cancel button next to Submit in the footer. |
|
|
79
86
|
|
|
80
|
-
|
|
87
|
+
#### Events
|
|
81
88
|
|
|
82
89
|
| Event | Detail | Description |
|
|
83
90
|
|---|---|---|
|
|
84
|
-
| `mrdSubmit` | `
|
|
85
|
-
| `mrdCancel` | — | Cancel button clicked |
|
|
91
|
+
| `mrdSubmit` | `Record<string, any>` | Fired on valid submit. Payload contains only layout fields; relation values are normalised to plain href strings. |
|
|
92
|
+
| `mrdCancel` | — | Fired when the Cancel button is clicked. Host handles navigation. |
|
|
93
|
+
| `mrdSearch` | `{ query: string; relatedClass: string }` | Relation search requested. Host calls `field.setSearchResults(results)` with the API response. |
|
|
94
|
+
| `mrdFetchAll` | see below | All records requested for a DROPDOWN relation. Host calls `field.setAllRecords(results)`. |
|
|
95
|
+
| `mrdUpload` | `{ name: string; file: File }` | A file was selected. Host uploads the file and calls `form.setFieldValue(name, uri)` when done. The field shows a loading spinner until the URI arrives. |
|
|
96
|
+
|
|
97
|
+
#### Methods
|
|
98
|
+
|
|
99
|
+
| Method | Description |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `setFieldValue(name, value)` | Inject a value into a named field from outside (e.g. after a file upload completes). |
|
|
102
|
+
| `setSearchResults(results)` | *(on `mrd-relation-field`)* Populate the search autocomplete list. |
|
|
103
|
+
| `setAllRecords(results)` | *(on `mrd-relation-field`)* Populate a DROPDOWN `<select>` with all records. |
|
|
104
|
+
|
|
105
|
+
#### `mrdFetchAll` event detail
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
{
|
|
109
|
+
name: string; // field name — use to find the mrd-relation-field element
|
|
110
|
+
relatedClass: string; // dot-notation class (e.g. "legalmanager.budget")
|
|
111
|
+
mostSignificantClass?: string; // URL segment (e.g. "budgets")
|
|
112
|
+
commonRelation?: string; // name of the dependency field (for dependent dropdowns)
|
|
113
|
+
filter?: string; // query param name
|
|
114
|
+
filterValue?: string; // href of the selected dependency; empty string = clear list
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### Full integration example
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
// mrdSearch — typeahead for RELATION fields
|
|
122
|
+
form.addEventListener('mrdSearch', async (e) => {
|
|
123
|
+
const { query, relatedClass } = e.detail;
|
|
124
|
+
const data = await fetch(`/api/search/${relatedClass}?q=${query}`).then(r => r.json());
|
|
125
|
+
const field = form.querySelector(`mrd-relation-field[name="${relatedClass}"]`);
|
|
126
|
+
field?.setSearchResults(data.map(r => ({ id: r._links.self.href, label: r.name })));
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// mrdFetchAll — populate DROPDOWN selects (including dependent dropdowns)
|
|
130
|
+
form.addEventListener('mrdFetchAll', async (e) => {
|
|
131
|
+
const { name, mostSignificantClass, filter, filterValue } = e.detail;
|
|
132
|
+
const field = form.querySelector(`mrd-relation-field[name="${name}"]`);
|
|
133
|
+
if (!field) return;
|
|
134
|
+
|
|
135
|
+
if (filter && !filterValue) { // dependency cleared → empty the list
|
|
136
|
+
field.setAllRecords([]);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let url = `/data/${tenantId}/${mostSignificantClass}`;
|
|
141
|
+
if (filter && filterValue) url += `?${filter}=${encodeURIComponent(filterValue)}`;
|
|
142
|
+
const result = await fetch(url).then(r => r.json());
|
|
143
|
+
const records = Object.values(result._embedded ?? {})[0] ?? [];
|
|
144
|
+
field.setAllRecords(records.map(r => ({ id: r._links.self.href, label: r.name })));
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// mrdUpload — stream file to server before submit
|
|
148
|
+
form.addEventListener('mrdUpload', async (e) => {
|
|
149
|
+
const { name, file } = e.detail;
|
|
150
|
+
const formData = new FormData();
|
|
151
|
+
formData.append('file', file);
|
|
152
|
+
|
|
153
|
+
// Get pre-signed upload URL from server, then POST the file
|
|
154
|
+
const uploadUrl = await fetch('/api/upload').then(r => r.json());
|
|
155
|
+
const [uri] = await fetch(uploadUrl, { method: 'POST', body: formData }).then(r => r.json());
|
|
156
|
+
|
|
157
|
+
// Return the stored URI to the field — spinner disappears, value is ready for submit
|
|
158
|
+
form.setFieldValue(name, uri);
|
|
159
|
+
});
|
|
160
|
+
```
|
|
86
161
|
|
|
87
162
|
---
|
|
88
163
|
|
|
89
164
|
### `<mrd-table>`
|
|
90
165
|
|
|
91
|
-
A virtual-scroll paginated table
|
|
166
|
+
A virtual-scroll paginated table with column sorting, Excel-style filtering, toolbar actions, and a pagination footer. Only visible rows are in the DOM; pages are fetched on demand via an event.
|
|
92
167
|
|
|
93
168
|
```html
|
|
94
169
|
<mrd-table id="table"></mrd-table>
|
|
@@ -97,60 +172,105 @@ A virtual-scroll paginated table. Only the visible rows (plus a configurable buf
|
|
|
97
172
|
```js
|
|
98
173
|
const table = document.getElementById('table');
|
|
99
174
|
|
|
100
|
-
table.columns = view.
|
|
175
|
+
table.columns = view.columns; // TableColumn[]
|
|
101
176
|
table.totalElements = page.totalElements;
|
|
102
177
|
table.pageSize = page.size;
|
|
103
|
-
table.tableHeight = 500;
|
|
104
|
-
table.locale = 'nl-NL';
|
|
178
|
+
table.tableHeight = 500; // px, fixed container height
|
|
179
|
+
table.locale = 'nl-NL'; // en / nl / ar / fr
|
|
105
180
|
table.defaultSort = view.defaultSort ?? '';
|
|
181
|
+
table.actions = [
|
|
182
|
+
{ action: 'create', label: 'New record', icon: 'assets/sprites.svg#icon-plus', variant: 'primary' },
|
|
183
|
+
{ action: 'export', label: 'Export to Excel', icon: 'assets/sprites.svg#icon-file-excel', disabled: true },
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
let activeFilters = [];
|
|
187
|
+
|
|
188
|
+
table.addEventListener('mrdFilter', (e) => {
|
|
189
|
+
activeFilters = e.detail.filters; // ColumnFilter[]
|
|
190
|
+
});
|
|
106
191
|
|
|
107
192
|
table.addEventListener('mrdLoadPage', async (e) => {
|
|
108
193
|
const { page, sort } = e.detail;
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
194
|
+
const params = new URLSearchParams();
|
|
195
|
+
if (page > 0) params.set('page', String(page));
|
|
196
|
+
if (sort) params.set('sort', sort);
|
|
197
|
+
activeFilters.forEach(f => {
|
|
198
|
+
if (f.operator === 'isEmpty') { params.set(f.field, ''); return; }
|
|
199
|
+
if (f.operator === 'isNotEmpty') { params.set(f.field + '_notempty', 'true'); return; }
|
|
200
|
+
if (f.values?.length) { params.set(f.field, f.values.join(',')); return; }
|
|
201
|
+
if (f.value != null) params.set(f.field, String(f.value));
|
|
202
|
+
if (f.from != null) params.set(f.field + '_from', String(f.from));
|
|
203
|
+
if (f.to != null) params.set(f.field + '_to', String(f.to));
|
|
204
|
+
});
|
|
205
|
+
const qs = params.toString();
|
|
206
|
+
const result = await fetch(qs ? `${dataUrl}?${qs}` : dataUrl).then(r => r.json());
|
|
207
|
+
const rows = Object.values(result._embedded ?? {})[0] ?? [];
|
|
112
208
|
await table.setPage(page, rows);
|
|
113
209
|
});
|
|
114
210
|
|
|
211
|
+
table.addEventListener('mrdAction', (e) => {
|
|
212
|
+
if (e.detail.action === 'create') location.href = '/new';
|
|
213
|
+
if (e.detail.action === 'export') window.open(excelUrl, '_blank');
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
table.addEventListener('mrdRowClick', (e) => {
|
|
217
|
+
location.href = e.detail._links.self.href;
|
|
218
|
+
});
|
|
219
|
+
|
|
115
220
|
await table.init();
|
|
116
|
-
await table.setPage(0, page0Rows); // inject pre-fetched page 0
|
|
221
|
+
await table.setPage(0, page0Rows); // inject pre-fetched page 0 without a second request
|
|
117
222
|
```
|
|
118
223
|
|
|
119
|
-
|
|
224
|
+
#### Props
|
|
120
225
|
|
|
121
226
|
| Prop | Type | Default | Description |
|
|
122
227
|
|---|---|---|---|
|
|
123
228
|
| `columns` | `TableColumn[]` | `[]` | Column definitions |
|
|
124
|
-
| `totalElements` | `number` | `0` | Total
|
|
125
|
-
| `pageSize` | `number` | `20` | Records per page |
|
|
229
|
+
| `totalElements` | `number` | `0` | Total record count. `0` = non-paginated mode (use `rows` prop instead) |
|
|
230
|
+
| `pageSize` | `number` | `20` | Records per page (must match API page size) |
|
|
126
231
|
| `rowHeight` | `number` | `36` | Row height in px |
|
|
127
|
-
| `tableHeight` | `number` | `500` |
|
|
128
|
-
| `locale` | `string` | `navigator.language` | Locale for cell formatting |
|
|
232
|
+
| `tableHeight` | `number` | `500` | Fixed scroll-container height in px |
|
|
233
|
+
| `locale` | `string` | `navigator.language` | Locale for cell formatting and built-in labels (`en`/`nl`/`ar`/`fr`) |
|
|
129
234
|
| `defaultSort` | `string` | `''` | Initial sort, e.g. `"timestamp,desc"` or `"name"` |
|
|
130
235
|
| `rows` | `Record[]` | `[]` | Rows for non-paginated mode |
|
|
236
|
+
| `actions` | `TableAction[]` | `[]` | Toolbar action buttons (`{ action, label, icon?, variant?, disabled? }`) |
|
|
131
237
|
|
|
132
|
-
|
|
238
|
+
#### Events
|
|
133
239
|
|
|
134
240
|
| Event | Detail | Description |
|
|
135
241
|
|---|---|---|
|
|
136
242
|
| `mrdLoadPage` | `{ page: number; sort: string }` | Fired when a page needs to be fetched |
|
|
243
|
+
| `mrdRowClick` | row object | Fired when a data row is clicked |
|
|
244
|
+
| `mrdAction` | `{ action: string }` | Fired when a toolbar action button is clicked |
|
|
245
|
+
| `mrdFilter` | `{ filters: ColumnFilter[] }` | Fired when active column filters change |
|
|
137
246
|
|
|
138
|
-
|
|
247
|
+
#### Methods
|
|
139
248
|
|
|
140
249
|
| Method | Description |
|
|
141
250
|
|---|---|
|
|
142
|
-
| `init()` | Reset state and render window
|
|
143
|
-
| `setPage(page, rows)` | Inject fetched rows for a page
|
|
251
|
+
| `init()` | Reset state and render window. Call after all props are set and before `setPage(0, …)`. |
|
|
252
|
+
| `setPage(page, rows)` | Inject fetched rows for a page. Automatically clamps the render window when the page is shorter than `pageSize` — prevents shimmer rows beyond actual data. |
|
|
144
253
|
|
|
145
|
-
**
|
|
254
|
+
**Sort format:** `"fieldName"` for ASC, `"fieldName,desc"` for DESC — append directly as `&sort=<value>`.
|
|
146
255
|
|
|
147
|
-
|
|
256
|
+
#### Column filtering
|
|
257
|
+
|
|
258
|
+
A filter-toggle button (▼) in the toolbar activates filter mode. Clicking ▾ in any column header opens a popup with sort and type-specific filter controls. Supported per data type:
|
|
259
|
+
|
|
260
|
+
| DataType | Filter |
|
|
261
|
+
|---|---|
|
|
262
|
+
| TEXT, EMAIL, HYPERLINK, RELATION | Starts with / equals / is empty / is not empty |
|
|
263
|
+
| INTEGER, DECIMAL, PERCENTAGE, CURRENCY | Exact value or from–to range |
|
|
264
|
+
| DATE, DATETIME, TIME | Exact date or from–to range |
|
|
265
|
+
| BOOLEAN | All / Yes / No |
|
|
266
|
+
| LIST | Checkbox list |
|
|
267
|
+
| FILE, IMAGE | Not supported |
|
|
148
268
|
|
|
149
269
|
---
|
|
150
270
|
|
|
151
271
|
### Field components
|
|
152
272
|
|
|
153
|
-
|
|
273
|
+
All leaf components can be used standalone. Each emits `mrdChange` and `mrdBlur`.
|
|
154
274
|
|
|
155
275
|
| Component | DataType | Description |
|
|
156
276
|
|---|---|---|
|
|
@@ -165,53 +285,68 @@ Individual input components can be used standalone. Each emits `mrdChange` and `
|
|
|
165
285
|
| `<mrd-email-field>` | `EMAIL` | Email input with validation |
|
|
166
286
|
| `<mrd-hyperlink-field>` | `HYPERLINK` | URL input with validation |
|
|
167
287
|
| `<mrd-list-field>` | `LIST` | Single dropdown or multi-checkbox |
|
|
168
|
-
| `<mrd-file-field>` | `FILE` | Drag-and-drop file upload |
|
|
169
|
-
| `<mrd-image-field>` | `IMAGE` | Drag-and-drop image upload with preview |
|
|
170
|
-
| `<mrd-relation-field>` | `RELATION` |
|
|
288
|
+
| `<mrd-file-field>` | `FILE` | Drag-and-drop file upload with upload spinner |
|
|
289
|
+
| `<mrd-image-field>` | `IMAGE` | Drag-and-drop image upload with local preview and spinner |
|
|
290
|
+
| `<mrd-relation-field>` | `RELATION` | Typeahead search (event-driven) or DROPDOWN select |
|
|
171
291
|
|
|
172
|
-
|
|
292
|
+
#### Common props
|
|
173
293
|
|
|
174
294
|
| Prop | Type | Description |
|
|
175
295
|
|---|---|---|
|
|
176
|
-
| `name` | `string` | Field name,
|
|
296
|
+
| `name` | `string` | Field name, echoed in event detail |
|
|
177
297
|
| `label` | `string` | Visible label |
|
|
178
298
|
| `value` | `any` | Current value |
|
|
179
|
-
| `required` | `boolean` |
|
|
299
|
+
| `required` | `boolean` | Validates on blur; shows error when empty |
|
|
180
300
|
| `disabled` | `boolean` | Disables the input |
|
|
181
|
-
| `locale` | `string` | BCP 47 locale
|
|
301
|
+
| `locale` | `string` | BCP 47 locale |
|
|
182
302
|
|
|
183
|
-
|
|
303
|
+
#### Common events
|
|
184
304
|
|
|
185
|
-
| Event | Detail |
|
|
186
|
-
|
|
187
|
-
| `mrdChange` | `{ name: string; value: any }` |
|
|
188
|
-
| `mrdBlur` | `{ name: string; value: any }` |
|
|
305
|
+
| Event | Detail | Description |
|
|
306
|
+
|---|---|---|
|
|
307
|
+
| `mrdChange` | `{ name: string; value: any }` | Fired on every value change |
|
|
308
|
+
| `mrdBlur` | `{ name: string; value: any }` | Fired on blur (triggers validation) |
|
|
309
|
+
| `mrdUpload` | `{ name: string; file: File }` | *(file/image only)* Fired immediately when a file is selected so the host can stream it to the server |
|
|
310
|
+
|
|
311
|
+
#### File / image upload flow
|
|
312
|
+
|
|
313
|
+
When a file is picked:
|
|
314
|
+
1. The field emits `mrdUpload` with the raw `File` object.
|
|
315
|
+
2. The field immediately shows a spinner and updates its value to the `File` (blocking submit).
|
|
316
|
+
3. The host uploads the file and calls `form.setFieldValue(name, uri)` (or `field.value = uri`).
|
|
317
|
+
4. The field detects the string URI, clears the spinner, and is ready for submit.
|
|
318
|
+
|
|
319
|
+
The submit payload always contains the final URI string — never a `File` object.
|
|
189
320
|
|
|
190
321
|
---
|
|
191
322
|
|
|
192
323
|
## Theming
|
|
193
324
|
|
|
194
|
-
All
|
|
325
|
+
All design tokens are CSS custom properties. The default primary colour is **green** (`#16a34a`). Override on `:root` or any ancestor to match your brand:
|
|
195
326
|
|
|
196
327
|
```css
|
|
197
328
|
:root {
|
|
198
|
-
--mrd-color-primary:
|
|
199
|
-
--mrd-color-
|
|
200
|
-
--mrd-
|
|
201
|
-
--mrd-
|
|
202
|
-
|
|
329
|
+
--mrd-color-primary: #16a34a; /* green-600 — change to your brand colour */
|
|
330
|
+
--mrd-color-primary-light: #dcfce7;
|
|
331
|
+
--mrd-color-primary-dark: #15803d;
|
|
332
|
+
--mrd-color-primary-hover: #166534;
|
|
333
|
+
--mrd-shadow-focus: 0 0 0 3px rgb(22 163 74 / 0.2); /* match primary */
|
|
334
|
+
|
|
335
|
+
--mrd-color-neutral-100: #f3f4f6;
|
|
336
|
+
--mrd-border-radius: 0.375rem;
|
|
337
|
+
--mrd-font-size-sm: 0.875rem;
|
|
203
338
|
}
|
|
204
339
|
```
|
|
205
340
|
|
|
341
|
+
The full list is defined in `src/global/variables.scss` and exposed in the built file `dist/mosterdcomponents/mosterdcomponents.css`.
|
|
342
|
+
|
|
206
343
|
---
|
|
207
344
|
|
|
208
345
|
## TypeScript types
|
|
209
346
|
|
|
210
|
-
Types are exported from the package root:
|
|
211
|
-
|
|
212
347
|
```ts
|
|
213
|
-
import type {
|
|
214
|
-
import type {
|
|
348
|
+
import type { ClientLayout, ClientLayoutItem, RelationSearchResult } from '@mmlogic/components';
|
|
349
|
+
import type { TableColumn, TableAction, ColumnFilter } from '@mmlogic/components/dist/types/utils/cell-renderer';
|
|
215
350
|
```
|
|
216
351
|
|
|
217
352
|
---
|