@malloydata/render 0.0.105-dev231124203430 → 0.0.105-dev231127183208

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,2 @@
1
+ <link rel="preconnect" href="https://rsms.me/" />
2
+ <link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
@@ -48,10 +48,31 @@ MalloyRender.styles = (0, lit_1.css) `
48
48
  --table-border: 1px solid #e5e7eb;
49
49
  --table-background: white;
50
50
  --table-gutter-size: 15px;
51
+ --table-pinned-background: #f5fafc;
52
+ --table-pinned-border: 1px solid #daedf3;
51
53
 
52
54
  font-family: Inter, system-ui, sans-serif;
53
55
  font-size: var(--table-font-size);
54
56
  }
57
+
58
+ @supports (font-variation-settings: normal) {
59
+ :host {
60
+ font-family:
61
+ InterVariable,
62
+ Inter,
63
+ system-ui sans-serif;
64
+
65
+ font-variant-numeric: tabular-nums;
66
+ font-feature-settings:
67
+ 'cv01' 1,
68
+ 'cv02' 1,
69
+ 'cv03' 1,
70
+ 'cv04' 1,
71
+ 'cv09' 1,
72
+ 'liga' 1,
73
+ 'calt' 1;
74
+ }
75
+ }
55
76
  `;
56
77
  __decorate([
57
78
  (0, decorators_js_1.property)({ attribute: false })
@@ -1,12 +1,26 @@
1
1
  import { DataArray } from '@malloydata/malloy';
2
- import { LitElement } from 'lit';
2
+ import { LitElement, TemplateResult } from 'lit';
3
+ type TableContext = {
4
+ root: boolean;
5
+ };
3
6
  export declare class Table extends LitElement {
4
7
  static styles: import("lit").CSSResult;
5
8
  data: DataArray;
6
- render(): import("lit-html").TemplateResult<1>;
9
+ rowLimit: number;
10
+ pinnedHeader: boolean;
11
+ protected _scrolling: boolean;
12
+ parentCtx: TableContext | undefined;
13
+ ctx: {
14
+ root: boolean;
15
+ };
16
+ connectedCallback(): void;
17
+ private _handleScroll;
18
+ protected createRenderRoot(): HTMLElement | DocumentFragment;
19
+ render(): TemplateResult<1>;
7
20
  }
8
21
  declare global {
9
22
  interface HTMLElementTagNameMap {
10
23
  'malloy-table': Table;
11
24
  }
12
25
  }
26
+ export {};
@@ -32,7 +32,9 @@ exports.Table = void 0;
32
32
  const lit_1 = require("lit");
33
33
  const decorators_js_1 = require("lit/decorators.js");
34
34
  const class_map_js_1 = require("lit/directives/class-map.js");
35
+ const context_1 = require("@lit/context");
35
36
  const util_1 = require("./util");
37
+ const tableContext = (0, context_1.createContext)('table');
36
38
  // TODO: replace with an estimator per column
37
39
  function getColumnWidth() {
38
40
  return 130;
@@ -44,30 +46,45 @@ const getContentStyle = (f) => {
44
46
  }
45
47
  return '';
46
48
  };
47
- const renderCell = (f, value) => {
49
+ const renderCell = (f, value, options) => {
48
50
  return (0, lit_1.html) `<div class="cell-wrapper">
49
- <div class="cell-gutter-start"></div>
51
+ <div
52
+ class=${(0, class_map_js_1.classMap)({
53
+ 'cell-gutter': true,
54
+ 'hide-gutter-border': options.hideStartGutter,
55
+ })}
56
+ ></div>
50
57
  <div class="cell-content" style="${getContentStyle(f)}">${value}</div>
51
- <div class="cell-gutter-end"></div>
58
+ <div
59
+ class=${(0, class_map_js_1.classMap)({
60
+ 'cell-gutter': true,
61
+ 'hide-gutter-border': options.hideEndGutter,
62
+ })}
63
+ ></div>
52
64
  </div>`;
53
65
  };
54
- const renderFieldContent = (row, f) => {
66
+ const renderFieldContent = (row, f, options) => {
67
+ var _a;
55
68
  if (f.isExploreField()) {
56
69
  return (0, lit_1.html) `<malloy-table
57
70
  .data=${row.cell(f)}
71
+ .pinnedHeader=${(_a = options.pinnedHeader) !== null && _a !== void 0 ? _a : false}
72
+ .rowLimit=${options.pinnedHeader ? 1 : Infinity}
58
73
  ></malloy-table>`;
59
74
  }
60
- return renderCell(f, row.cell(f).value);
75
+ if (options.pinnedHeader)
76
+ return renderCell(f, '', {
77
+ hideStartGutter: (0, util_1.isFirstChild)(f),
78
+ hideEndGutter: (0, util_1.isLastChild)(f),
79
+ });
80
+ return renderCell(f, row.cell(f).value, {
81
+ hideStartGutter: (0, util_1.isFirstChild)(f),
82
+ hideEndGutter: (0, util_1.isLastChild)(f),
83
+ });
61
84
  };
62
- const renderField = (row, f) => {
63
- return (0, lit_1.html) `<td
64
- class=${(0, class_map_js_1.classMap)({
65
- 'column-cell': true,
66
- 'hide-end-gutter': (0, util_1.isLastChild)(f),
67
- 'hide-start-gutter': (0, util_1.isFirstChild)(f),
68
- })}
69
- >
70
- ${renderFieldContent(row, f)}
85
+ const renderField = (row, f, options) => {
86
+ return (0, lit_1.html) `<td class="column-cell">
87
+ ${renderFieldContent(row, f, options)}
71
88
  </td>`;
72
89
  };
73
90
  const renderHeader = (f) => {
@@ -78,40 +95,120 @@ const renderHeader = (f) => {
78
95
  const isLast = (0, util_1.isLastChild)(f);
79
96
  const isParentLast = (0, util_1.isLastChild)(f.parentExplore);
80
97
  const hideEndGutter = isLast && (isParentLast || isParentNotAField);
81
- return (0, lit_1.html) `<th
82
- class=${(0, class_map_js_1.classMap)({
83
- 'column-cell': true,
84
- 'hide-end-gutter': hideEndGutter,
85
- 'hide-start-gutter': hideStartGutter,
98
+ return (0, lit_1.html) `<th class="column-cell">
99
+ ${renderCell(f, f.name, {
100
+ hideStartGutter,
101
+ hideEndGutter,
86
102
  })}
87
- >
88
- ${renderCell(f, f.name)}
89
103
  </th>`;
90
104
  };
91
105
  let Table = exports.Table = class Table extends lit_1.LitElement {
106
+ constructor() {
107
+ super(...arguments);
108
+ this.rowLimit = Infinity;
109
+ this.pinnedHeader = false;
110
+ this._scrolling = false;
111
+ this.ctx = { root: false };
112
+ }
113
+ connectedCallback() {
114
+ super.connectedCallback();
115
+ if (typeof this.parentCtx === 'undefined') {
116
+ this.ctx = {
117
+ root: true,
118
+ };
119
+ }
120
+ }
121
+ _handleScroll(e) {
122
+ const target = e.target;
123
+ this._scrolling = target.scrollTop > 0;
124
+ }
125
+ // If rendering a pinned header, render it within the current ShadowDOM root so we can use CSS to style the nested table headers when scrolling
126
+ createRenderRoot() {
127
+ if (this.pinnedHeader)
128
+ return this;
129
+ return super.createRenderRoot();
130
+ }
92
131
  render() {
93
132
  const fields = this.data.field.allFields;
94
133
  const headers = fields.map(f => renderHeader(f));
95
- const rows = Array.from(this.data, row => (0, lit_1.html) `<tr>
96
- ${fields.map(f => renderField(row, f))}
134
+ const renderOptions = {
135
+ pinnedHeader: this.pinnedHeader,
136
+ };
137
+ const rows = [];
138
+ let i = 0;
139
+ for (const row of this.data) {
140
+ if (i >= this.rowLimit)
141
+ break;
142
+ rows.push((0, lit_1.html) `<tr>
143
+ ${fields.map(f => renderField(row, f, renderOptions))}
97
144
  </tr>`);
98
- return (0, lit_1.html) `<table>
99
- <thead>
100
- <tr>
101
- ${headers}
102
- </tr>
103
- </thead>
104
- <tbody>
105
- ${rows}
106
- </tbody>
107
- </table>`;
145
+ i++;
146
+ }
147
+ const renderStickyHeader = () => {
148
+ if (this.ctx.root) {
149
+ return (0, lit_1.html) `<div class="sticky-header">
150
+ <div class="sticky-header-content">
151
+ <malloy-table
152
+ class=${(0, class_map_js_1.classMap)({
153
+ 'pinned-header': true,
154
+ 'scrolled': this._scrolling,
155
+ })}
156
+ .rowLimit=${1}
157
+ .data=${this.data}
158
+ .pinnedHeader=${true}
159
+ ></malloy-table>
160
+ </div>
161
+ </div>`;
162
+ }
163
+ return lit_1.nothing;
164
+ };
165
+ return (0, lit_1.html) `<div @scroll=${this._handleScroll} class="table-wrapper">
166
+ ${renderStickyHeader()}
167
+ <table>
168
+ <thead>
169
+ <tr>
170
+ ${headers}
171
+ </tr>
172
+ </thead>
173
+ <tbody>
174
+ ${rows}
175
+ </tbody>
176
+ </table>
177
+ </div>`;
108
178
  }
109
179
  };
110
180
  Table.styles = (0, lit_1.css) `
181
+ .table-wrapper {
182
+ width: 100%;
183
+ height: 100%;
184
+ position: relative;
185
+ overflow: auto;
186
+ }
187
+
188
+ .sticky-header {
189
+ position: sticky;
190
+ top: 0px;
191
+ z-index: 100;
192
+ }
193
+
194
+ .sticky-header-content {
195
+ position: absolute;
196
+ top: 0px;
197
+ left: 0px;
198
+ pointer-events: none;
199
+ }
200
+
201
+ .sticky-header-content th {
202
+ pointer-events: all;
203
+ }
204
+
111
205
  table {
112
206
  border-collapse: collapse;
113
207
  background: var(--table-background);
114
- font-variant-numeric: tabular-nums;
208
+ }
209
+
210
+ th {
211
+ transition: background-color 0.25s;
115
212
  }
116
213
 
117
214
  table * {
@@ -154,29 +251,60 @@ Table.styles = (0, lit_1.css) `
154
251
  text-overflow: ellipsis;
155
252
  }
156
253
 
157
- .cell-gutter-start {
254
+ .cell-gutter {
158
255
  border-top: var(--table-border);
159
256
  height: var(--table-row-height);
160
257
  width: var(--table-gutter-size);
258
+ transition: border-color 0.25s;
161
259
  }
162
260
 
163
- .cell-gutter-end {
164
- border-top: var(--table-border);
165
- height: var(--table-row-height);
166
- width: var(--table-gutter-size);
261
+ .cell-gutter.hide-gutter-border {
262
+ border-color: transparent;
263
+ }
264
+
265
+ .pinned-header table {
266
+ background: transparent;
267
+ }
268
+
269
+ .pinned-header th {
270
+ background: var(--table-background);
167
271
  }
168
272
 
169
- .hide-end-gutter .cell-gutter-end {
170
- border-top: none;
273
+ .pinned-header.scrolled th {
274
+ background: var(--table-pinned-background);
275
+ box-shadow: 0 0 0.5em rgba(0, 0, 0, 0.5);
171
276
  }
172
277
 
173
- .hide-start-gutter .cell-gutter-start {
174
- border-top: none;
278
+ .pinned-header.scrolled {
279
+ .cell-content,
280
+ .cell-gutter,
281
+ .cell-gutter.hide-gutter-border {
282
+ border-top: var(--table-pinned-border);
283
+ }
175
284
  }
176
285
  `;
177
286
  __decorate([
178
287
  (0, decorators_js_1.property)({ attribute: false })
179
288
  ], Table.prototype, "data", void 0);
289
+ __decorate([
290
+ (0, decorators_js_1.property)({ type: Number })
291
+ ], Table.prototype, "rowLimit", void 0);
292
+ __decorate([
293
+ (0, decorators_js_1.property)({ type: Boolean })
294
+ ], Table.prototype, "pinnedHeader", void 0);
295
+ __decorate([
296
+ (0, decorators_js_1.state)()
297
+ ], Table.prototype, "_scrolling", void 0);
298
+ __decorate([
299
+ (0, context_1.consume)({ context: tableContext }),
300
+ (0, decorators_js_1.property)({ attribute: false })
301
+ ], Table.prototype, "parentCtx", void 0);
302
+ __decorate([
303
+ (0, context_1.provide)({ context: tableContext })
304
+ ], Table.prototype, "ctx", void 0);
305
+ __decorate([
306
+ (0, decorators_js_1.eventOptions)({ passive: true })
307
+ ], Table.prototype, "_handleScroll", null);
180
308
  exports.Table = Table = __decorate([
181
309
  (0, decorators_js_1.customElement)('malloy-table')
182
310
  ], Table);
@@ -28,3 +28,10 @@ export declare const Nested: {
28
28
  view: string;
29
29
  };
30
30
  };
31
+ export declare const NestedCompact: {
32
+ args: {
33
+ source: string;
34
+ view: string;
35
+ classes: string;
36
+ };
37
+ };
@@ -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.Nested = exports.Products2Column = exports.ProductsTableCustomTheme = exports.ProductsTable = void 0;
6
+ exports.NestedCompact = 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");
@@ -11,11 +11,15 @@ require("../component/render");
11
11
  const meta = {
12
12
  title: 'Malloy Next/Tables',
13
13
  render: ({ classes }, context) => {
14
+ const parent = document.createElement('div');
15
+ parent.style.height = '1000px';
16
+ parent.style.position = 'relative';
14
17
  const el = document.createElement('malloy-render');
15
18
  if (classes)
16
19
  el.classList.add(classes);
17
20
  el.result = context.loaded['result'];
18
- return el;
21
+ parent.appendChild(el);
22
+ return parent;
19
23
  },
20
24
  loaders: [(0, util_1.createLoader)(tables_malloy_raw_1.default)],
21
25
  argTypes: {},
@@ -46,4 +50,11 @@ exports.Nested = {
46
50
  view: 'nested',
47
51
  },
48
52
  };
53
+ exports.NestedCompact = {
54
+ args: {
55
+ source: 'products',
56
+ view: 'nested',
57
+ classes: 'compact',
58
+ },
59
+ };
49
60
  //# sourceMappingURL=tables.stories.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/render",
3
- "version": "0.0.105-dev231124203430",
3
+ "version": "0.0.105-dev231127183208",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,7 +23,8 @@
23
23
  "build-storybook": "storybook build"
24
24
  },
25
25
  "dependencies": {
26
- "@malloydata/malloy": "^0.0.105-dev231124203430",
26
+ "@lit/context": "^1.1.0",
27
+ "@malloydata/malloy": "^0.0.105-dev231127183208",
27
28
  "@types/luxon": "^2.4.0",
28
29
  "lit": "^3.0.2",
29
30
  "lodash": "^4.17.20",