@operato/styles 10.29.1 → 10.29.9

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@operato/styles",
3
3
  "description": "Webcomponent styles following open-wc recommendations",
4
4
  "author": "heartyoh",
5
- "version": "10.29.1",
5
+ "version": "10.29.9",
6
6
  "type": "module",
7
7
  "main": "dist/src/index.js",
8
8
  "module": "dist/src/index.js",
@@ -30,6 +30,7 @@
30
30
  "./common-button-styles.js": "./dist/src/common-button-styles.js",
31
31
  "./common-grist-styles.js": "./dist/src/common-grist-styles.js",
32
32
  "./button-container-styles.js": "./dist/src/button-container-styles.js",
33
+ "./button-styles.js": "./dist/src/button-styles.js",
33
34
  "./common-header-styles.js": "./dist/src/common-header-styles.js",
34
35
  "./common-popup-styles.js": "./dist/src/common-popup-styles.js",
35
36
  "./line-styles.js": "./dist/src/line-styles.js",
@@ -67,6 +68,9 @@
67
68
  "./common-grist-styles.js": [
68
69
  "./dist/src/common-grist-styles.d.ts"
69
70
  ],
71
+ "./button-styles.js": [
72
+ "./dist/src/button-styles.d.ts"
73
+ ],
70
74
  "./button-container-styles.js": [
71
75
  "./dist/src/button-container-styles.d.ts"
72
76
  ],
@@ -94,6 +98,7 @@
94
98
  "analyze": "cem analyze --litelement",
95
99
  "start": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wds\"",
96
100
  "build": "tsc && npm run analyze -- --exclude dist",
101
+ "test": "tsc && wtr",
97
102
  "prepublishOnly": "tsc && npm run analyze -- --exclude dist",
98
103
  "storybook": "npm run build && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wds -c .storybook/server.mjs\"",
99
104
  "storybook:build": "npm run build && build-storybook"
@@ -122,5 +127,5 @@
122
127
  },
123
128
  "customElements": "custom-elements.json",
124
129
  "prettier": "@hatiolab/prettier-config",
125
- "gitHead": "1ae246813b79645ee00b600bd7f631bacf1a9213"
130
+ "gitHead": "24e4809ab0168eef48792291f72b11f75d8179ad"
126
131
  }
