@operato/data-grist 10.29.28 → 10.29.30

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,33 @@
1
+ import '@material/web/icon/icon.js';
2
+ import { LitElement } from 'lit';
3
+ /**
4
+ * A catalog card's picture cell: the picture shown whole on the card's plate, a quiet icon when there is none, and at
5
+ * most one marker in the top-left corner. Board, player, template and figure cards draw it (ADR-0117 amendment
6
+ * 2026-10-13), so a card catalog reads the same in every product.
7
+ *
8
+ * ## Why an element
9
+ *
10
+ * ox-grist's CARD mode draws the picture column through its `record.renderer`, whose output lands inside
11
+ * `ox-card-field`'s shadow root - a page's stylesheet does not reach it. The cell carries its own styles here.
12
+ *
13
+ * - `src`: the picture. Shown with `contain`, never cropped: wide dashboards, tall towers and small popups all sit
14
+ * whole on the plate (`--data-card-thumbnail-background`), so a row of cards lines up.
15
+ * - `icon`: drawn when there is no picture; a slot named `empty` replaces it (a figure's own mark).
16
+ * - `badge` and `tone`: the one thing the card has to say before it is opened (draft, not latest, cannot be read).
17
+ * Nothing is said for the usual state. `tone` is `plain`, `warn` or `crit`.
18
+ * - The default slot is laid over the picture for an action that belongs to it (a figure catalog's delete).
19
+ */
20
+ export declare class OxCardThumb extends LitElement {
21
+ static styles: import("lit").CSSResult;
22
+ src?: string;
23
+ alt: string;
24
+ icon: string;
25
+ badge?: string;
26
+ tone: 'plain' | 'warn' | 'crit';
27
+ render(): import("lit-html").TemplateResult<1>;
28
+ }
29
+ declare global {
30
+ interface HTMLElementTagNameMap {
31
+ 'ox-card-thumb': OxCardThumb;
32
+ }
33
+ }
@@ -0,0 +1,115 @@
1
+ import { __decorate } from "tslib";
2
+ import '@material/web/icon/icon.js';
3
+ import { css, html, LitElement, nothing } from 'lit';
4
+ import { customElement, property } from 'lit/decorators.js';
5
+ /**
6
+ * A catalog card's picture cell: the picture shown whole on the card's plate, a quiet icon when there is none, and at
7
+ * most one marker in the top-left corner. Board, player, template and figure cards draw it (ADR-0117 amendment
8
+ * 2026-10-13), so a card catalog reads the same in every product.
9
+ *
10
+ * ## Why an element
11
+ *
12
+ * ox-grist's CARD mode draws the picture column through its `record.renderer`, whose output lands inside
13
+ * `ox-card-field`'s shadow root - a page's stylesheet does not reach it. The cell carries its own styles here.
14
+ *
15
+ * - `src`: the picture. Shown with `contain`, never cropped: wide dashboards, tall towers and small popups all sit
16
+ * whole on the plate (`--data-card-thumbnail-background`), so a row of cards lines up.
17
+ * - `icon`: drawn when there is no picture; a slot named `empty` replaces it (a figure's own mark).
18
+ * - `badge` and `tone`: the one thing the card has to say before it is opened (draft, not latest, cannot be read).
19
+ * Nothing is said for the usual state. `tone` is `plain`, `warn` or `crit`.
20
+ * - The default slot is laid over the picture for an action that belongs to it (a figure catalog's delete).
21
+ */
22
+ let OxCardThumb = class OxCardThumb extends LitElement {
23
+ constructor() {
24
+ super(...arguments);
25
+ this.alt = '';
26
+ this.icon = 'image';
27
+ this.tone = 'plain';
28
+ }
29
+ render() {
30
+ return html `
31
+ ${this.src
32
+ ? html `<img src=${this.src} alt=${this.alt} loading="lazy" />`
33
+ : html `<div empty>
34
+ <slot name="empty"><md-icon>${this.icon}</md-icon></slot>
35
+ </div>`}
36
+ ${this.badge ? html `<span badge tone=${this.tone}>${this.badge}</span>` : nothing}
37
+ <slot></slot>
38
+ `;
39
+ }
40
+ };
41
+ OxCardThumb.styles = css `
42
+ :host {
43
+ position: relative;
44
+ display: block;
45
+ width: 100%;
46
+ height: 100%;
47
+ overflow: hidden;
48
+ /* The information area below has no border of its own: this is the seam between picture and text. */
49
+ border-bottom: 1px solid var(--md-sys-color-outline-variant);
50
+ box-sizing: border-box;
51
+ }
52
+
53
+ img {
54
+ display: block;
55
+ width: 100%;
56
+ height: 100%;
57
+ object-fit: contain;
58
+ }
59
+
60
+ [empty] {
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: center;
64
+ width: 100%;
65
+ height: 100%;
66
+ color: var(--md-sys-color-outline);
67
+ }
68
+
69
+ [empty] md-icon {
70
+ --md-icon-size: 28px;
71
+ }
72
+
73
+ [badge] {
74
+ position: absolute;
75
+ top: 6px;
76
+ left: 6px;
77
+ padding: 1px 7px;
78
+ font: var(--label-font, inherit);
79
+ font-size: 0.68rem;
80
+ line-height: 1.5;
81
+ color: var(--md-sys-color-on-secondary-container);
82
+ background-color: var(--md-sys-color-secondary-container);
83
+ border-radius: 4px;
84
+ }
85
+
86
+ [badge][tone='warn'] {
87
+ color: var(--md-sys-color-on-tertiary-container);
88
+ background-color: var(--md-sys-color-tertiary-container);
89
+ }
90
+
91
+ [badge][tone='crit'] {
92
+ color: var(--md-sys-color-on-error-container);
93
+ background-color: var(--md-sys-color-error-container);
94
+ }
95
+ `;
96
+ __decorate([
97
+ property({ type: String })
98
+ ], OxCardThumb.prototype, "src", void 0);
99
+ __decorate([
100
+ property({ type: String })
101
+ ], OxCardThumb.prototype, "alt", void 0);
102
+ __decorate([
103
+ property({ type: String })
104
+ ], OxCardThumb.prototype, "icon", void 0);
105
+ __decorate([
106
+ property({ type: String })
107
+ ], OxCardThumb.prototype, "badge", void 0);
108
+ __decorate([
109
+ property({ type: String })
110
+ ], OxCardThumb.prototype, "tone", void 0);
111
+ OxCardThumb = __decorate([
112
+ customElement('ox-card-thumb')
113
+ ], OxCardThumb);
114
+ export { OxCardThumb };
115
+ //# sourceMappingURL=ox-card-thumb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-card-thumb.js","sourceRoot":"","sources":["../../../src/data-card/ox-card-thumb.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AAEnC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D;;;;;;;;;;;;;;;;GAgBG;AAEI,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,UAAU;IAApC;;QA0DuB,QAAG,GAAG,EAAE,CAAA;QACR,SAAI,GAAG,OAAO,CAAA;QAEd,SAAI,GAA8B,OAAO,CAAA;IAavE,CAAC;IAXC,MAAM;QACJ,OAAO,IAAI,CAAA;QACP,IAAI,CAAC,GAAG;YACR,CAAC,CAAC,IAAI,CAAA,YAAY,IAAI,CAAC,GAAG,QAAQ,IAAI,CAAC,GAAG,oBAAoB;YAC9D,CAAC,CAAC,IAAI,CAAA;0CAC4B,IAAI,CAAC,IAAI;iBAClC;QACT,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA,oBAAoB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO;;KAElF,CAAA;IACH,CAAC;;AAxEM,kBAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDlB,AAtDY,CAsDZ;AAE2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wCAAa;AACZ;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wCAAS;AACR;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;yCAAe;AACd;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0CAAe;AACd;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;yCAA0C;AA7D1D,WAAW;IADvB,aAAa,CAAC,eAAe,CAAC;GAClB,WAAW,CA0EvB","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\n/**\n * A catalog card's picture cell: the picture shown whole on the card's plate, a quiet icon when there is none, and at\n * most one marker in the top-left corner. Board, player, template and figure cards draw it (ADR-0117 amendment\n * 2026-10-13), so a card catalog reads the same in every product.\n *\n * ## Why an element\n *\n * ox-grist's CARD mode draws the picture column through its `record.renderer`, whose output lands inside\n * `ox-card-field`'s shadow root - a page's stylesheet does not reach it. The cell carries its own styles here.\n *\n * - `src`: the picture. Shown with `contain`, never cropped: wide dashboards, tall towers and small popups all sit\n * whole on the plate (`--data-card-thumbnail-background`), so a row of cards lines up.\n * - `icon`: drawn when there is no picture; a slot named `empty` replaces it (a figure's own mark).\n * - `badge` and `tone`: the one thing the card has to say before it is opened (draft, not latest, cannot be read).\n * Nothing is said for the usual state. `tone` is `plain`, `warn` or `crit`.\n * - The default slot is laid over the picture for an action that belongs to it (a figure catalog's delete).\n */\n@customElement('ox-card-thumb')\nexport class OxCardThumb extends LitElement {\n static styles = css`\n :host {\n position: relative;\n display: block;\n width: 100%;\n height: 100%;\n overflow: hidden;\n /* The information area below has no border of its own: this is the seam between picture and text. */\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n box-sizing: border-box;\n }\n\n img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n\n [empty] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n color: var(--md-sys-color-outline);\n }\n\n [empty] md-icon {\n --md-icon-size: 28px;\n }\n\n [badge] {\n position: absolute;\n top: 6px;\n left: 6px;\n padding: 1px 7px;\n font: var(--label-font, inherit);\n font-size: 0.68rem;\n line-height: 1.5;\n color: var(--md-sys-color-on-secondary-container);\n background-color: var(--md-sys-color-secondary-container);\n border-radius: 4px;\n }\n\n [badge][tone='warn'] {\n color: var(--md-sys-color-on-tertiary-container);\n background-color: var(--md-sys-color-tertiary-container);\n }\n\n [badge][tone='crit'] {\n color: var(--md-sys-color-on-error-container);\n background-color: var(--md-sys-color-error-container);\n }\n `\n\n @property({ type: String }) src?: string\n @property({ type: String }) alt = ''\n @property({ type: String }) icon = 'image'\n @property({ type: String }) badge?: string\n @property({ type: String }) tone: 'plain' | 'warn' | 'crit' = 'plain'\n\n render() {\n return html`\n ${this.src\n ? html`<img src=${this.src} alt=${this.alt} loading=\"lazy\" />`\n : html`<div empty>\n <slot name=\"empty\"><md-icon>${this.icon}</md-icon></slot>\n </div>`}\n ${this.badge ? html`<span badge tone=${this.tone}>${this.badge}</span>` : nothing}\n <slot></slot>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ox-card-thumb': OxCardThumb\n }\n}\n"]}
@@ -13,3 +13,4 @@ export * from './record-view/index.js';
13
13
  export * from './personalizer/index.js';
