@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 +295 -3
- package/assets/README.md +5 -0
- package/assets/data-grid.css +2 -0
- package/fesm2022/masterteam-data-grid.mjs +19474 -0
- package/fesm2022/masterteam-data-grid.mjs.map +1 -0
- package/package.json +34 -3
- package/types/masterteam-data-grid.d.ts +3422 -0
package/README.md
CHANGED
|
@@ -1,3 +1,295 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
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).
|
package/assets/README.md
ADDED
|
@@ -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
|
+
|