@@ -0,0 +1,180 @@
1
+ import { expect, fixture, html } from '@open-wc/testing'
2
+ import { css, LitElement } from 'lit'
3
+
4
+ import { ButtonContainerStyles } from '../src/button-container-styles.js'
5
+ import { ButtonStyles } from '../src/button-styles.js'
6
+ import { FormFieldStyles } from '../src/form-field-styles.js'
7
+ import { DocumentPageStyles, WorkSurfacePageStyles } from '../src/page-frame-styles.js'
8
+
9
+ /*
10
+ * The ground the page frames lay, and the button and field sizes (operato-application/design/ui/page-standard.md).
11
+ *
12
+ * What these stand on: a screen that forgot to set a value used to fall to the browser default -
13
+ * 16px body text, rgb(0 0 238) links, Korean broken mid-word, cards wider than their header. The
14
+ * frame now lays the value; a screen that says otherwise still wins. Measured on rendered elements,
15
+ * not on the stylesheet text.
16
+ *
17
+ * The tokens are defined here because a test page has no shell theme.
18
+ */
19
+ const TOKENS = css`
20
+ :host {
21
+ --ui-t-body: 13px;
22
+ --ui-ink: rgb(27, 27, 27);
23
+ --ui-accent: rgb(0, 114, 126);
24
+ --ui-gutter: 16px;
25
+ --context-action-height: 32px;
26
+ --cell-action-height: 26px;
27
+ --form-element-height-medium: 32px;
28
+ --form-element-height-small: 26px;
29
+ --md-sys-color-primary: rgb(0, 114, 126);
30
+ --md-sys-color-surface-container-lowest: rgb(255, 255, 255);
31
+ }
32
+ `
33
+
34
+ class DocumentProbe extends LitElement {
35
+ static styles = [DocumentPageStyles, ButtonStyles, FormFieldStyles, TOKENS]
36
+ render() {
37
+ return html`
38
+ <div class="page">
39
+ <section class="page-section">
40
+ <p class="page-section-note">note</p>
41
+ <div class="page-card" id="card" style="width: 300px; padding: 16px">card</div>
42
+ <span id="text">text</span>
43
+ <a id="thing" href="#a">LOT-1</a>
44
+ <a id="go" class="page-nav-link" href="#b">go</a>
45
+ <div style="display: grid; grid-template-columns: 400px">
46
+ <button id="plain">add</button>
47
+ </div>
48
+ <button id="raised" raised>save</button>
49
+ <button id="small" small>hold</button>
50
+ <input id="field" />
51
+ <input id="small-field" small />
52
+ <textarea id="area"></textarea>
53
+ </section>
54
+ </div>
55
+ `
56
+ }
57
+ }
58
+ customElements.define('document-probe', DocumentProbe)
59
+
60
+ class SurfaceProbe extends LitElement {
61
+ static styles = [WorkSurfacePageStyles, TOKENS]
62
+ render() {
63
+ return html`<div class="page-headroom"><span>range</span></div>`
64
+ }
65
+ }
66
+ customElements.define('surface-probe', SurfaceProbe)
67
+
68
+ class OwnRuleProbe extends LitElement {
69
+ static styles = [
70
+ DocumentPageStyles,
71
+ ButtonStyles,
72
+ TOKENS,
73
+ css`
74
+ :host {
75
+ font-size: 15px;
76
+ }
77
+ button {
78
+ height: 48px;
79
+ }
80
+ a {
81
+ color: rgb(255, 0, 0);
82
+ }
83
+ `
84
+ ]
85
+ render() {
86
+ return html`<span id="text">t</span><button id="own">x</button><a id="a" href="#">a</a>`
87
+ }
88
+ }
89
+ customElements.define('own-rule-probe', OwnRuleProbe)
90
+
91
+ const style = (el: Element) => getComputedStyle(el)
92
+
93
+ describe('page frame ground', () => {
94
+ it('body text is the body token, not the browser 16px', async () => {
95
+ const el = (await fixture(html`<document-probe></document-probe>`)) as DocumentProbe
96
+ expect(style(el.shadowRoot!.querySelector('#text')!).fontSize).to.equal('13px')
97
+ })
98
+
99
+ it('a link to a thing reads as text; a link to a screen takes the accent; neither underlines at rest', async () => {
100
+ const el = (await fixture(html`<document-probe></document-probe>`)) as DocumentProbe
101
+ const thing = style(el.shadowRoot!.querySelector('#thing')!)
102
+ const go = style(el.shadowRoot!.querySelector('#go')!)
103
+ expect(thing.color).to.equal('rgb(27, 27, 27)')
104
+ expect(thing.textDecorationLine).to.equal('none')
105
+ expect(go.color).to.equal('rgb(0, 114, 126)')
106
+ })
107
+
108
+ it('Korean wraps at words, and a word with no break point still breaks', async () => {
109
+ const el = (await fixture(html`<document-probe></document-probe>`)) as DocumentProbe
110
+ const text = style(el.shadowRoot!.querySelector('#text')!)
111
+ expect(text.wordBreak).to.equal('keep-all')
112
+ expect(text.overflowWrap).to.equal('anywhere')
113
+ })
114
+
115
+ it('padding stays inside the width (a card is not wider than it was told)', async () => {
116
+ const el = (await fixture(html`<document-probe></document-probe>`)) as DocumentProbe
117
+ expect(el.shadowRoot!.querySelector('#card')!.getBoundingClientRect().width).to.equal(300)
118
+ })
119
+
120
+ it('the document column is not held to 1080px, and its side gutters are equal', async () => {
121
+ const el = (await fixture(html`<document-probe style="display: block; width: 1600px"></document-probe>`)) as DocumentProbe
122
+ const page = el.shadowRoot!.querySelector('.page')!
123
+ expect(style(page).maxWidth).to.equal('none')
124
+ expect(page.getBoundingClientRect().width).to.equal(1600)
125
+ expect(style(page).paddingLeft).to.equal('16px')
126
+ expect(style(page).paddingRight).to.equal('16px')
127
+ })
128
+
129
+ it('the work surface headroom uses the same gutter', async () => {
130
+ const el = (await fixture(html`<surface-probe></surface-probe>`)) as SurfaceProbe
131
+ expect(style(el.shadowRoot!.querySelector('.page-headroom')!).paddingLeft).to.equal('16px')
132
+ })
133
+
134
+ it("a screen's own rule still wins over the ground", async () => {
135
+ const el = (await fixture(html`<own-rule-probe></own-rule-probe>`)) as OwnRuleProbe
136
+ expect(style(el.shadowRoot!.querySelector('#text')!).fontSize).to.equal('15px')
137
+ expect(style(el.shadowRoot!.querySelector('#own')!).height).to.equal('48px')
138
+ expect(style(el.shadowRoot!.querySelector('#a')!).color).to.equal('rgb(255, 0, 0)')
139
+ })
140
+ })
141
+
142
+ describe('buttons and fields', () => {
143
+ it('a button is as tall as its place and as wide as its label - it does not stretch to a grid track', async () => {
144
+ const el = (await fixture(html`<document-probe></document-probe>`)) as DocumentProbe
145
+ const plain = el.shadowRoot!.querySelector('#plain')!
146
+ expect(style(plain).height).to.equal('32px')
147
+ expect(style(plain).fontSize).to.equal('13px')
148
+ expect(style(plain).fontWeight).to.equal('600')
149
+ expect(plain.getBoundingClientRect().width).to.be.below(100)
150
+ expect(style(el.shadowRoot!.querySelector('#small')!).height).to.equal('26px')
151
+ })
152
+
153
+ it('a raised button is filled, a plain one is not', async () => {
154
+ const el = (await fixture(html`<document-probe></document-probe>`)) as DocumentProbe
155
+ const raised = style(el.shadowRoot!.querySelector('#raised')!).backgroundColor
156
+ const plain = style(el.shadowRoot!.querySelector('#plain')!).backgroundColor
157
+ expect(raised).to.not.equal(plain)
158
+ })
159
+
160
+ it('one-line fields take the form height; a small one the cell height; a textarea keeps its own', async () => {
161
+ const el = (await fixture(html`<document-probe></document-probe>`)) as DocumentProbe
162
+ expect(style(el.shadowRoot!.querySelector('#field')!).height).to.equal('32px')
163
+ expect(style(el.shadowRoot!.querySelector('#small-field')!).height).to.equal('26px')
164
+ expect(style(el.shadowRoot!.querySelector('#area')!).height).to.not.equal('32px')
165
+ })
166
+ })
167
+
168
+ describe('ButtonContainerStyles', () => {
169
+ /*
170
+ * dssp draws 26 of its own pages with this block. ButtonStyles was taken out next to it, not out of
171
+ * it: the CSS this block emits must stay byte for byte what 10.29.1 published.
172
+ * sha-256 of ButtonContainerStyles.cssText in the published 10.29.1 (2026-10-05).
173
+ */
174
+ it('emits the same CSS as the published 10.29.1', async () => {
175
+ const bytes = new TextEncoder().encode(ButtonContainerStyles.cssText)
176
+ const digest = await crypto.subtle.digest('SHA-256', bytes)
177
+ const hex = [...new Uint8Array(digest)].map(b => b.toString(16).padStart(2, '0')).join('')
178
+ expect(hex).to.equal('bcab002afc1a4521cd7da312cacba2bcd594cfe0e3dcd6c1d62a388adfd25203')
179
+ })
180
+ })