14
14
  export * from './utils/column-text.js';
15
15
  export * from './utils/list-param.js';
16
+ export * from './data-card/ox-card-thumb.js';
package/dist/src/index.js CHANGED
@@ -13,4 +13,5 @@ export * from './record-view/index.js';
13
13
  export * from './personalizer/index.js';
14
14
  export * from './utils/column-text.js';
15
15
  export * from './utils/list-param.js';
16
+ export * from './data-card/ox-card-thumb.js';
16
17
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAE1B,cAAc,4BAA4B,CAAA;AAC1C,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA;AAEhC,cAAc,oBAAoB,CAAA;AAClC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wBAAwB,CAAA;AACtC,cAAc,yBAAyB,CAAA;AAEvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA","sourcesContent":["export * from './types.js'\n\nexport * from './configure/zero-config.js'\nexport * from './data-grist.js'\nexport * from './data-report.js'\n\nexport * from './editors/index.js'\nexport * from './renderers/index.js'\nexport * from './handlers/index.js'\nexport * from './formatters/index.js'\nexport * from './gutters/index.js'\nexport * from './filters/index.js'\nexport * from './sorters/sorters-control.js'\nexport * from './record-view/index.js'\nexport * from './personalizer/index.js'\n\nexport * from './utils/column-text.js'\nexport * from './utils/list-param.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAE1B,cAAc,4BAA4B,CAAA;AAC1C,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA;AAEhC,cAAc,oBAAoB,CAAA;AAClC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wBAAwB,CAAA;AACtC,cAAc,yBAAyB,CAAA;AAEvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,8BAA8B,CAAA","sourcesContent":["export * from './types.js'\n\nexport * from './configure/zero-config.js'\nexport * from './data-grist.js'\nexport * from './data-report.js'\n\nexport * from './editors/index.js'\nexport * from './renderers/index.js'\nexport * from './handlers/index.js'\nexport * from './formatters/index.js'\nexport * from './gutters/index.js'\nexport * from './filters/index.js'\nexport * from './sorters/sorters-control.js'\nexport * from './record-view/index.js'\nexport * from './personalizer/index.js'\n\nexport * from './utils/column-text.js'\nexport * from './utils/list-param.js'\nexport * from './data-card/ox-card-thumb.js'\n"]}
@@ -0,0 +1 @@
1
+ import '../src/data-card/ox-card-thumb.js';
@@ -0,0 +1,44 @@
1
+ import { expect, fixture, html } from '@open-wc/testing';
2
+ import '../src/data-card/ox-card-thumb.js';
3
+ /*
4
+ * The one picture cell of a catalog card (ADR-0117 amendment 2026-10-13): the picture whole, an icon when there is
5
+ * none, at most one marker in the top-left corner, and a seam under it.
6
+ */
7
+ describe('ox-card-thumb', () => {
8
+ it('★ shows the picture whole, never cropped, with a seam under it', async () => {
9
+ const thumb = await fixture(html `<ox-card-thumb
10
+ style="--md-sys-color-outline-variant: rgb(200, 200, 200)"
11
+ src="data:image/gif;base64,R0lGODlhAQABAAAAACw="
12
+ alt="a board"
13
+ ></ox-card-thumb>`);
14
+ const img = thumb.shadowRoot.querySelector('img');
15
+ expect(img.getAttribute('alt')).to.equal('a board');
16
+ expect(getComputedStyle(img).objectFit).to.equal('contain');
17
+ expect(getComputedStyle(thumb).borderBottomStyle).to.equal('solid');
18
+ expect(thumb.shadowRoot.querySelector('[empty]')).to.equal(null);
19
+ });
20
+ it('★ draws its icon when there is no picture, or the empty slot when one is given', async () => {
21
+ const bare = await fixture(html `<ox-card-thumb icon="dashboard"></ox-card-thumb>`);
22
+ expect(bare.shadowRoot.querySelector('[empty] md-icon').textContent).to.equal('dashboard');
23
+ const marked = await fixture(html `<ox-card-thumb><span slot="empty" id="mark">no picture</span></ox-card-thumb>`);
24
+ const slot = marked.shadowRoot.querySelector('slot[name="empty"]');
25
+ expect(slot.assignedElements().map(e => e.id)).to.deep.equal(['mark']);
26
+ });
27
+ it('★ says one thing in the corner, in its tone, and nothing when there is nothing to say', async () => {
28
+ const quiet = await fixture(html `<ox-card-thumb></ox-card-thumb>`);
29
+ expect(quiet.shadowRoot.querySelector('[badge]')).to.equal(null);
30
+ const warned = await fixture(html `<ox-card-thumb badge="not latest" tone="warn"></ox-card-thumb>`);
31
+ const badge = warned.shadowRoot.querySelector('[badge]');
32
+ expect(badge.textContent).to.equal('not latest');
33
+ expect(badge.getAttribute('tone')).to.equal('warn');
34
+ expect(getComputedStyle(badge).position).to.equal('absolute');
35
+ expect(getComputedStyle(badge).top).to.equal('6px');
36
+ expect(getComputedStyle(badge).left).to.equal('6px');
37
+ });
38
+ it('lays the default slot over the picture for an action that belongs to it', async () => {
39
+ const thumb = await fixture(html `<ox-card-thumb><button id="del">x</button></ox-card-thumb>`);
40
+ const slot = thumb.shadowRoot.querySelector('slot:not([name])');
41
+ expect(slot.assignedElements().map(e => e.id)).to.deep.equal(['del']);
42
+ });
43
+ });
44
+ //# sourceMappingURL=card-thumb.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-thumb.test.js","sourceRoot":"","sources":["../../test/card-thumb.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, html } from '@open-wc/testing'\n\nimport '../src/data-card/ox-card-thumb.js'\nimport type { OxCardThumb } from '../src/data-card/ox-card-thumb.js'\n\n/*\n * The one picture cell of a catalog card (ADR-0117 amendment 2026-10-13): the picture whole, an icon when there is\n * none, at most one marker in the top-left corner, and a seam under it.\n */\ndescribe('ox-card-thumb', () => {\n it('★ shows the picture whole, never cropped, with a seam under it', async () => {\n const thumb = await fixture<OxCardThumb>(html`<ox-card-thumb\n style=\"--md-sys-color-outline-variant: rgb(200, 200, 200)\"\n src=\"data:image/gif;base64,R0lGODlhAQABAAAAACw=\"\n alt=\"a board\"\n ></ox-card-thumb>`)\n const img = thumb.shadowRoot!.querySelector('img')!\n expect(img.getAttribute('alt')).to.equal('a board')\n expect(getComputedStyle(img).objectFit).to.equal('contain')\n expect(getComputedStyle(thumb).borderBottomStyle).to.equal('solid')\n expect(thumb.shadowRoot!.querySelector('[empty]')).to.equal(null)\n })\n\n it('★ draws its icon when there is no picture, or the empty slot when one is given', async () => {\n const bare = await fixture<OxCardThumb>(html`<ox-card-thumb icon=\"dashboard\"></ox-card-thumb>`)\n expect(bare.shadowRoot!.querySelector('[empty] md-icon')!.textContent).to.equal('dashboard')\n\n const marked = await fixture<OxCardThumb>(html`<ox-card-thumb><span slot=\"empty\" id=\"mark\">no picture</span></ox-card-thumb>`)\n const slot = marked.shadowRoot!.querySelector('slot[name=\"empty\"]') as HTMLSlotElement\n expect(slot.assignedElements().map(e => e.id)).to.deep.equal(['mark'])\n })\n\n it('★ says one thing in the corner, in its tone, and nothing when there is nothing to say', async () => {\n const quiet = await fixture<OxCardThumb>(html`<ox-card-thumb></ox-card-thumb>`)\n expect(quiet.shadowRoot!.querySelector('[badge]')).to.equal(null)\n\n const warned = await fixture<OxCardThumb>(html`<ox-card-thumb badge=\"not latest\" tone=\"warn\"></ox-card-thumb>`)\n const badge = warned.shadowRoot!.querySelector('[badge]') as HTMLElement\n expect(badge.textContent).to.equal('not latest')\n expect(badge.getAttribute('tone')).to.equal('warn')\n expect(getComputedStyle(badge).position).to.equal('absolute')\n expect(getComputedStyle(badge).top).to.equal('6px')\n expect(getComputedStyle(badge).left).to.equal('6px')\n })\n\n it('lays the default slot over the picture for an action that belongs to it', async () => {\n const thumb = await fixture<OxCardThumb>(html`<ox-card-thumb><button id=\"del\">x</button></ox-card-thumb>`)\n const slot = thumb.shadowRoot!.querySelector('slot:not([name])') as HTMLSlotElement\n expect(slot.assignedElements().map(e => e.id)).to.deep.equal(['del'])\n })\n})\n"]}