@malloydata/render 0.0.112-dev231206194739 → 0.0.112-dev231207161601
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/dist/component/render-result-metadata.d.ts +12 -0
- package/dist/component/render-result-metadata.js +87 -0
- package/dist/component/render.d.ts +4 -1
- package/dist/component/render.js +15 -1
- package/dist/component/result-context.d.ts +4 -0
- package/dist/component/result-context.js +28 -0
- package/dist/component/table.d.ts +13 -4
- package/dist/component/table.js +137 -82
- package/dist/component/util.d.ts +4 -0
- package/dist/component/util.js +21 -1
- package/dist/stories/tables.stories.d.ts +6 -0
- package/dist/stories/tables.stories.js +7 -1
- package/package.json +2 -2
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Field, Result } from '@malloydata/malloy';
|
|
2
|
+
export interface FieldRenderMetadata {
|
|
3
|
+
field: Field;
|
|
4
|
+
min: number | null;
|
|
5
|
+
max: number | null;
|
|
6
|
+
minString: string | null;
|
|
7
|
+
maxString: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface RenderResultMetadata {
|
|
10
|
+
fields: Record<string, FieldRenderMetadata>;
|
|
11
|
+
}
|
|
12
|
+
export declare function getResultMetadata(result: Result): RenderResultMetadata;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
*
|
|
5
|
+
* Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
* a copy of this software and associated documentation files
|
|
7
|
+
* (the "Software"), to deal in the Software without restriction,
|
|
8
|
+
* including without limitation the rights to use, copy, modify, merge,
|
|
9
|
+
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
10
|
+
* and to permit persons to whom the Software is furnished to do so,
|
|
11
|
+
* subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be
|
|
14
|
+
* included in all copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
22
|
+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.getResultMetadata = void 0;
|
|
26
|
+
const util_1 = require("./util");
|
|
27
|
+
function getResultMetadata(result) {
|
|
28
|
+
const fieldKeyMap = new WeakMap();
|
|
29
|
+
const getFieldKey = (f) => {
|
|
30
|
+
if (fieldKeyMap.has(f))
|
|
31
|
+
return fieldKeyMap.get(f);
|
|
32
|
+
const fieldKey = JSON.stringify(f.fieldPath);
|
|
33
|
+
fieldKeyMap.set(f, fieldKey);
|
|
34
|
+
return fieldKey;
|
|
35
|
+
};
|
|
36
|
+
const metadata = {
|
|
37
|
+
fields: {},
|
|
38
|
+
};
|
|
39
|
+
function initFieldMeta(e) {
|
|
40
|
+
for (const f of e.allFields) {
|
|
41
|
+
if (f.isAtomicField()) {
|
|
42
|
+
const fieldKey = getFieldKey(f);
|
|
43
|
+
metadata.fields[fieldKey] = {
|
|
44
|
+
field: f,
|
|
45
|
+
min: null,
|
|
46
|
+
max: null,
|
|
47
|
+
minString: null,
|
|
48
|
+
maxString: null,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
else if (f.isExploreField()) {
|
|
52
|
+
initFieldMeta(f);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const populateFieldMeta = (data, metadata) => {
|
|
57
|
+
var _a, _b;
|
|
58
|
+
for (const row of data) {
|
|
59
|
+
for (const f of data.field.allFields) {
|
|
60
|
+
const value = f.isAtomicField() ? row.cell(f).value : undefined;
|
|
61
|
+
const fieldKey = getFieldKey(f);
|
|
62
|
+
const fieldMeta = metadata.fields[fieldKey];
|
|
63
|
+
if ((0, util_1.valueIsNumber)(f, value)) {
|
|
64
|
+
const n = value;
|
|
65
|
+
fieldMeta.min = Math.min((_a = fieldMeta.min) !== null && _a !== void 0 ? _a : n, n);
|
|
66
|
+
fieldMeta.max = Math.max((_b = fieldMeta.max) !== null && _b !== void 0 ? _b : n, n);
|
|
67
|
+
}
|
|
68
|
+
else if ((0, util_1.valueIsString)(f, value)) {
|
|
69
|
+
const s = value;
|
|
70
|
+
if (!fieldMeta.minString || fieldMeta.minString.length > s.length)
|
|
71
|
+
fieldMeta.minString = s;
|
|
72
|
+
if (!fieldMeta.maxString || fieldMeta.maxString.length < s.length)
|
|
73
|
+
fieldMeta.maxString = s;
|
|
74
|
+
}
|
|
75
|
+
else if (f.isExploreField()) {
|
|
76
|
+
const data = row.cell(f);
|
|
77
|
+
populateFieldMeta(data, metadata);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
initFieldMeta(result.data.field);
|
|
83
|
+
populateFieldMeta(result.data, metadata);
|
|
84
|
+
return metadata;
|
|
85
|
+
}
|
|
86
|
+
exports.getResultMetadata = getResultMetadata;
|
|
87
|
+
//# sourceMappingURL=render-result-metadata.js.map
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Result } from '@malloydata/malloy';
|
|
2
|
-
import { LitElement } from 'lit';
|
|
2
|
+
import { LitElement, PropertyValues } from 'lit';
|
|
3
3
|
import './table';
|
|
4
|
+
import { RenderResultMetadata } from './render-result-metadata';
|
|
4
5
|
export declare class MalloyRender extends LitElement {
|
|
5
6
|
static styles: import("lit").CSSResult;
|
|
6
7
|
result: Result;
|
|
8
|
+
metadata: RenderResultMetadata;
|
|
9
|
+
willUpdate(changedProperties: PropertyValues<this>): void;
|
|
7
10
|
render(): import("lit-html").TemplateResult<1>;
|
|
8
11
|
}
|
|
9
12
|
declare global {
|
package/dist/component/render.js
CHANGED
|
@@ -32,6 +32,9 @@ exports.MalloyRender = void 0;
|
|
|
32
32
|
const lit_1 = require("lit");
|
|
33
33
|
const decorators_js_1 = require("lit/decorators.js");
|
|
34
34
|
require("./table");
|
|
35
|
+
const context_1 = require("@lit/context");
|
|
36
|
+
const result_context_1 = require("./result-context");
|
|
37
|
+
const render_result_metadata_1 = require("./render-result-metadata");
|
|
35
38
|
// Get the first valid theme value or fallback to CSS variable
|
|
36
39
|
function getThemeValue(prop, ...themes) {
|
|
37
40
|
let value;
|
|
@@ -46,6 +49,11 @@ function getThemeValue(prop, ...themes) {
|
|
|
46
49
|
.toLowerCase()})`);
|
|
47
50
|
}
|
|
48
51
|
let MalloyRender = exports.MalloyRender = class MalloyRender extends lit_1.LitElement {
|
|
52
|
+
willUpdate(changedProperties) {
|
|
53
|
+
if (changedProperties.has('result')) {
|
|
54
|
+
this.metadata = (0, render_result_metadata_1.getResultMetadata)(this.result);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
49
57
|
render() {
|
|
50
58
|
const modelTag = this.result.modelTag;
|
|
51
59
|
const { tag: resultTag } = this.result.tagParse();
|
|
@@ -62,11 +70,13 @@ let MalloyRender = exports.MalloyRender = class MalloyRender extends lit_1.LitEl
|
|
|
62
70
|
const tableGutterSize = getThemeValue('tableGutterSize', localTheme, modelTheme);
|
|
63
71
|
const tablePinnedBackground = getThemeValue('tablePinnedBackground', localTheme, modelTheme);
|
|
64
72
|
const tablePinnedBorder = getThemeValue('tablePinnedBorder', localTheme, modelTheme);
|
|
73
|
+
const fontFamily = getThemeValue('fontFamily', localTheme, modelTheme);
|
|
65
74
|
const dynamicStyle = (0, lit_1.html) `<style>
|
|
66
75
|
:host {
|
|
67
76
|
--malloy-render--table-row-height: ${tableRowHeight};
|
|
68
77
|
--malloy-render--table-body-color: ${tableBodyColor};
|
|
69
78
|
--malloy-render--table-font-size: ${tableFontSize};
|
|
79
|
+
--malloy-render--font-family: ${fontFamily};
|
|
70
80
|
--malloy-render--table-header-color: ${tableHeaderColor};
|
|
71
81
|
--malloy-render--table-header-weight: ${tableHeaderWeight};
|
|
72
82
|
--malloy-render--table-body-weight: ${tableBodyWeight};
|
|
@@ -96,8 +106,9 @@ MalloyRender.styles = (0, lit_1.css) `
|
|
|
96
106
|
--malloy-theme--table-gutter-size: 15px;
|
|
97
107
|
--malloy-theme--table-pinned-background: #f5fafc;
|
|
98
108
|
--malloy-theme--table-pinned-border: 1px solid #daedf3;
|
|
109
|
+
--malloy-theme--font-family: Inter, system-ui, sans-serif;
|
|
99
110
|
|
|
100
|
-
font-family:
|
|
111
|
+
font-family: var(--malloy-render--font-family);
|
|
101
112
|
font-size: var(--malloy-render--table-font-size);
|
|
102
113
|
}
|
|
103
114
|
|
|
@@ -117,6 +128,9 @@ MalloyRender.styles = (0, lit_1.css) `
|
|
|
117
128
|
__decorate([
|
|
118
129
|
(0, decorators_js_1.property)({ attribute: false })
|
|
119
130
|
], MalloyRender.prototype, "result", void 0);
|
|
131
|
+
__decorate([
|
|
132
|
+
(0, context_1.provide)({ context: result_context_1.resultContext })
|
|
133
|
+
], MalloyRender.prototype, "metadata", void 0);
|
|
120
134
|
exports.MalloyRender = MalloyRender = __decorate([
|
|
121
135
|
(0, decorators_js_1.customElement)('malloy-render')
|
|
122
136
|
], MalloyRender);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
*
|
|
5
|
+
* Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
* a copy of this software and associated documentation files
|
|
7
|
+
* (the "Software"), to deal in the Software without restriction,
|
|
8
|
+
* including without limitation the rights to use, copy, modify, merge,
|
|
9
|
+
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
10
|
+
* and to permit persons to whom the Software is furnished to do so,
|
|
11
|
+
* subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be
|
|
14
|
+
* included in all copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
22
|
+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.resultContext = void 0;
|
|
26
|
+
const context_1 = require("@lit/context");
|
|
27
|
+
exports.resultContext = (0, context_1.createContext)('malloy-render-result');
|
|
28
|
+
//# sourceMappingURL=result-context.js.map
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { DataArray } from '@malloydata/malloy';
|
|
1
|
+
import { DataArray, Field } from '@malloydata/malloy';
|
|
2
2
|
import { LitElement, TemplateResult } from 'lit';
|
|
3
|
+
import { RenderResultMetadata } from './render-result-metadata';
|
|
3
4
|
type TableContext = {
|
|
4
5
|
root: boolean;
|
|
6
|
+
widthCache: Map<Field, number>;
|
|
5
7
|
};
|
|
6
8
|
export declare class Table extends LitElement {
|
|
7
9
|
static styles: import("lit").CSSResult;
|
|
@@ -10,12 +12,19 @@ export declare class Table extends LitElement {
|
|
|
10
12
|
pinnedHeader: boolean;
|
|
11
13
|
protected _scrolling: boolean;
|
|
12
14
|
parentCtx: TableContext | undefined;
|
|
13
|
-
ctx:
|
|
14
|
-
|
|
15
|
-
};
|
|
15
|
+
ctx: TableContext;
|
|
16
|
+
metadata: RenderResultMetadata;
|
|
16
17
|
connectedCallback(): void;
|
|
17
18
|
private _handleScroll;
|
|
18
19
|
protected createRenderRoot(): HTMLElement | DocumentFragment;
|
|
20
|
+
private renderHeader;
|
|
21
|
+
private renderField;
|
|
22
|
+
private getCellFontStyling;
|
|
23
|
+
private measuringCanvas;
|
|
24
|
+
private getColumnWidth;
|
|
25
|
+
private getContentStyle;
|
|
26
|
+
private renderCell;
|
|
27
|
+
private renderFieldContent;
|
|
19
28
|
render(): TemplateResult<1>;
|
|
20
29
|
}
|
|
21
30
|
declare global {
|
package/dist/component/table.js
CHANGED
|
@@ -35,96 +35,31 @@ const class_map_js_1 = require("lit/directives/class-map.js");
|
|
|
35
35
|
const context_1 = require("@lit/context");
|
|
36
36
|
const util_1 = require("./util");
|
|
37
37
|
const render_numeric_field_1 = require("./render-numeric-field");
|
|
38
|
+
const result_context_1 = require("./result-context");
|
|
39
|
+
const MIN_COLUMN_WIDTH = 32;
|
|
40
|
+
const MAX_COLUMN_WIDTH = 384;
|
|
41
|
+
const COLUMN_BUFFER = 12;
|
|
38
42
|
const tableContext = (0, context_1.createContext)('table');
|
|
39
|
-
// TODO: replace with an estimator per column
|
|
40
|
-
function getColumnWidth() {
|
|
41
|
-
return 130;
|
|
42
|
-
}
|
|
43
|
-
const getContentStyle = (f) => {
|
|
44
|
-
if (f.isAtomicField()) {
|
|
45
|
-
const width = getColumnWidth();
|
|
46
|
-
return `width: ${width}px; min-width: ${width}px; max-width: ${width}px;`;
|
|
47
|
-
}
|
|
48
|
-
return '';
|
|
49
|
-
};
|
|
50
|
-
const renderCell = (f, value, options) => {
|
|
51
|
-
return (0, lit_1.html) `<div class="cell-wrapper">
|
|
52
|
-
<div
|
|
53
|
-
class=${(0, class_map_js_1.classMap)({
|
|
54
|
-
'cell-gutter': true,
|
|
55
|
-
'hide-gutter-border': options.hideStartGutter,
|
|
56
|
-
})}
|
|
57
|
-
></div>
|
|
58
|
-
<div class="cell-content" style="${getContentStyle(f)}">${value}</div>
|
|
59
|
-
<div
|
|
60
|
-
class=${(0, class_map_js_1.classMap)({
|
|
61
|
-
'cell-gutter': true,
|
|
62
|
-
'hide-gutter-border': options.hideEndGutter,
|
|
63
|
-
})}
|
|
64
|
-
></div>
|
|
65
|
-
</div>`;
|
|
66
|
-
};
|
|
67
|
-
const renderFieldContent = (row, f, options) => {
|
|
68
|
-
var _a;
|
|
69
|
-
if (f.isExploreField()) {
|
|
70
|
-
return (0, lit_1.html) `<malloy-table
|
|
71
|
-
.data=${row.cell(f)}
|
|
72
|
-
.pinnedHeader=${(_a = options.pinnedHeader) !== null && _a !== void 0 ? _a : false}
|
|
73
|
-
.rowLimit=${options.pinnedHeader ? 1 : Infinity}
|
|
74
|
-
></malloy-table>`;
|
|
75
|
-
}
|
|
76
|
-
let value = row.cell(f).value;
|
|
77
|
-
if (options.pinnedHeader)
|
|
78
|
-
value = '';
|
|
79
|
-
else if (f.isAtomicField() && f.isNumber()) {
|
|
80
|
-
value = (0, render_numeric_field_1.renderNumericField)(f, value);
|
|
81
|
-
}
|
|
82
|
-
return renderCell(f, value, {
|
|
83
|
-
hideStartGutter: (0, util_1.isFirstChild)(f),
|
|
84
|
-
hideEndGutter: (0, util_1.isLastChild)(f),
|
|
85
|
-
});
|
|
86
|
-
};
|
|
87
|
-
const renderField = (row, f, options) => {
|
|
88
|
-
return (0, lit_1.html) `<td
|
|
89
|
-
class="column-cell ${(0, class_map_js_1.classMap)({
|
|
90
|
-
numeric: f.isAtomicField() && f.isNumber(),
|
|
91
|
-
})}"
|
|
92
|
-
>
|
|
93
|
-
${renderFieldContent(row, f, options)}
|
|
94
|
-
</td>`;
|
|
95
|
-
};
|
|
96
|
-
const renderHeader = (f) => {
|
|
97
|
-
const isFirst = (0, util_1.isFirstChild)(f);
|
|
98
|
-
const isParentFirst = (0, util_1.isFirstChild)(f.parentExplore);
|
|
99
|
-
const isParentNotAField = !f.parentExplore.isExploreField();
|
|
100
|
-
const hideStartGutter = isFirst && (isParentFirst || isParentNotAField);
|
|
101
|
-
const isLast = (0, util_1.isLastChild)(f);
|
|
102
|
-
const isParentLast = (0, util_1.isLastChild)(f.parentExplore);
|
|
103
|
-
const hideEndGutter = isLast && (isParentLast || isParentNotAField);
|
|
104
|
-
return (0, lit_1.html) `<th
|
|
105
|
-
class="column-cell ${(0, class_map_js_1.classMap)({
|
|
106
|
-
numeric: f.isAtomicField() && f.isNumber(),
|
|
107
|
-
})}"
|
|
108
|
-
>
|
|
109
|
-
${renderCell(f, f.name, {
|
|
110
|
-
hideStartGutter,
|
|
111
|
-
hideEndGutter,
|
|
112
|
-
})}
|
|
113
|
-
</th>`;
|
|
114
|
-
};
|
|
115
43
|
let Table = exports.Table = class Table extends lit_1.LitElement {
|
|
116
44
|
constructor() {
|
|
117
45
|
super(...arguments);
|
|
118
46
|
this.rowLimit = Infinity;
|
|
119
47
|
this.pinnedHeader = false;
|
|
120
48
|
this._scrolling = false;
|
|
121
|
-
this.
|
|
49
|
+
this.measuringCanvas = document.createElement('canvas');
|
|
122
50
|
}
|
|
123
51
|
connectedCallback() {
|
|
124
52
|
super.connectedCallback();
|
|
125
53
|
if (typeof this.parentCtx === 'undefined') {
|
|
126
54
|
this.ctx = {
|
|
127
55
|
root: true,
|
|
56
|
+
widthCache: new Map(),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.ctx = {
|
|
61
|
+
root: false,
|
|
62
|
+
widthCache: this.parentCtx.widthCache,
|
|
128
63
|
};
|
|
129
64
|
}
|
|
130
65
|
}
|
|
@@ -138,19 +73,135 @@ let Table = exports.Table = class Table extends lit_1.LitElement {
|
|
|
138
73
|
return this;
|
|
139
74
|
return super.createRenderRoot();
|
|
140
75
|
}
|
|
76
|
+
renderHeader(f) {
|
|
77
|
+
const isFirst = (0, util_1.isFirstChild)(f);
|
|
78
|
+
const isParentFirst = (0, util_1.isFirstChild)(f.parentExplore);
|
|
79
|
+
const isParentNotAField = !f.parentExplore.isExploreField();
|
|
80
|
+
const hideStartGutter = isFirst && (isParentFirst || isParentNotAField);
|
|
81
|
+
const isLast = (0, util_1.isLastChild)(f);
|
|
82
|
+
const isParentLast = (0, util_1.isLastChild)(f.parentExplore);
|
|
83
|
+
const hideEndGutter = isLast && (isParentLast || isParentNotAField);
|
|
84
|
+
return (0, lit_1.html) `<th
|
|
85
|
+
class="column-cell ${(0, class_map_js_1.classMap)({
|
|
86
|
+
numeric: f.isAtomicField() && f.isNumber(),
|
|
87
|
+
})}"
|
|
88
|
+
>
|
|
89
|
+
${this.renderCell(f, f.name, {
|
|
90
|
+
hideStartGutter,
|
|
91
|
+
hideEndGutter,
|
|
92
|
+
})}
|
|
93
|
+
</th>`;
|
|
94
|
+
}
|
|
95
|
+
renderField(row, f) {
|
|
96
|
+
return (0, lit_1.html) `<td
|
|
97
|
+
class="column-cell ${(0, class_map_js_1.classMap)({
|
|
98
|
+
numeric: f.isAtomicField() && f.isNumber(),
|
|
99
|
+
})}"
|
|
100
|
+
>
|
|
101
|
+
${this.renderFieldContent(row, f)}
|
|
102
|
+
</td>`;
|
|
103
|
+
}
|
|
104
|
+
getCellFontStyling() {
|
|
105
|
+
const rootStyle = getComputedStyle(this);
|
|
106
|
+
const fontFamily = rootStyle
|
|
107
|
+
.getPropertyValue('--malloy-render--font-family')
|
|
108
|
+
.trim();
|
|
109
|
+
const fontSize = rootStyle
|
|
110
|
+
.getPropertyValue('--malloy-render--table-font-size')
|
|
111
|
+
.trim();
|
|
112
|
+
return {
|
|
113
|
+
fontFamily,
|
|
114
|
+
fontSize,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
getColumnWidth(f) {
|
|
118
|
+
const fieldKey = JSON.stringify(f.fieldPath);
|
|
119
|
+
const fieldMeta = this.metadata.fields[fieldKey];
|
|
120
|
+
let width = this.ctx.widthCache.get(f);
|
|
121
|
+
if (typeof width === 'undefined') {
|
|
122
|
+
const fontStyles = this.getCellFontStyling();
|
|
123
|
+
const font = `${fontStyles.fontSize} ${fontStyles.fontFamily}`;
|
|
124
|
+
const titleWidth = (0, util_1.getTextWidth)(f.name, font, this.measuringCanvas);
|
|
125
|
+
if (f.isAtomicField() && f.isString()) {
|
|
126
|
+
width =
|
|
127
|
+
Math.max((0, util_1.getTextWidth)(fieldMeta.maxString, font, this.measuringCanvas), titleWidth) + COLUMN_BUFFER;
|
|
128
|
+
}
|
|
129
|
+
else if (f.isAtomicField() && f.isNumber()) {
|
|
130
|
+
const formattedValue = (0, render_numeric_field_1.renderNumericField)(f, fieldMeta.max);
|
|
131
|
+
width =
|
|
132
|
+
Math.max((0, util_1.getTextWidth)(formattedValue, font, this.measuringCanvas), titleWidth) + COLUMN_BUFFER;
|
|
133
|
+
}
|
|
134
|
+
else
|
|
135
|
+
width = 130;
|
|
136
|
+
width = (0, util_1.clamp)(MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH, width);
|
|
137
|
+
this.ctx.widthCache.set(f, width);
|
|
138
|
+
}
|
|
139
|
+
return width;
|
|
140
|
+
}
|
|
141
|
+
getContentStyle(f) {
|
|
142
|
+
if (f.isAtomicField()) {
|
|
143
|
+
const width = this.getColumnWidth(f);
|
|
144
|
+
return `width: ${width}px; min-width: ${width}px; max-width: ${width}px;`;
|
|
145
|
+
}
|
|
146
|
+
return '';
|
|
147
|
+
}
|
|
148
|
+
renderCell(f, value, options) {
|
|
149
|
+
return (0, lit_1.html) `<div class="cell-wrapper">
|
|
150
|
+
<div
|
|
151
|
+
class=${(0, class_map_js_1.classMap)({
|
|
152
|
+
'cell-gutter': true,
|
|
153
|
+
'hide-gutter-border': options.hideStartGutter,
|
|
154
|
+
})}
|
|
155
|
+
></div>
|
|
156
|
+
<div
|
|
157
|
+
class="cell-content"
|
|
158
|
+
style="${this.getContentStyle(f)}"
|
|
159
|
+
title="${value}"
|
|
160
|
+
>
|
|
161
|
+
${value}
|
|
162
|
+
</div>
|
|
163
|
+
<div
|
|
164
|
+
class=${(0, class_map_js_1.classMap)({
|
|
165
|
+
'cell-gutter': true,
|
|
166
|
+
'hide-gutter-border': options.hideEndGutter,
|
|
167
|
+
})}
|
|
168
|
+
></div>
|
|
169
|
+
</div>`;
|
|
170
|
+
}
|
|
171
|
+
renderFieldContent(row, f) {
|
|
172
|
+
var _a;
|
|
173
|
+
if (f.isExploreField()) {
|
|
174
|
+
return (0, lit_1.html) `<malloy-table
|
|
175
|
+
.data=${row.cell(f)}
|
|
176
|
+
.pinnedHeader=${(_a = this.pinnedHeader) !== null && _a !== void 0 ? _a : false}
|
|
177
|
+
.rowLimit=${this.pinnedHeader ? 1 : Infinity}
|
|
178
|
+
></malloy-table>`;
|
|
179
|
+
}
|
|
180
|
+
let value = row.cell(f).value;
|
|
181
|
+
if (this.pinnedHeader)
|
|
182
|
+
value = '';
|
|
183
|
+
else if ((0, util_1.valueIsNumber)(f, value)) {
|
|
184
|
+
// TS doesn't support typeguards for multiple parameters, so unfortunately have to assert AtomicField here. https://github.com/microsoft/TypeScript/issues/26916
|
|
185
|
+
value = (0, render_numeric_field_1.renderNumericField)(f, value);
|
|
186
|
+
}
|
|
187
|
+
else if (value === null) {
|
|
188
|
+
value = '∅';
|
|
189
|
+
}
|
|
190
|
+
return this.renderCell(f, value, {
|
|
191
|
+
hideStartGutter: (0, util_1.isFirstChild)(f),
|
|
192
|
+
hideEndGutter: (0, util_1.isLastChild)(f),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
141
195
|
render() {
|
|
142
196
|
const fields = this.data.field.allFields;
|
|
143
|
-
const headers = fields.map(f => renderHeader(f));
|
|
144
|
-
const renderOptions = {
|
|
145
|
-
pinnedHeader: this.pinnedHeader,
|
|
146
|
-
};
|
|
197
|
+
const headers = fields.map(f => this.renderHeader(f));
|
|
147
198
|
const rows = [];
|
|
148
199
|
let i = 0;
|
|
149
200
|
for (const row of this.data) {
|
|
150
201
|
if (i >= this.rowLimit)
|
|
151
202
|
break;
|
|
152
203
|
rows.push((0, lit_1.html) `<tr>
|
|
153
|
-
${fields.map(f => renderField(row, f
|
|
204
|
+
${fields.map(f => this.renderField(row, f))}
|
|
154
205
|
</tr>`);
|
|
155
206
|
i++;
|
|
156
207
|
}
|
|
@@ -321,6 +372,10 @@ __decorate([
|
|
|
321
372
|
__decorate([
|
|
322
373
|
(0, context_1.provide)({ context: tableContext })
|
|
323
374
|
], Table.prototype, "ctx", void 0);
|
|
375
|
+
__decorate([
|
|
376
|
+
(0, context_1.consume)({ context: result_context_1.resultContext }),
|
|
377
|
+
(0, decorators_js_1.property)({ attribute: false })
|
|
378
|
+
], Table.prototype, "metadata", void 0);
|
|
324
379
|
__decorate([
|
|
325
380
|
(0, decorators_js_1.eventOptions)({ passive: true })
|
|
326
381
|
], Table.prototype, "_handleScroll", null);
|
package/dist/component/util.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import { Explore, Field } from '@malloydata/malloy';
|
|
2
2
|
export declare function isLastChild(f: Field | Explore): boolean;
|
|
3
3
|
export declare function isFirstChild(f: Field | Explore): boolean;
|
|
4
|
+
export declare function valueIsNumber(f: Field, v: unknown): v is number;
|
|
5
|
+
export declare function valueIsString(f: Field, s: unknown): s is string;
|
|
6
|
+
export declare function getTextWidth(text: string, font: string, canvasToUse?: HTMLCanvasElement): number;
|
|
7
|
+
export declare function clamp(s: number, e: number, v: number): number;
|
package/dist/component/util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isFirstChild = exports.isLastChild = void 0;
|
|
3
|
+
exports.clamp = exports.getTextWidth = exports.valueIsString = exports.valueIsNumber = exports.isFirstChild = exports.isLastChild = void 0;
|
|
4
4
|
function getLocationInParent(f) {
|
|
5
5
|
var _a;
|
|
6
6
|
const parent = f.parentExplore;
|
|
@@ -16,4 +16,24 @@ function isFirstChild(f) {
|
|
|
16
16
|
return getLocationInParent(f) === 0;
|
|
17
17
|
}
|
|
18
18
|
exports.isFirstChild = isFirstChild;
|
|
19
|
+
function valueIsNumber(f, v) {
|
|
20
|
+
return f.isAtomicField() && f.isNumber() && v !== null;
|
|
21
|
+
}
|
|
22
|
+
exports.valueIsNumber = valueIsNumber;
|
|
23
|
+
function valueIsString(f, s) {
|
|
24
|
+
return f.isAtomicField() && f.isString() && s !== null;
|
|
25
|
+
}
|
|
26
|
+
exports.valueIsString = valueIsString;
|
|
27
|
+
function getTextWidth(text, font, canvasToUse) {
|
|
28
|
+
const canvas = canvasToUse !== null && canvasToUse !== void 0 ? canvasToUse : document.createElement('canvas');
|
|
29
|
+
const context = canvas.getContext('2d');
|
|
30
|
+
context.font = font;
|
|
31
|
+
const metrics = context.measureText(text);
|
|
32
|
+
return metrics.width;
|
|
33
|
+
}
|
|
34
|
+
exports.getTextWidth = getTextWidth;
|
|
35
|
+
function clamp(s, e, v) {
|
|
36
|
+
return Math.max(s, Math.min(e, v));
|
|
37
|
+
}
|
|
38
|
+
exports.clamp = clamp;
|
|
19
39
|
//# sourceMappingURL=util.js.map
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.NumberFormatting = exports.Nested = exports.Products2Column = exports.ProductsTableCustomTheme = exports.ProductsTable = void 0;
|
|
6
|
+
exports.NullTest = exports.NumberFormatting = exports.Nested = exports.Products2Column = exports.ProductsTableCustomTheme = exports.ProductsTable = void 0;
|
|
7
7
|
const tables_malloy_raw_1 = __importDefault(require("./static/tables.malloy?raw"));
|
|
8
8
|
const util_1 = require("./util");
|
|
9
9
|
require("./themes.css");
|
|
@@ -56,4 +56,10 @@ exports.NumberFormatting = {
|
|
|
56
56
|
view: 'number_formats',
|
|
57
57
|
},
|
|
58
58
|
};
|
|
59
|
+
exports.NullTest = {
|
|
60
|
+
args: {
|
|
61
|
+
source: 'null_test',
|
|
62
|
+
view: '{ select: * }',
|
|
63
|
+
},
|
|
64
|
+
};
|
|
59
65
|
//# sourceMappingURL=tables.stories.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malloydata/render",
|
|
3
|
-
"version": "0.0.112-
|
|
3
|
+
"version": "0.0.112-dev231207161601",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@lit/context": "^1.1.0",
|
|
27
|
-
"@malloydata/malloy": "^0.0.112-
|
|
27
|
+
"@malloydata/malloy": "^0.0.112-dev231207161601",
|
|
28
28
|
"@types/luxon": "^2.4.0",
|
|
29
29
|
"lit": "^3.0.2",
|
|
30
30
|
"lodash": "^4.17.20",
|