@operato/data-grist 10.29.4 → 10.29.6
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/CHANGELOG.md +17 -0
- package/coverage/lcov-report/index.html +40 -40
- package/coverage/lcov-report/webpack/bootstrap.html +1 -1
- package/coverage/lcov-report/webpack/index.html +1 -1
- package/coverage/lcov-report/webpack/runtime/define property getters.html +1 -1
- package/coverage/lcov-report/webpack/runtime/global.html +1 -1
- package/coverage/lcov-report/webpack/runtime/hasOwnProperty shorthand.html +1 -1
- package/coverage/lcov-report/webpack/runtime/index.html +1 -1
- package/coverage/lcov-report/webpack/runtime/make namespace object.html +1 -1
- package/coverage/lcov.info +30482 -30377
- package/dist/src/data-card/data-card-field.js +3 -0
- package/dist/src/data-card/data-card-field.js.map +1 -1
- package/dist/src/data-grid/data-grid-accum-field.js +4 -0
- package/dist/src/data-grid/data-grid-accum-field.js.map +1 -1
- package/dist/src/data-grid/data-grid-field.d.ts +1 -0
- package/dist/src/data-grid/data-grid-field.js +29 -1
- package/dist/src/data-grid/data-grid-field.js.map +1 -1
- package/dist/test/field-contains-content.test.d.ts +1 -0
- package/dist/test/field-contains-content.test.js +98 -0
- package/dist/test/field-contains-content.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/test/field-contains-content.test.ts +120 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@operato/data-grist",
|
|
3
|
-
"version": "10.29.
|
|
3
|
+
"version": "10.29.6",
|
|
4
4
|
"description": "User interface for grid (desktop) and list (mobile)",
|
|
5
5
|
"author": "heartyoh",
|
|
6
6
|
"type": "module",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@operato/i18n": "^10.29.1",
|
|
73
73
|
"@operato/input": "^10.29.1",
|
|
74
74
|
"@operato/list-state": "^10.29.1",
|
|
75
|
-
"@operato/p13n": "^10.29.
|
|
75
|
+
"@operato/p13n": "^10.29.5",
|
|
76
76
|
"@operato/popup": "^10.29.1",
|
|
77
77
|
"@operato/pull-to-refresh": "^10.29.1",
|
|
78
78
|
"@operato/styles": "^10.29.1",
|
|
@@ -116,5 +116,5 @@
|
|
|
116
116
|
"prettier --write"
|
|
117
117
|
]
|
|
118
118
|
},
|
|
119
|
-
"gitHead": "
|
|
119
|
+
"gitHead": "4ce15fe4cf60d6bb6810ec86f5eb9839298001a2"
|
|
120
120
|
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* Elements are compared by presence, not by value: a failing element comparison makes chai render the DOM and hang the runner. */
|
|
2
|
+
import { expect, fixture } from '@open-wc/testing'
|
|
3
|
+
import { html } from 'lit'
|
|
4
|
+
|
|
5
|
+
import '../src/data-grist.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A cell keeps what its renderer draws inside its column.
|
|
9
|
+
*
|
|
10
|
+
* `FieldRenderer` may return a plain string, and the cell rendered it as a bare text node. Only
|
|
11
|
+
* `span` and `pre` were clipped, so a long string — or an `<a>` — spilled past its track. The body's
|
|
12
|
+
* scrollWidth grew past the header's (the header is just the sum of the column widths): at the far
|
|
13
|
+
* right the header stopped while the body kept scrolling, and stray text showed where there were no
|
|
14
|
+
* columns.
|
|
15
|
+
*
|
|
16
|
+
* [measured] operato-office contract list — body 5503 / header 3830 (2026-10-04)
|
|
17
|
+
*
|
|
18
|
+
* The long cells sit in the last column, because only content that runs past the last track widens
|
|
19
|
+
* the body; in a middle column the next cell paints over it and the defect hides.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const LONG = '긴 글자가 열 너비를 넘는다 '.repeat(40)
|
|
23
|
+
|
|
24
|
+
const settle = (ms = 150) => new Promise(resolve => setTimeout(resolve, ms))
|
|
25
|
+
|
|
26
|
+
type Root = HTMLElement & { renderRoot: ShadowRoot; updateComplete: Promise<unknown> }
|
|
27
|
+
|
|
28
|
+
async function grid(renderer: (value: unknown) => unknown) {
|
|
29
|
+
const config = {
|
|
30
|
+
columns: [
|
|
31
|
+
{ type: 'string', name: 'id', hidden: true },
|
|
32
|
+
{ type: 'string', name: 'name', header: 'name', width: 120 },
|
|
33
|
+
{ type: 'string', name: 'note', header: 'note', width: 160, record: { renderer } }
|
|
34
|
+
],
|
|
35
|
+
pagination: { pages: [20] }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const el = (await fixture(html`
|
|
39
|
+
<ox-grist
|
|
40
|
+
style="width: 400px; height: 300px"
|
|
41
|
+
mode="GRID"
|
|
42
|
+
.config=${config}
|
|
43
|
+
.fetchHandler=${async () => ({
|
|
44
|
+
total: 2,
|
|
45
|
+
records: [
|
|
46
|
+
{ id: '1', name: 'a', note: LONG },
|
|
47
|
+
{ id: '2', name: 'b', note: LONG }
|
|
48
|
+
]
|
|
49
|
+
})}
|
|
50
|
+
></ox-grist>
|
|
51
|
+
`)) as Root & { fetch(): Promise<void> }
|
|
52
|
+
|
|
53
|
+
await el.fetch()
|
|
54
|
+
await settle()
|
|
55
|
+
await el.updateComplete
|
|
56
|
+
|
|
57
|
+
const grist = el.renderRoot.querySelector('#grist') as Root
|
|
58
|
+
const header = grist.renderRoot.querySelector('ox-grid-header') as Root
|
|
59
|
+
const body = grist.renderRoot.querySelector('ox-grid-body') as Root
|
|
60
|
+
await body.updateComplete
|
|
61
|
+
|
|
62
|
+
const notes = Array.from(body.renderRoot.querySelectorAll('ox-grid-field')).filter(
|
|
63
|
+
f => (f as any).column?.name === 'note'
|
|
64
|
+
) as Root[]
|
|
65
|
+
|
|
66
|
+
return { header, body, notes }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
describe('a grid cell keeps its content inside its column', () => {
|
|
70
|
+
/* Resizing the grid body inside a fixture trips Chrome's benign "ResizeObserver loop" error. */
|
|
71
|
+
const ignoreResizeLoop = (e: ErrorEvent) => {
|
|
72
|
+
if (String(e.message).includes('ResizeObserver loop')) {
|
|
73
|
+
e.stopImmediatePropagation()
|
|
74
|
+
e.preventDefault()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
let previousOnError: OnErrorEventHandler = null
|
|
78
|
+
before(() => {
|
|
79
|
+
window.addEventListener('error', ignoreResizeLoop, true)
|
|
80
|
+
previousOnError = window.onerror
|
|
81
|
+
window.onerror = (message, ...rest) =>
|
|
82
|
+
String(message).includes('ResizeObserver loop') ? true : previousOnError?.call(window, message, ...rest)
|
|
83
|
+
})
|
|
84
|
+
after(() => {
|
|
85
|
+
window.removeEventListener('error', ignoreResizeLoop, true)
|
|
86
|
+
window.onerror = previousOnError
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const renderers: [string, (value: unknown) => unknown][] = [
|
|
90
|
+
['a plain string', value => String(value)],
|
|
91
|
+
['an <a>', value => html`<a href="#">${value}</a>`]
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
for (const [kind, renderer] of renderers) {
|
|
95
|
+
it(`${kind}: the body scrolls exactly as far as the header`, async () => {
|
|
96
|
+
const { header, body, notes } = await grid(renderer)
|
|
97
|
+
|
|
98
|
+
expect(notes.length, 'the long cells must be drawn, or this measures nothing').to.be.at.least(2)
|
|
99
|
+
expect(body.scrollWidth, 'content past the last column widens only the body').to.equal(header.scrollWidth)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it(`${kind}: the cell is as wide as its column and clips what does not fit`, async () => {
|
|
103
|
+
const { notes } = await grid(renderer)
|
|
104
|
+
|
|
105
|
+
for (const note of notes) {
|
|
106
|
+
expect(Math.round(note.getBoundingClientRect().width)).to.equal(160)
|
|
107
|
+
expect(getComputedStyle(note).overflowX).to.equal('hidden')
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
it('a plain string still ends in an ellipsis', async () => {
|
|
113
|
+
const { notes } = await grid(value => String(value))
|
|
114
|
+
|
|
115
|
+
const text = notes[0].renderRoot.querySelector('span') as HTMLElement | null
|
|
116
|
+
expect(!!text, 'the string sits in a box that can take text-overflow').to.equal(true)
|
|
117
|
+
expect(getComputedStyle(text!).textOverflow).to.equal('ellipsis')
|
|
118
|
+
expect(text!.clientWidth).to.be.lessThan(160)
|
|
119
|
+
})
|
|
120
|
+
})
|