@malloydata/render 0.0.112-dev231206194739 → 0.0.112-dev231206204526

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.
@@ -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 {
@@ -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: Inter, system-ui, sans-serif;
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,4 @@
1
+ import { RenderResultMetadata } from './render-result-metadata';
2
+ export declare const resultContext: {
3
+ __context__: RenderResultMetadata;
4
+ };
@@ -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
- root: boolean;
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 {
@@ -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.ctx = { root: false };
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, renderOptions))}
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);
@@ -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;
@@ -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
@@ -34,3 +34,9 @@ export declare const NumberFormatting: {
34
34
  view: string;
35
35
  };
36
36
  };
37
+ export declare const NullTest: {
38
+ args: {
39
+ source: string;
40
+ view: string;
41
+ };
42
+ };
@@ -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-dev231206194739",
3
+ "version": "0.0.112-dev231206204526",
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-dev231206194739",
27
+ "@malloydata/malloy": "^0.0.112-dev231206204526",
28
28
  "@types/luxon": "^2.4.0",
29
29
  "lit": "^3.0.2",
30
30
  "lodash": "^4.17.20",