@masterteam/data-grid 0.0.0-stage → 0.0.2

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 CHANGED
@@ -1,3 +1,295 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # @masterteam/data-grid
2
+
3
+ Independent Angular 21 data-grid package, currently an **incomplete implementation checkpoint**. Full parity with the locked AG Grid 36.2.0 Community and Enterprise reference remains required; this package is not ready for that acceptance claim. First registry release: `@masterteam/data-grid@0.0.1` (2026-10-27, peers: Angular only); the release is a checkpoint, not an acceptance claim.
4
+
5
+ ```ts
6
+ import { MtDataGridComponent, type MtColumnDef } from '@masterteam/data-grid';
7
+ // Add MtDataGridComponent to a standalone component's imports.
8
+ readonly rows = [{ id: 'a', name: 'Record', amount: 0 }];
9
+ readonly columns: MtColumnDef<(typeof this.rows)[number]>[] = [
10
+ { field: 'name', width: 240 }, { field: 'amount', width: 180 },
11
+ ];
12
+ readonly identify = (row: (typeof this.rows)[number]) => row.id;
13
+ ```
14
+
15
+ ```html
16
+ <mt-data-grid [rowData]="rows" [columnDefs]="columns" [getRowId]="identify" [height]="400" ariaLabel="Records" />
17
+ ```
18
+
19
+ Implemented foundations: fixed row/column virtual geometry, stable IDs, value getters/formatters, local stable multi-sort (Shift-click), keyboard arrows/Home/End/Page Up/Down, RTL positions, loading/empty text and a small owned API. Callers retain ownership of their input arrays/records. Without getRowId, IDs are source indices; provide IDs for identity across replacements. Values render as text. Duplicate identities and invalid sizes/sort models are errors.
20
+
21
+ Set direction="rtl" for right-to-left layout; label and overlay messages are caller-configurable. CSS variables currently expose mt-grid foreground/background/header/border/row-border/radius/font/cell-padding/hover/focus customization. These are an owned initial subset, not all upstream themes/parts.
22
+
23
+ Columns resize by dragging the header edge or pressing Alt+Left/Right from a focused header (2px per press, RTL aware). Shift-drag transfers width to the next displayed column within both columns' bounds. `resizable:false` disables that column's handle/keys; it can still receive width transferred by its neighbor. Width state belongs to each grid, including hidden columns. `initialWidth` applies on introduction of an ID; a later explicit `width` replaces its state, while omission preserves it. Removing and re-adding the ID creates fresh state. The default minimum is36px; minWidth/maxWidth bound widths.
24
+
25
+ The gridReady event exposes `api.getColumnWidths()` and `api.setColumnWidths([{ colId: 'name', width: 280 }], finished = true)`. API requests outside the column's bounds are ignored, including0/negative requests; they still emit the requested completion notification with current widths. A same-width finished=true call can close a prior unfinished update. Nonfinite sizes and unknown/duplicate IDs fail atomically. `columnResized` emits `{ columns: [{ colId, width }], finished, source: 'api' | 'uiColumnResized' }`. Input-definition replacement events, pointer no-change/Shift-final event details, exact upstream event timing/payloads, held-key acceleration, flex/auto/group sizing and full column state remain open; these owned names/signatures do not imply upstream API compatibility.
26
+
27
+ Build/test/API checks use the package scripts. Research, gaps, API differences and evidence are documented in `.github/instructions/data-grid/README.md`. Canonical integration is the existing showcase `/data-grid` route. Existing mt-table remains in place.
28
+
29
+ ## Portal integration contracts
30
+
31
+ Categorical analysis: give a column `chartCategory: { values: ({ value, data }) =>
32
+ [{ id, label, color }], multiValue? }` and charts group records by that identity,
33
+ label the axis/legend with `label`, colour items with the authored colour (or a
34
+ stable palette slot), and offer **Count of records**, **Non-empty** and **Distinct**
35
+ measures beside numeric series. A Title + Status range therefore charts
36
+ `<chartRecordsLabel> by Status` with integer counts and no numeric column;
37
+ numeric series sum per identity category by default. `chartRecordsLabel` names the
38
+ records ("Tasks"). Multi-value categories count a record once per member and
39
+ disable share charts; missing values group under the localized `Unassigned`.
40
+
41
+ Nested viewports isolate their sticky headers so details cannot paint above a
42
+ parent grid header. For a visible closed native end rail, use
43
+ `{toolPanels: ['columns', 'filters'], position: 'right'}` in LTR (`left` in RTL),
44
+ omitting `defaultToolPanel`. `hiddenByDefault` hides the rail itself.
45
+
46
+ For application-wide Columns panel defaults, provide
47
+ `{provide: MT_GRID_COLUMNS_TOOL_PANEL_DEFAULTS, useValue: {suppressRowGroups: true}}`.
48
+ This hides the duplicate Row Groups zone while retaining the top grouping strip,
49
+ column menus and grouping API. Only built-in Columns panels inherit these defaults;
50
+ explicit `toolPanelParams` override them. Other applications keep the full panel
51
+ by default. `/data-table` demonstrates this provider without changing `/data-grid/demo`.
52
+
53
+ `[autoSizeStrategy]="{ type: 'fitGridWidth' }"` fits displayed columns on mount,
54
+ viewport resizing and visibility/group changes, respecting `minWidth`, `maxWidth`
55
+ and `suppressSizeToFit`. Manual column widths survive sorting/filtering.
56
+ Applying or resetting column state refits saved widths to the current viewport
57
+ in this mode, retaining their proportions and authored limits. A layout saved on
58
+ a wider screen therefore does not force a scrollbar when reopened in a detail.
59
+ `api.sizeColumnsToFit()` requests another fit explicitly. When the minimum widths
60
+ cannot fit, horizontal scrolling remains available; data is never hidden to force
61
+ a fit. This mode measures the viewport, not every cell. It fits within the precise
62
+ content-box width, rounded down, so fractional layouts cannot create a phantom scrollbar.
63
+
64
+ `paginationPanelShow="whenNeeded"` hides the native pager while loading and when
65
+ the entire result fits one page; its default is `always`. The shared pager centers
66
+ numbered controls with the host's paginator tokens. Empty aggregation status panels
67
+ reserve no footer space. `groupDisplayType="groupRows"` gives a full-width heading
68
+ with source-field name, entity content and record count.
69
+
70
+ Loading uses bounded skeleton rows aligned with displayed column widths. A host may
71
+ provide `MT_GRID_EMPTY_OVERLAY` with an Angular component having a `params` input
72
+ (`MtGridEmptyOverlayParams`: `message`, `filtered`, `clearFilters`) to reuse its existing artwork and clear-filter action.
73
+ An explicit `[noRowsTemplate]` takes precedence. The engine imports no product UI.
74
+
75
+ `dataProcessing="external"` emits sort/filter state while leaving the supplied
76
+ server-owned page in its original order. The consumer owns cancellation, totals
77
+ and complete-result processing; this is not a server row-model implementation.
78
+ `headerRenderer` and `groupRowRenderer` accept owned component renderer contracts.
79
+ `captureGridViewState`, `parseGridViewState` and `applyGridViewState` expose version 1
80
+ configuration for columns, sort/filter, grouping, values and pivot, excluding rows.
81
+ `forEachNodeAfterFilterAndSort` iterates the filtered/sorted displayed result before
82
+ pagination; `getDisplayedRowAtIndex` addresses the current page. Detail/group/footer
83
+ rows remain distinguishable on their nodes. `@masterteam/data-table` supplies entity
84
+ cell renderers and native column adapters for direct grid use. Earlier compatibility
85
+ and Studio orchestration is isolated in its `/legacy` entry point.
86
+
87
+ `localeText` supplies a per-grid dictionary. Keys are trimmed English source
88
+ messages (for example `Columns`, `Copy`, `No Rows To Show`); default English and
89
+ caller data/column names remain intact. `localeTextResolver(key, defaultValue,
90
+ params)` can override a message, returning undefined to use the dictionary/default.
91
+ `{parameter}` messages interpolate text safely. Labels, filter operators, panels,
92
+ menus, chart controls and accessibility strings share the scope, including charts
93
+ mounted in an external container. The engine has no Transloco dependency.
94
+
95
+ Chart ranges optionally accept `rowIds`: an array keeps an explicit record
96
+ selection stable through sort/filter/data replacement, `[]` charts no records,
97
+ and `null` follows every matching record independently of group expansion, excluding
98
+ group totals. In pivot mode it follows the finest result groups without duplicate
99
+ parent aggregates. Omission retains positional range behavior.
100
+ New ranges selected in an identity-based chart capture their record IDs too.
101
+ Filtered-out selections produce an empty chart and return when the filter clears.
102
+
103
+ ## Styles
104
+
105
+ Load the compiled utilities once in the host's global styles, after installing/building the package:
106
+
107
+ ```css
108
+ @import "@masterteam/data-grid/assets/data-grid.css";
109
+ ```
110
+
111
+ `pnpm --filter @masterteam/data-grid build` runs `build:tailwind` and then ng-packagr.
112
+ For source-linked development, run `pnpm --filter @masterteam/data-grid build:tailwind`
113
+ after template utility changes. The output is the tracked, generated
114
+ `packages/masterteam/data-grid/assets/data-grid.css` (copied to dist by ng-packagr); the
115
+ showcase imports it from source and build-fixture regenerates and bundles it automatically.
116
+ The grid adds `.mt-grid-root` to its host. Its `mtg:` utilities are scoped, unlayered and
117
+ contain no preflight; other packages' Tailwind bundles can coexist in either load order.
118
+ The existing Masterteam `--mt-grid-*` tokens still control identity and host overrides.
119
+ Geometry, complex states and host/theme tokens remain in component styles. Do not scan this
120
+ package into a host utility bundle or replace its asset with a full unprefixed Tailwind build.
121
+ External chart containers receive the same scope on their chart-dialog host automatically.
122
+
123
+ ## Main demo
124
+
125
+ `/data-grid/demo` is the complete example walkthrough on independently generated players:
126
+ Data Size selects 100 / 1,000 / 10,000 / 100,000 rows (20 data columns plus row numbers
127
+ and selection), default 1,000. Participant, Game of Choice, Performance and Monthly Breakdown
128
+ groups use header text/number/set popups and twelve read-only months (three shown while
129
+ collapsed). The main demo is view-first: no editable columns, editors or undo/redo. The grid fills the available viewport, with
130
+ Columns open and counts/range aggregates in its status bar. Group/pivot drags, totals,
131
+ range/fill-handle selection and copy, all 35 charts and CSV/Excel/PDF exports run on this data.
132
+
133
+ `rowGroupPanelShow="always"`, `pivotPanelShow="always"` and `[showQuickFilter]="true"`
134
+ compose one 48px panel row. `pivotPanelShow` accepts `never`, `always`, `onlyWhenPivoting`
135
+ (default); it is independent of the Row Groups zone. The optional quick-filter field shares
136
+ `quickFilterText`, filter events and `api.resetQuickFilter()` state; no page-level field is needed.
137
+ `animateRows` fades new rows for 150ms and respects reduced motion, without animating geometry.
138
+
139
+ The demo chrome uses `mt-page` and `mt-select-field`. Default Classic Masterteam identity
140
+ flows through the PrimeNG `--p-*` token bridge; no identity is seeded. Host `html.dark`
141
+ updates grid surfaces and linked chart colours, including already open dialogs. Explicit chart
142
+ formatting overrides still win. The behaviour reference is observed only; its code, data and
143
+ assets are not used. Run `demo-check.mjs` against the existing source showcase on port 4444.
144
+
145
+ Group-header drags contribute every eligible child in display order. The pointer carries a
146
+ Classic raised ghost; role zones show live chips, hide prospective grouped headers and restore
147
+ on leave/cancel. Horizontal chips use muted hierarchy chevrons. Pivot result leaves read
148
+ `sum(Jan)` / `avg(Bank Balance)` under their key; `Total` labels only totals groups. Generated
149
+ columns fit the longest aggregate header (minimum 100px) and retain subsequent user resizing.
150
+ Narrow horizontal role zones scroll their own chip lists, keeping reorder targets inside the zone.
151
+
152
+ Header filters open 2px below their buttons, start-aligned and flipped/clamped to the viewport.
153
+ Active filter buttons stay primary-tinted. Set popups focus Search, show tri-state Select All
154
+ and 32px checkbox rows, and apply immediately unless the host explicitly configures Apply.
155
+ The demo has no floating-filter row; the optional `floatingFilter` API remains available.
156
+ The showcase Arabic toggle drives the demo direction end to end. Charts, supplied directional
157
+ icons and pager controls mirror; data/header texts and Latin currency remain English.
158
+
159
+ ### Premium chart and column tools
160
+
161
+ Range charts use a 720×480 dialog (minimum 480×360) with a 44px Range Chart title bar,
162
+ Maximize/Close and a single Chart Menu: Edit Chart, Advanced Settings, Unlink from Grid /
163
+ Link to Grid, Download Chart. Alt+E/F/L/D invokes those actions; Escape closes the focused dialog.
164
+ The 320px editor expands the dialog inside the host and uses underline tabs, accordion sections,
165
+ 36px fields and complete chart-type labels. Title and bottom legend reservations shrink every plot;
166
+ legend names wrap across three rows then paginate. Donuts use a 62% hole with a centre total.
167
+
168
+ `pivotPanelShow` defaults to `onlyWhenPivoting` (`always` remains available). Optional
169
+ `pivotPanelHint` provides a short empty-state example. Columns-panel drags preserve the source at
170
+ 50% opacity, insert between siblings and move complete groups. Group-header resize handles distribute
171
+ the delta proportionally across visible resizable leaves, respecting their min/max bounds;
172
+ double-click autosizes the group and Alt+Left/Right resizes by 10px. The Values aggregation picker
173
+ anchors and flips around its chip, supports arrows/Enter/Escape and restores chip focus.
174
+
175
+ ### Group content and controlled paging
176
+
177
+ A column's `groupValueRenderer` renders its group key content; the native expander, count, keyboard and drag behaviour remain grid-owned. Without it, the source column's `valueFormatter` formats the key using a representative leaf. Group identities stay independent of labels. `cellRenderer: 'group'` accepts `cellRendererParams.innerRenderer` to retain component/function content beside the expander.
178
+
179
+ Pagination uses shared numbered pages and first/previous/next/last controls. For a server-owned page, combine `dataProcessing="external"` with `paginationTotalRows` and optional zero-based `paginationCurrentPage`; the supplied rows are already paged and are not sliced again. `paginationChanged` carries the requested page and size. The consumer owns cancellation, loading, errors and authoritative counts. This does not implement grouped/pivot server rows.
180
+
181
+ ### Complete client query and workbook utilities
182
+
183
+ `queryClientRows(rows, columns, { filters, sort, search, quickFilterColumns }, getRowId)`
184
+ uses the same typed predicates, quick search and comparators as the grid. Supply a
185
+ verified complete client array; unknown/non-filterable predicate columns reject
186
+ instead of silently broadening a scope. It never fetches or pages product data.
187
+
188
+ `createExcelWorkbook([{ name, headers, rows }], rtl?)` returns an XLSX Blob with typed
189
+ number/boolean/date/literal-text cells, filters, column widths and legal unique sheet
190
+ names. The caller owns authorization, acquisition, scope, cancellation and download.
191
+ It is a browser utility, not a durable export job or Chromium PDF implementation.
192
+ See the `/data-table` showcase's matching Records/Summary export.
193
+
194
+ Expanded master/detail rows remain on their master's page and do not increase the
195
+ pager's row count or displace the next master onto another page.
196
+
197
+ ## Unlinked chart popups
198
+
199
+ Unlink a native chart from its Chart Menu (or Alt+L) to freeze its data and float
200
+ the same chart across the page. Drag its title, resize its edges, or maximize it
201
+ to the viewport. Link to Grid restores its grid position and live updates.
202
+ Themes, fonts and RTL continue to follow the source grid. Charts close when their
203
+ owner grid is destroyed. Explicit `chartContainer` embeds keep their container.
204
+ See `/data-grid/demo` in the showcase for the same native chart behaviour.
205
+
206
+ ## Data-based chart names
207
+
208
+ Chart popups and their accessible names use the chart's data title: for example,
209
+ `Budget by Status` or `Amount, Budget by Team`. Automatic titles follow selected
210
+ category/series fields; switching chart type, transposing or unlinking keeps the
211
+ field context. An explicit creation/API title or Format → Titles text takes
212
+ precedence and is also shown in the popup header. Hiding the plot title leaves
213
+ the popup named; clearing it falls back to the data description.
214
+
215
+ The `localeText` / resolver message `{series} by {category}` localizes the
216
+ relationship, with displayed property headers interpolated literally.
217
+
218
+ `chartContext` optionally supplies a source path (for example, `Projects · Digital
219
+ Services Platform · Financial`). The grid captures it when creating a chart;
220
+ `MtCreateRangeChartParams.chartContext` overrides it and `MtChartModel.chartContext`
221
+ reports it. The native popup shows this path above the analysis title, without
222
+ repeating the title in its plot. Embedded plots keep their title, and PNG downloads
223
+ include the context and title once. Unlinked charts retain their captured context.
224
+
225
+ With checked leaf records, Chart Range uses those stable row identities, the first
226
+ non-time category and the first numeric measure containing data. Other chartable
227
+ columns remain available in Data. Without checked records, the cell range applies.
228
+ This uses raw typed values and declared chart roles, not formatted entity text.
229
+
230
+ Crowded cartesian charts keep a bounded canvas and every source point. Native
231
+ category scrollbars expose horizontal windows for columns/lines and vertical
232
+ windows for bars, with wrapped, unrotated labels at readable spacing. Wheel and
233
+ keyboard (arrows, Page Up/Down, Home/End) move the window; numeric scales retain
234
+ the full data domain. Authored navigators retain control of their own axes. Resize
235
+ preserves the window; a changed category set resets it. Pie/scatter and other
236
+ charts without category axes retain their own layouts.
237
+
238
+ ## Auto height and page-hosted chart popups — 2026-10-25
239
+
240
+ `autoHeight` sizes the grid by its content instead of `height`: the header band,
241
+ the status bar / pager / group panel, the plain rows and every open detail row.
242
+ `autoHeightMaxRows` caps the plain rows (the viewport then scrolls them) while
243
+ open details always count in full, so a nested grid inside a detail row never
244
+ squeezes the grid inside *its* detail row; `autoHeightMinRows` (default 3)
245
+ keeps room for the loading and no-rows states. A `MtGridChartScope` may also
246
+ set `chartHost`, a positioned page element: linked chart popups are appended
247
+ to it and bounded by it rather than by the (possibly small) grid that created
248
+ them. The product Studio uses both for its one-page expand-in-place hierarchy.
249
+
250
+ ## Page-owned unlinked charts
251
+
252
+ Provide `MtGridChartScope` at a page/schema component to keep native unlinked
253
+ popups alive when module tabs, record details or virtual rows destroy their grids.
254
+ Call `scope.clear()` on schema/security changes; destroying the provider closes
255
+ all its charts. `scope.themeSource` may point at a surviving theme anchor.
256
+
257
+ Scoped unlinked popups close through their close button or scope cleanup, and
258
+ ignore Escape/outside clicks. Each keeps its frozen data, drag/resize, editor,
259
+ chart types and downloads. After its source is destroyed, relinking and selecting
260
+ a new source range disappear. The chart releases source-grid subscriptions and
261
+ uses an independent injector; retaining a popup does not retain a hidden grid.
262
+ Unscoped grids keep their existing destruction/Escape behaviour; explicit chart
263
+ containers remain consumer-owned embeds and are not retained.
264
+
265
+ ## Chart editor polish — 2026-10-24
266
+
267
+ The native shared chart surface now wraps automatic horizontal category labels into
268
+ at most three measured lines, thinning dense ticks instead of rotating them. Full
269
+ category identities remain in the data and point tooltips. Explicit API-authored
270
+ rotation remains supported. English and Arabic labels share the same layout.
271
+
272
+ Every chart type has an owned rounded-stroke shape preview, matching grid-action
273
+ icon weight and colour. The chooser and context menu offer 33 distinct presets.
274
+ `coneFunnel` remains an API/saved-model compatibility type; `customCombo` remains
275
+ restorable and is entered by editing a combination's per-series types in Data.
276
+ Saved compatibility types still appear selected in their editor. All 35 public
277
+ types remain supported. Stacked/normalised/combination/range choices explain their
278
+ two-series requirement; bubbles require X, Y and size. Extra series are selected
279
+ in Data, with unavailable single-series variants clearly identified.
280
+
281
+ The visible Format tab is **Advanced settings**. Its public `format` id and
282
+ `formatPanel` configuration remain stable. The editor has softer field/select
283
+ focus, selected options, consistent 36px controls, grouped axis settings, and a
284
+ 48px tab strip that accommodates the longer English/Arabic label. The engine
285
+ still has no component-library/PrimeNG dependency.
286
+
287
+ The entity integration now formats calculated numeric ticks and aggregates from
288
+ the supplied value, retaining percent/currency units. It no longer repeats a
289
+ sample record's display text (e.g. 0%) for every tick. Ordinary entity cells retain
290
+ their authored display text, and explicit native valueFormatter overrides win.
291
+
292
+
293
+ Sort getter values are reused within one sort invocation and refreshed on the next.
294
+ Scoped unlinked charts survive immediate source teardown, including menu-driven
295
+ Unlink. Verification: [performance/lifecycle notes](../../../.github/instructions/data-grid/PERFORMANCE.md).
@@ -0,0 +1,5 @@
1
+ `data-grid.css` is generated — do not edit it. It is the grid's prefixed (`mtg:`), scoped
2
+ (`.mt-grid-root`), unlayered Tailwind 4 utilities, tracked so the showcase can import it from
3
+ source and so ng-packagr ships it in `dist/masterteam/data-grid/assets/`.
4
+ Source: `src/lib/tailwind.css`; regenerate with `pnpm --filter @masterteam/data-grid build:tailwind`
5
+ (`build` and `testing/data-grid/scripts/build-fixture.mjs` run it first).
@@ -0,0 +1,2 @@
1
+ @supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){.mt-grid-root:is(*),.mt-grid-root *,.mt-grid-root:is(:before),.mt-grid-root :before,.mt-grid-root:is(:after),.mt-grid-root :after,.mt-grid-root:is(::backdrop),.mt-grid-root ::backdrop{--tw-font-weight:initial}}.mt-grid-root,.mt-grid-root{--mtg-font-weight-normal:400;--mtg-font-weight-medium:500;--mtg-font-weight-semibold:600;--mtg-font-weight-bold:700}.mt-grid-root:is(.mtg\:\[margin\:4px_0_8px\]),.mt-grid-root .mtg\:\[margin\:4px_0_8px\]{margin:4px 0 8px}.mt-grid-root:is(.mtg\:\[margin\:12px_0_8px\]),.mt-grid-root .mtg\:\[margin\:12px_0_8px\]{margin:12px 0 8px}.mt-grid-root:is(.mtg\:\[margin\:12px_16px\]),.mt-grid-root .mtg\:\[margin\:12px_16px\]{margin:12px 16px}.mt-grid-root:is(.mtg\:m-0),.mt-grid-root .mtg\:m-0{margin:0}.mt-grid-root:is(.mtg\:mx-2),.mt-grid-root .mtg\:mx-2{margin-inline:8px}.mt-grid-root:is(.mtg\:mx-\[var\(--mt-grid-menu-item-margin\)\]),.mt-grid-root .mtg\:mx-\[var\(--mt-grid-menu-item-margin\)\]{margin-inline:var(--mt-grid-menu-item-margin)}.mt-grid-root:is(.mtg\:my-2),.mt-grid-root .mtg\:my-2{margin-block:8px}.mt-grid-root:is(.mtg\:ms-0),.mt-grid-root .mtg\:ms-0{margin-inline-start:0}.mt-grid-root:is(.mtg\:ms-0\.5),.mt-grid-root .mtg\:ms-0\.5{margin-inline-start:2px}.mt-grid-root:is(.mtg\:ms-0\.75),.mt-grid-root .mtg\:ms-0\.75{margin-inline-start:3px}.mt-grid-root:is(.mtg\:ms-1),.mt-grid-root .mtg\:ms-1{margin-inline-start:4px}.mt-grid-root:is(.mtg\:ms-2),.mt-grid-root .mtg\:ms-2{margin-inline-start:8px}.mt-grid-root:is(.mtg\:me-0\.5),.mt-grid-root .mtg\:me-0\.5{margin-inline-end:2px}.mt-grid-root:is(.mtg\:me-1\.5),.mt-grid-root .mtg\:me-1\.5{margin-inline-end:6px}.mt-grid-root:is(.mtg\:me-2),.mt-grid-root .mtg\:me-2{margin-inline-end:8px}.mt-grid-root:is(.mtg\:me-3),.mt-grid-root .mtg\:me-3{margin-inline-end:12px}.mt-grid-root:is(.mtg\:mt-2),.mt-grid-root .mtg\:mt-2{margin-top:8px}.mt-grid-root:is(.mtg\:mb-2),.mt-grid-root .mtg\:mb-2{margin-bottom:8px}.mt-grid-root:is(.mtg\:block),.mt-grid-root .mtg\:block{display:block}.mt-grid-root:is(.mtg\:contents),.mt-grid-root .mtg\:contents{display:contents}.mt-grid-root:is(.mtg\:flex),.mt-grid-root .mtg\:flex{display:flex}.mt-grid-root:is(.mtg\:grid),.mt-grid-root .mtg\:grid{display:grid}.mt-grid-root:is(.mtg\:inline-flex),.mt-grid-root .mtg\:inline-flex{display:inline-flex}.mt-grid-root:is(.mtg\:min-h-0),.mt-grid-root .mtg\:min-h-0{min-height:0}.mt-grid-root:is(.mtg\:min-w-0),.mt-grid-root .mtg\:min-w-0{min-width:0}.mt-grid-root:is(.mtg\:flex-1),.mt-grid-root .mtg\:flex-1{flex:1}.mt-grid-root:is(.mtg\:flex-auto),.mt-grid-root .mtg\:flex-auto{flex:auto}.mt-grid-root:is(.mtg\:flex-none),.mt-grid-root .mtg\:flex-none{flex:none}.mt-grid-root:is(.mtg\:flex-col),.mt-grid-root .mtg\:flex-col{flex-direction:column}.mt-grid-root:is(.mtg\:flex-wrap),.mt-grid-root .mtg\:flex-wrap{flex-wrap:wrap}.mt-grid-root:is(.mtg\:items-center),.mt-grid-root .mtg\:items-center{align-items:center}.mt-grid-root:is(.mtg\:justify-between),.mt-grid-root .mtg\:justify-between{justify-content:space-between}.mt-grid-root:is(.mtg\:justify-center),.mt-grid-root .mtg\:justify-center{justify-content:center}.mt-grid-root:is(.mtg\:justify-end),.mt-grid-root .mtg\:justify-end{justify-content:flex-end}.mt-grid-root:is(.mtg\:\[gap\:6px_2px\]),.mt-grid-root .mtg\:\[gap\:6px_2px\]{gap:6px 2px}.mt-grid-root:is(.mtg\:gap-0\.5),.mt-grid-root .mtg\:gap-0\.5{gap:2px}.mt-grid-root:is(.mtg\:gap-0\.25),.mt-grid-root .mtg\:gap-0\.25{gap:1px}.mt-grid-root:is(.mtg\:gap-0\.75),.mt-grid-root .mtg\:gap-0\.75{gap:3px}.mt-grid-root:is(.mtg\:gap-1),.mt-grid-root .mtg\:gap-1{gap:4px}.mt-grid-root:is(.mtg\:gap-1\.5),.mt-grid-root .mtg\:gap-1\.5{gap:6px}.mt-grid-root:is(.mtg\:gap-2),.mt-grid-root .mtg\:gap-2{gap:8px}.mt-grid-root:is(.mtg\:gap-3),.mt-grid-root .mtg\:gap-3{gap:12px}.mt-grid-root:is(.mtg\:gap-4),.mt-grid-root .mtg\:gap-4{gap:16px}.mt-grid-root:is(.mtg\:gap-6),.mt-grid-root .mtg\:gap-6{gap:24px}.mt-grid-root:is(.mtg\:gap-8),.mt-grid-root .mtg\:gap-8{gap:32px}.mt-grid-root:is(.mtg\:overflow-auto),.mt-grid-root .mtg\:overflow-auto{overflow:auto}.mt-grid-root:is(.mtg\:overflow-hidden),.mt-grid-root .mtg\:overflow-hidden{overflow:hidden}.mt-grid-root:is(.mtg\:overflow-visible),.mt-grid-root .mtg\:overflow-visible{overflow:visible}.mt-grid-root:is(.mtg\:\[border-radius\:var\(--mt-grid-checkbox-radius\)\]),.mt-grid-root .mtg\:\[border-radius\:var\(--mt-grid-checkbox-radius\)\]{border-radius:var(--mt-grid-checkbox-radius)}.mt-grid-root:is(.mtg\:\[border-radius\:var\(--mt-grid-chip-radius\)\]),.mt-grid-root .mtg\:\[border-radius\:var\(--mt-grid-chip-radius\)\]{border-radius:var(--mt-grid-chip-radius)}.mt-grid-root:is(.mtg\:\[border-radius\:var\(--mt-grid-dropdown-radius\)\]),.mt-grid-root .mtg\:\[border-radius\:var\(--mt-grid-dropdown-radius\)\]{border-radius:var(--mt-grid-dropdown-radius)}.mt-grid-root:is(.mtg\:rounded-\[2px\]),.mt-grid-root .mtg\:rounded-\[2px\]{border-radius:2px}.mt-grid-root:is(.mtg\:rounded-\[4px\]),.mt-grid-root .mtg\:rounded-\[4px\]{border-radius:4px}.mt-grid-root:is(.mtg\:rounded-\[9px\]),.mt-grid-root .mtg\:rounded-\[9px\]{border-radius:9px}.mt-grid-root:is(.mtg\:rounded-\[12px\]),.mt-grid-root .mtg\:rounded-\[12px\]{border-radius:12px}.mt-grid-root:is(.mtg\:rounded-grid),.mt-grid-root .mtg\:rounded-grid{border-radius:var(--mt-grid-radius)}.mt-grid-root:is(.mtg\:rounded-grid-control),.mt-grid-root .mtg\:rounded-grid-control{border-radius:var(--mt-grid-control-radius)}.mt-grid-root:is(.mtg\:rounded-grid-overlay),.mt-grid-root .mtg\:rounded-grid-overlay{border-radius:var(--mt-grid-overlay-radius)}.mt-grid-root:is(.mtg\:bg-grid-background),.mt-grid-root .mtg\:bg-grid-background{background-color:var(--mt-grid-background)}.mt-grid-root:is(.mtg\:bg-grid-chrome),.mt-grid-root .mtg\:bg-grid-chrome{background-color:var(--mt-grid-chrome)}.mt-grid-root:is(.mtg\:bg-grid-input),.mt-grid-root .mtg\:bg-grid-input{background-color:var(--mt-grid-input-background)}.mt-grid-root:is(.mtg\:bg-grid-menu),.mt-grid-root .mtg\:bg-grid-menu{background-color:var(--mt-grid-menu-background)}.mt-grid-root:is(.mtg\:\[padding\:0_0_8px\]),.mt-grid-root .mtg\:\[padding\:0_0_8px\]{padding:0 0 8px}.mt-grid-root:is(.mtg\:\[padding\:0_2px\]),.mt-grid-root .mtg\:\[padding\:0_2px\]{padding:0 2px}.mt-grid-root:is(.mtg\:\[padding\:0_4px\]),.mt-grid-root .mtg\:\[padding\:0_4px\]{padding:0 4px}.mt-grid-root:is(.mtg\:\[padding\:0_4px_6px_4px\]),.mt-grid-root .mtg\:\[padding\:0_4px_6px_4px\]{padding:0 4px 6px}.mt-grid-root:is(.mtg\:\[padding\:0_4px_6px_26px\]),.mt-grid-root .mtg\:\[padding\:0_4px_6px_26px\]{padding:0 4px 6px 26px}.mt-grid-root:is(.mtg\:\[padding\:0_8px\]),.mt-grid-root .mtg\:\[padding\:0_8px\]{padding:0 8px}.mt-grid-root:is(.mtg\:\[padding\:0_8px_8px\]),.mt-grid-root .mtg\:\[padding\:0_8px_8px\]{padding:0 8px 8px}.mt-grid-root:is(.mtg\:\[padding\:0_10px\]),.mt-grid-root .mtg\:\[padding\:0_10px\]{padding:0 10px}.mt-grid-root:is(.mtg\:\[padding\:0_12px\]),.mt-grid-root .mtg\:\[padding\:0_12px\]{padding:0 12px}.mt-grid-root:is(.mtg\:\[padding\:0_16px\]),.mt-grid-root .mtg\:\[padding\:0_16px\]{padding:0 16px}.mt-grid-root:is(.mtg\:\[padding\:2px_6px\]),.mt-grid-root .mtg\:\[padding\:2px_6px\]{padding:2px 6px}.mt-grid-root:is(.mtg\:\[padding\:2px_8px\]),.mt-grid-root .mtg\:\[padding\:2px_8px\]{padding:2px 8px}.mt-grid-root:is(.mtg\:\[padding\:4px_0_4px_12px\]),.mt-grid-root .mtg\:\[padding\:4px_0_4px_12px\]{padding:4px 0 4px 12px}.mt-grid-root:is(.mtg\:\[padding\:4px_2px\]),.mt-grid-root .mtg\:\[padding\:4px_2px\]{padding:4px 2px}.mt-grid-root:is(.mtg\:\[padding\:5px_8px\]),.mt-grid-root .mtg\:\[padding\:5px_8px\]{padding:5px 8px}.mt-grid-root:is(.mtg\:\[padding\:6px_8px_12px\]),.mt-grid-root .mtg\:\[padding\:6px_8px_12px\]{padding:6px 8px 12px}.mt-grid-root:is(.mtg\:\[padding\:8px_0\]),.mt-grid-root .mtg\:\[padding\:8px_0\]{padding:8px 0}.mt-grid-root:is(.mtg\:\[padding\:8px_0_0\]),.mt-grid-root .mtg\:\[padding\:8px_0_0\]{padding:8px 0 0}.mt-grid-root:is(.mtg\:\[padding\:8px_12px\]),.mt-grid-root .mtg\:\[padding\:8px_12px\]{padding:8px 12px}.mt-grid-root:is(.mtg\:\[padding\:8px_12px_0\]),.mt-grid-root .mtg\:\[padding\:8px_12px_0\]{padding:8px 12px 0}.mt-grid-root:is(.mtg\:\[padding\:8px_12px_12px\]),.mt-grid-root .mtg\:\[padding\:8px_12px_12px\]{padding:8px 12px 12px}.mt-grid-root:is(.mtg\:\[padding\:8px_16px\]),.mt-grid-root .mtg\:\[padding\:8px_16px\]{padding:8px 16px}.mt-grid-root:is(.mtg\:\[padding\:10px_12px\]),.mt-grid-root .mtg\:\[padding\:10px_12px\]{padding:10px 12px}.mt-grid-root:is(.mtg\:\[padding\:12px_16px_0\]),.mt-grid-root .mtg\:\[padding\:12px_16px_0\]{padding:12px 16px 0}.mt-grid-root:is(.mtg\:\[padding\:24px_8px\]),.mt-grid-root .mtg\:\[padding\:24px_8px\]{padding:24px 8px}.mt-grid-root:is(.mtg\:p-0),.mt-grid-root .mtg\:p-0{padding:0}.mt-grid-root:is(.mtg\:p-0\.5),.mt-grid-root .mtg\:p-0\.5{padding:2px}.mt-grid-root:is(.mtg\:p-0\.75),.mt-grid-root .mtg\:p-0\.75{padding:3px}.mt-grid-root:is(.mtg\:p-1),.mt-grid-root .mtg\:p-1{padding:4px}.mt-grid-root:is(.mtg\:p-2),.mt-grid-root .mtg\:p-2{padding:8px}.mt-grid-root:is(.mtg\:p-3),.mt-grid-root .mtg\:p-3{padding:12px}.mt-grid-root:is(.mtg\:p-4),.mt-grid-root .mtg\:p-4{padding:16px}.mt-grid-root:is(.mtg\:p-\[var\(--mt-grid-dropdown-padding\)\]),.mt-grid-root .mtg\:p-\[var\(--mt-grid-dropdown-padding\)\]{padding:var(--mt-grid-dropdown-padding)}.mt-grid-root:is(.mtg\:\[padding-inline\:8px_28px\]),.mt-grid-root .mtg\:\[padding-inline\:8px_28px\]{padding-inline:8px 28px}.mt-grid-root:is(.mtg\:\[padding-inline\:16px_8px\]),.mt-grid-root .mtg\:\[padding-inline\:16px_8px\]{padding-inline:16px 8px}.mt-grid-root:is(.mtg\:px-0),.mt-grid-root .mtg\:px-0{padding-inline:0}.mt-grid-root:is(.mtg\:px-2),.mt-grid-root .mtg\:px-2{padding-inline:8px}.mt-grid-root:is(.mtg\:px-3),.mt-grid-root .mtg\:px-3{padding-inline:12px}.mt-grid-root:is(.mtg\:px-4),.mt-grid-root .mtg\:px-4{padding-inline:16px}.mt-grid-root:is(.mtg\:px-6),.mt-grid-root .mtg\:px-6{padding-inline:24px}.mt-grid-root:is(.mtg\:px-8),.mt-grid-root .mtg\:px-8{padding-inline:32px}.mt-grid-root:is(.mtg\:px-\[var\(--mt-grid-cell-padding\,16px\)\]),.mt-grid-root .mtg\:px-\[var\(--mt-grid-cell-padding\,16px\)\]{padding-inline:var(--mt-grid-cell-padding,16px)}.mt-grid-root:is(.mtg\:px-\[var\(--mt-grid-menu-item-padding\)\]),.mt-grid-root .mtg\:px-\[var\(--mt-grid-menu-item-padding\)\]{padding-inline:var(--mt-grid-menu-item-padding)}.mt-grid-root:is(.mtg\:py-0),.mt-grid-root .mtg\:py-0{padding-block:0}.mt-grid-root:is(.mtg\:py-1),.mt-grid-root .mtg\:py-1{padding-block:4px}.mt-grid-root:is(.mtg\:py-1\.5),.mt-grid-root .mtg\:py-1\.5{padding-block:6px}.mt-grid-root:is(.mtg\:ps-2),.mt-grid-root .mtg\:ps-2{padding-inline-start:8px}.mt-grid-root:is(.mtg\:ps-3),.mt-grid-root .mtg\:ps-3{padding-inline-start:12px}.mt-grid-root:is(.mtg\:ps-4),.mt-grid-root .mtg\:ps-4{padding-inline-start:16px}.mt-grid-root:is(.mtg\:pe-2),.mt-grid-root .mtg\:pe-2{padding-inline-end:8px}.mt-grid-root:is(.mtg\:pe-3),.mt-grid-root .mtg\:pe-3{padding-inline-end:12px}.mt-grid-root:is(.mtg\:pe-4),.mt-grid-root .mtg\:pe-4{padding-inline-end:16px}.mt-grid-root:is(.mtg\:pe-6),.mt-grid-root .mtg\:pe-6{padding-inline-end:24px}.mt-grid-root:is(.mtg\:pb-3),.mt-grid-root .mtg\:pb-3{padding-bottom:12px}.mt-grid-root:is(.mtg\:text-center),.mt-grid-root .mtg\:text-center{text-align:center}.mt-grid-root:is(.mtg\:text-start),.mt-grid-root .mtg\:text-start{text-align:start}.mt-grid-root:is(.mtg\:text-\[length\:var\(--mt-grid-caption-size\)\]),.mt-grid-root .mtg\:text-\[length\:var\(--mt-grid-caption-size\)\]{font-size:var(--mt-grid-caption-size)}.mt-grid-root:is(.mtg\:text-\[length\:var\(--mt-grid-font-size\)\]),.mt-grid-root .mtg\:text-\[length\:var\(--mt-grid-font-size\)\]{font-size:var(--mt-grid-font-size)}.mt-grid-root:is(.mtg\:font-bold),.mt-grid-root .mtg\:font-bold{--tw-font-weight:var(--mtg-font-weight-bold);font-weight:var(--mtg-font-weight-bold)}.mt-grid-root:is(.mtg\:font-medium),.mt-grid-root .mtg\:font-medium{--tw-font-weight:var(--mtg-font-weight-medium);font-weight:var(--mtg-font-weight-medium)}.mt-grid-root:is(.mtg\:font-normal),.mt-grid-root .mtg\:font-normal{--tw-font-weight:var(--mtg-font-weight-normal);font-weight:var(--mtg-font-weight-normal)}.mt-grid-root:is(.mtg\:font-semibold),.mt-grid-root .mtg\:font-semibold{--tw-font-weight:var(--mtg-font-weight-semibold);font-weight:var(--mtg-font-weight-semibold)}.mt-grid-root:is(.mtg\:text-ellipsis),.mt-grid-root .mtg\:text-ellipsis{text-overflow:ellipsis}.mt-grid-root:is(.mtg\:whitespace-nowrap),.mt-grid-root .mtg\:whitespace-nowrap{white-space:nowrap}.mt-grid-root:is(.mtg\:text-grid-foreground),.mt-grid-root .mtg\:text-grid-foreground{color:var(--mt-grid-foreground)}.mt-grid-root:is(.mtg\:text-grid-muted),.mt-grid-root .mtg\:text-grid-muted{color:var(--mt-grid-muted)}.mt-grid-root:is(.mtg\:text-grid-primary),.mt-grid-root .mtg\:text-grid-primary{color:var(--mt-grid-primary)}.mt-grid-root:is(.mtg\:text-grid-secondary),.mt-grid-root .mtg\:text-grid-secondary{color:var(--mt-grid-secondary)}.mt-grid-root:is(.mtg\:uppercase),.mt-grid-root .mtg\:uppercase{text-transform:uppercase}.mt-grid-root:is(.mtg\:\[box-shadow\:var\(--mt-grid-shadow-dialog\)\]),.mt-grid-root .mtg\:\[box-shadow\:var\(--mt-grid-shadow-dialog\)\]{box-shadow:var(--mt-grid-shadow-dialog)}.mt-grid-root:is(.mtg\:\[box-shadow\:var\(--mt-grid-shadow-panel\)\]),.mt-grid-root .mtg\:\[box-shadow\:var\(--mt-grid-shadow-panel\)\]{box-shadow:var(--mt-grid-shadow-panel)}.mt-grid-root:is(.mtg\:\[box-shadow\:var\(--mt-grid-shadow-popover\)\]),.mt-grid-root .mtg\:\[box-shadow\:var\(--mt-grid-shadow-popover\)\]{box-shadow:var(--mt-grid-shadow-popover)}.mt-grid-root:is(.mtg\:\[border\:1px_solid_var\(--mt-grid-border\)\]),.mt-grid-root .mtg\:\[border\:1px_solid_var\(--mt-grid-border\)\]{border:1px solid var(--mt-grid-border)}@media (hover:hover){.mt-grid-root:is(.mtg\:hover\:\[background-color\:var\(--mt-grid-control-hover\)\]:hover),.mt-grid-root .mtg\:hover\:\[background-color\:var\(--mt-grid-control-hover\)\]:hover{background-color:var(--mt-grid-control-hover)}.mt-grid-root:is(.mtg\:hover\:\[background-color\:var\(--mt-grid-hover\)\]:hover),.mt-grid-root .mtg\:hover\:\[background-color\:var\(--mt-grid-hover\)\]:hover{background-color:var(--mt-grid-hover)}.mt-grid-root:is(.mtg\:hover\:\[background-color\:var\(--mt-grid-menu-active\)\]:hover),.mt-grid-root .mtg\:hover\:\[background-color\:var\(--mt-grid-menu-active\)\]:hover{background-color:var(--mt-grid-menu-active)}.mt-grid-root:is(.mtg\:hover\:\[background-color\:var\(--mt-grid-secondary-bg-hover\)\]:hover),.mt-grid-root .mtg\:hover\:\[background-color\:var\(--mt-grid-secondary-bg-hover\)\]:hover{background-color:var(--mt-grid-secondary-bg-hover)}}
2
+