@fusion.dev/helix-core 0.139.0 → 0.140.0
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/custom-elements.json +229 -2
- package/dist/controllers/fullscreen-controller/fullscreen-controller.js +7 -1
- package/dist/controllers/virtualize-controller/virtualize-controller.js +11 -5
- package/dist/helix-element/helix-element.d.ts +5 -0
- package/dist/helix-element/helix-element.js +12 -0
- package/dist/helix-element/react-bridge.js +27 -9
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/utils/custom-element/custom-element.js +10 -5
- package/dist/utils/report-render/report-render.d.ts +28 -0
- package/dist/utils/report-render/report-render.js +18 -0
- package/dist/utils/report-runtime/report-runtime.d.ts +97 -0
- package/dist/utils/report-runtime/report-runtime.js +35 -0
- package/dist/utils/tell-disclosure/tell-disclosure.js +10 -5
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
package/custom-elements.json
CHANGED
|
@@ -5358,6 +5358,17 @@
|
|
|
5358
5358
|
}
|
|
5359
5359
|
],
|
|
5360
5360
|
"description": "Prepends the shadow-root reset to every subclass's styles, so no component\nhas to remember to include it."
|
|
5361
|
+
},
|
|
5362
|
+
{
|
|
5363
|
+
"kind": "method",
|
|
5364
|
+
"name": "performUpdate",
|
|
5365
|
+
"privacy": "protected",
|
|
5366
|
+
"return": {
|
|
5367
|
+
"type": {
|
|
5368
|
+
"text": "void"
|
|
5369
|
+
}
|
|
5370
|
+
},
|
|
5371
|
+
"description": "The first update, timed where a page asked to measure what the components\ncost, and a property read where it did not: see `reportRender`."
|
|
5361
5372
|
}
|
|
5362
5373
|
],
|
|
5363
5374
|
"events": [],
|
|
@@ -6032,6 +6043,21 @@
|
|
|
6032
6043
|
"name": "HelixElement",
|
|
6033
6044
|
"module": "src/helix-element/helix-element.ts"
|
|
6034
6045
|
}
|
|
6046
|
+
},
|
|
6047
|
+
{
|
|
6048
|
+
"kind": "method",
|
|
6049
|
+
"name": "performUpdate",
|
|
6050
|
+
"privacy": "protected",
|
|
6051
|
+
"return": {
|
|
6052
|
+
"type": {
|
|
6053
|
+
"text": "void"
|
|
6054
|
+
}
|
|
6055
|
+
},
|
|
6056
|
+
"description": "The first update, timed where a page asked to measure what the components\ncost, and a property read where it did not: see `reportRender`.",
|
|
6057
|
+
"inheritedFrom": {
|
|
6058
|
+
"name": "HelixElement",
|
|
6059
|
+
"module": "src/helix-element/helix-element.ts"
|
|
6060
|
+
}
|
|
6035
6061
|
}
|
|
6036
6062
|
],
|
|
6037
6063
|
"events": [],
|
|
@@ -8078,6 +8104,70 @@
|
|
|
8078
8104
|
"module": "./utils/relative-time/relative-time.js"
|
|
8079
8105
|
}
|
|
8080
8106
|
},
|
|
8107
|
+
{
|
|
8108
|
+
"kind": "js",
|
|
8109
|
+
"name": "measuring",
|
|
8110
|
+
"declaration": {
|
|
8111
|
+
"name": "measuring",
|
|
8112
|
+
"module": "./utils/report-render/report-render.js"
|
|
8113
|
+
}
|
|
8114
|
+
},
|
|
8115
|
+
{
|
|
8116
|
+
"kind": "js",
|
|
8117
|
+
"name": "RENDER_SLOT",
|
|
8118
|
+
"declaration": {
|
|
8119
|
+
"name": "RENDER_SLOT",
|
|
8120
|
+
"module": "./utils/report-render/report-render.js"
|
|
8121
|
+
}
|
|
8122
|
+
},
|
|
8123
|
+
{
|
|
8124
|
+
"kind": "js",
|
|
8125
|
+
"name": "reportRender",
|
|
8126
|
+
"declaration": {
|
|
8127
|
+
"name": "reportRender",
|
|
8128
|
+
"module": "./utils/report-render/report-render.js"
|
|
8129
|
+
}
|
|
8130
|
+
},
|
|
8131
|
+
{
|
|
8132
|
+
"kind": "js",
|
|
8133
|
+
"name": "RUNTIME_LOG",
|
|
8134
|
+
"declaration": {
|
|
8135
|
+
"name": "RUNTIME_LOG",
|
|
8136
|
+
"module": "./utils/report-runtime/report-runtime.js"
|
|
8137
|
+
}
|
|
8138
|
+
},
|
|
8139
|
+
{
|
|
8140
|
+
"kind": "js",
|
|
8141
|
+
"name": "RUNTIME_SLOT",
|
|
8142
|
+
"declaration": {
|
|
8143
|
+
"name": "RUNTIME_SLOT",
|
|
8144
|
+
"module": "./utils/report-runtime/report-runtime.js"
|
|
8145
|
+
}
|
|
8146
|
+
},
|
|
8147
|
+
{
|
|
8148
|
+
"kind": "js",
|
|
8149
|
+
"name": "RuntimeEvent",
|
|
8150
|
+
"declaration": {
|
|
8151
|
+
"name": "RuntimeEvent",
|
|
8152
|
+
"module": "./utils/report-runtime/report-runtime.js"
|
|
8153
|
+
}
|
|
8154
|
+
},
|
|
8155
|
+
{
|
|
8156
|
+
"kind": "js",
|
|
8157
|
+
"name": "RuntimeKind",
|
|
8158
|
+
"declaration": {
|
|
8159
|
+
"name": "RuntimeKind",
|
|
8160
|
+
"module": "./utils/report-runtime/report-runtime.js"
|
|
8161
|
+
}
|
|
8162
|
+
},
|
|
8163
|
+
{
|
|
8164
|
+
"kind": "js",
|
|
8165
|
+
"name": "reportRuntime",
|
|
8166
|
+
"declaration": {
|
|
8167
|
+
"name": "reportRuntime",
|
|
8168
|
+
"module": "./utils/report-runtime/report-runtime.js"
|
|
8169
|
+
}
|
|
8170
|
+
},
|
|
8081
8171
|
{
|
|
8082
8172
|
"kind": "js",
|
|
8083
8173
|
"name": "noteVersion",
|
|
@@ -14352,6 +14442,143 @@
|
|
|
14352
14442
|
}
|
|
14353
14443
|
]
|
|
14354
14444
|
},
|
|
14445
|
+
{
|
|
14446
|
+
"kind": "javascript-module",
|
|
14447
|
+
"path": "src/utils/report-render/report-render.ts",
|
|
14448
|
+
"declarations": [
|
|
14449
|
+
{
|
|
14450
|
+
"kind": "variable",
|
|
14451
|
+
"name": "RENDER_SLOT",
|
|
14452
|
+
"description": "The key the listener is kept under. `@fusion.dev/helix-diagnostics` names the same string."
|
|
14453
|
+
},
|
|
14454
|
+
{
|
|
14455
|
+
"kind": "function",
|
|
14456
|
+
"name": "measuring",
|
|
14457
|
+
"return": {
|
|
14458
|
+
"type": {
|
|
14459
|
+
"text": "boolean"
|
|
14460
|
+
}
|
|
14461
|
+
},
|
|
14462
|
+
"description": "Whether anything is measuring, read before each first update."
|
|
14463
|
+
},
|
|
14464
|
+
{
|
|
14465
|
+
"kind": "function",
|
|
14466
|
+
"name": "reportRender",
|
|
14467
|
+
"return": {
|
|
14468
|
+
"type": {
|
|
14469
|
+
"text": "void"
|
|
14470
|
+
}
|
|
14471
|
+
},
|
|
14472
|
+
"parameters": [
|
|
14473
|
+
{
|
|
14474
|
+
"name": "element",
|
|
14475
|
+
"type": {
|
|
14476
|
+
"text": "HTMLElement"
|
|
14477
|
+
}
|
|
14478
|
+
},
|
|
14479
|
+
{
|
|
14480
|
+
"name": "start",
|
|
14481
|
+
"type": {
|
|
14482
|
+
"text": "number"
|
|
14483
|
+
}
|
|
14484
|
+
},
|
|
14485
|
+
{
|
|
14486
|
+
"name": "duration",
|
|
14487
|
+
"type": {
|
|
14488
|
+
"text": "number"
|
|
14489
|
+
}
|
|
14490
|
+
}
|
|
14491
|
+
],
|
|
14492
|
+
"description": "Tells the listener, where there is one, how long `element`'s first update\ntook: from `start`, on the `performance.now()` clock, for `duration`\nmilliseconds.\n\n**A listener that throws never breaks the element.** The error is printed\nonce."
|
|
14493
|
+
}
|
|
14494
|
+
],
|
|
14495
|
+
"exports": [
|
|
14496
|
+
{
|
|
14497
|
+
"kind": "js",
|
|
14498
|
+
"name": "RENDER_SLOT",
|
|
14499
|
+
"declaration": {
|
|
14500
|
+
"name": "RENDER_SLOT",
|
|
14501
|
+
"module": "src/utils/report-render/report-render.ts"
|
|
14502
|
+
}
|
|
14503
|
+
},
|
|
14504
|
+
{
|
|
14505
|
+
"kind": "js",
|
|
14506
|
+
"name": "measuring",
|
|
14507
|
+
"declaration": {
|
|
14508
|
+
"name": "measuring",
|
|
14509
|
+
"module": "src/utils/report-render/report-render.ts"
|
|
14510
|
+
}
|
|
14511
|
+
},
|
|
14512
|
+
{
|
|
14513
|
+
"kind": "js",
|
|
14514
|
+
"name": "reportRender",
|
|
14515
|
+
"declaration": {
|
|
14516
|
+
"name": "reportRender",
|
|
14517
|
+
"module": "src/utils/report-render/report-render.ts"
|
|
14518
|
+
}
|
|
14519
|
+
}
|
|
14520
|
+
]
|
|
14521
|
+
},
|
|
14522
|
+
{
|
|
14523
|
+
"kind": "javascript-module",
|
|
14524
|
+
"path": "src/utils/report-runtime/report-runtime.ts",
|
|
14525
|
+
"declarations": [
|
|
14526
|
+
{
|
|
14527
|
+
"kind": "variable",
|
|
14528
|
+
"name": "RUNTIME_SLOT",
|
|
14529
|
+
"description": "The key the listener is kept under. `@fusion.dev/helix-diagnostics` names\nthe same string.\n\nThe listener returns `true` when it prints the event in its own place, and\nthen the console line here is not printed."
|
|
14530
|
+
},
|
|
14531
|
+
{
|
|
14532
|
+
"kind": "variable",
|
|
14533
|
+
"name": "RUNTIME_LOG",
|
|
14534
|
+
"description": "The key the events reported so far are kept under, for a listener that starts late."
|
|
14535
|
+
},
|
|
14536
|
+
{
|
|
14537
|
+
"kind": "function",
|
|
14538
|
+
"name": "reportRuntime",
|
|
14539
|
+
"return": {
|
|
14540
|
+
"type": {
|
|
14541
|
+
"text": "void"
|
|
14542
|
+
}
|
|
14543
|
+
},
|
|
14544
|
+
"parameters": [
|
|
14545
|
+
{
|
|
14546
|
+
"name": "event",
|
|
14547
|
+
"type": {
|
|
14548
|
+
"text": "RuntimeEvent"
|
|
14549
|
+
}
|
|
14550
|
+
}
|
|
14551
|
+
],
|
|
14552
|
+
"description": "Reports one event: to the log, to the listener where there is one, and to\nthe console unless the listener prints it itself.\n\n**A listener that throws never stops the report.** The error is printed\nonce, and the event is printed as if nothing listened."
|
|
14553
|
+
}
|
|
14554
|
+
],
|
|
14555
|
+
"exports": [
|
|
14556
|
+
{
|
|
14557
|
+
"kind": "js",
|
|
14558
|
+
"name": "RUNTIME_SLOT",
|
|
14559
|
+
"declaration": {
|
|
14560
|
+
"name": "RUNTIME_SLOT",
|
|
14561
|
+
"module": "src/utils/report-runtime/report-runtime.ts"
|
|
14562
|
+
}
|
|
14563
|
+
},
|
|
14564
|
+
{
|
|
14565
|
+
"kind": "js",
|
|
14566
|
+
"name": "RUNTIME_LOG",
|
|
14567
|
+
"declaration": {
|
|
14568
|
+
"name": "RUNTIME_LOG",
|
|
14569
|
+
"module": "src/utils/report-runtime/report-runtime.ts"
|
|
14570
|
+
}
|
|
14571
|
+
},
|
|
14572
|
+
{
|
|
14573
|
+
"kind": "js",
|
|
14574
|
+
"name": "reportRuntime",
|
|
14575
|
+
"declaration": {
|
|
14576
|
+
"name": "reportRuntime",
|
|
14577
|
+
"module": "src/utils/report-runtime/report-runtime.ts"
|
|
14578
|
+
}
|
|
14579
|
+
}
|
|
14580
|
+
]
|
|
14581
|
+
},
|
|
14355
14582
|
{
|
|
14356
14583
|
"kind": "javascript-module",
|
|
14357
14584
|
"path": "src/utils/report-usage/report-usage.ts",
|
|
@@ -15455,7 +15682,7 @@
|
|
|
15455
15682
|
"type": {
|
|
15456
15683
|
"text": "string"
|
|
15457
15684
|
},
|
|
15458
|
-
"default": "'0.
|
|
15685
|
+
"default": "'0.140.0'",
|
|
15459
15686
|
"description": "The version of the package this file ships in.\n\n**Written by `fusion/scripts/version.mjs`** wherever it writes the package's\n`package.json`, and stamped back into the repository beside it after a\nrelease, so the two never disagree; a spec beside this holds them to it.\nNothing else in the running code knows which release it is."
|
|
15460
15687
|
}
|
|
15461
15688
|
],
|
|
@@ -15473,6 +15700,6 @@
|
|
|
15473
15700
|
],
|
|
15474
15701
|
"helix": {
|
|
15475
15702
|
"package": "@fusion.dev/helix-core",
|
|
15476
|
-
"version": "0.
|
|
15703
|
+
"version": "0.140.0"
|
|
15477
15704
|
}
|
|
15478
15705
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { reportRuntime } from '../../utils/report-runtime/report-runtime.js';
|
|
1
2
|
export class FullscreenController {
|
|
2
3
|
constructor(host, report) {
|
|
3
4
|
this.host = host;
|
|
@@ -16,7 +17,12 @@ export class FullscreenController {
|
|
|
16
17
|
await this.host.requestFullscreen();
|
|
17
18
|
}
|
|
18
19
|
catch (error) {
|
|
19
|
-
|
|
20
|
+
reportRuntime({
|
|
21
|
+
detail: error,
|
|
22
|
+
kind: 'fullscreen-refused',
|
|
23
|
+
message: `<${this.host.localName}> could not enter fullscreen. If it is inside an iframe, that frame needs allow="fullscreen".`,
|
|
24
|
+
tag: this.host.localName,
|
|
25
|
+
});
|
|
20
26
|
}
|
|
21
27
|
}
|
|
22
28
|
hostConnected() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { reportRuntime } from '../../utils/report-runtime/report-runtime.js';
|
|
1
2
|
import { Heights } from './heights.js';
|
|
2
3
|
const UNSTABLE = 10;
|
|
3
4
|
export class VirtualizeController {
|
|
@@ -153,10 +154,15 @@ export class VirtualizeController {
|
|
|
153
154
|
return;
|
|
154
155
|
}
|
|
155
156
|
this.warned = true;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
'
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
const host = this.host;
|
|
158
|
+
reportRuntime({
|
|
159
|
+
kind: 'unsettled-window',
|
|
160
|
+
message: `VirtualizeController: the window did not settle in ${UNSTABLE} passes, so it is holding ` +
|
|
161
|
+
'the last one. That happens when the scrolling box has no height of its own: its ' +
|
|
162
|
+
'`clientHeight` is then a function of the rows just drawn, so measuring moves what is ' +
|
|
163
|
+
'being measured and the two never agree. Give the container a block size and an ' +
|
|
164
|
+
'overflow, which is what the styled tier does and what a headless consumer has to.',
|
|
165
|
+
tag: typeof host.localName === 'string' ? host.localName : undefined,
|
|
166
|
+
});
|
|
161
167
|
}
|
|
162
168
|
}
|
|
@@ -274,6 +274,11 @@ export declare class HelixElement extends LitElement {
|
|
|
274
274
|
* has to remember to include it.
|
|
275
275
|
*/
|
|
276
276
|
protected static finalizeStyles(styles?: CSSResultOrNative | CSSResultOrNative[]): CSSResultOrNative[];
|
|
277
|
+
/**
|
|
278
|
+
* The first update, timed where a page asked to measure what the components
|
|
279
|
+
* cost, and a property read where it did not: see `reportRender`.
|
|
280
|
+
*/
|
|
281
|
+
protected performUpdate(): void;
|
|
277
282
|
/**
|
|
278
283
|
* Marks the component's first style resolution as done, so `SETTLED` stops
|
|
279
284
|
* suppressing transitions.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { css, LitElement } from 'lit';
|
|
2
2
|
import { unsafeStatic } from 'lit/static-html.js';
|
|
3
|
+
import { measuring, reportRender } from '../utils/report-render/report-render.js';
|
|
3
4
|
import { noteVersion, reportUsage } from '../utils/report-usage/report-usage.js';
|
|
4
5
|
import { applyReactProperties, auditReactProps, bindReactHandler, reactPropsOf, } from './react-bridge.js';
|
|
5
6
|
const BOX_SIZING = css `
|
|
@@ -113,6 +114,17 @@ export class HelixElement extends LitElement {
|
|
|
113
114
|
static finalizeStyles(styles) {
|
|
114
115
|
return [BOX_SIZING, HIDDEN, SCROLLER, MIRROR, SETTLED, ...LitElement.finalizeStyles(styles)];
|
|
115
116
|
}
|
|
117
|
+
performUpdate() {
|
|
118
|
+
if (this.hasUpdated || !measuring()) {
|
|
119
|
+
super.performUpdate();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const start = performance.now();
|
|
123
|
+
super.performUpdate();
|
|
124
|
+
if (this.hasUpdated) {
|
|
125
|
+
reportRender(this, start, performance.now() - start);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
116
128
|
firstUpdated(changed) {
|
|
117
129
|
super.firstUpdated(changed);
|
|
118
130
|
reportUsage(this);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { eventsForTag } from '../events/element-events.js';
|
|
2
2
|
import { helixEventNames } from '../events/events.js';
|
|
3
|
+
import { reportRuntime } from '../utils/report-runtime/report-runtime.js';
|
|
3
4
|
const REACT_PROPS = '__reactProps$';
|
|
4
5
|
let reactPropsKey;
|
|
5
6
|
export const reactPropsOf = (node) => {
|
|
@@ -22,15 +23,24 @@ export const auditReactProps = (host, props) => {
|
|
|
22
23
|
}
|
|
23
24
|
audited.add(host);
|
|
24
25
|
const tag = host instanceof Element ? `<${host.localName}>` : 'A Helix element';
|
|
26
|
+
const element = host instanceof Element ? host.localName : undefined;
|
|
25
27
|
for (const key of Object.keys(props)) {
|
|
26
28
|
if (key.startsWith('on:')) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
reportRuntime({
|
|
30
|
+
kind: 'solid-handler-syntax',
|
|
31
|
+
message: `${tag} was given \`${key}\`, which is Solid's syntax. React binds the name after \`on\` ` +
|
|
32
|
+
`verbatim, so this listens for an event called \`${key.slice(2)}\`. Write \`on${key.slice(3)}\`.`,
|
|
33
|
+
tag: element,
|
|
34
|
+
});
|
|
29
35
|
continue;
|
|
30
36
|
}
|
|
31
37
|
if (REMOVED.has(key)) {
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
reportRuntime({
|
|
39
|
+
kind: 'removed-callback',
|
|
40
|
+
message: `${tag} was given \`${key}\`, which was removed. It never worked from JSX, because React ` +
|
|
41
|
+
`binds any \`on\` prop as an event of that name. Listen for the element's change event instead.`,
|
|
42
|
+
tag: element,
|
|
43
|
+
});
|
|
34
44
|
continue;
|
|
35
45
|
}
|
|
36
46
|
if (!key.startsWith('on') || !key.includes('-')) {
|
|
@@ -38,15 +48,23 @@ export const auditReactProps = (host, props) => {
|
|
|
38
48
|
}
|
|
39
49
|
const name = key.slice(2);
|
|
40
50
|
if (!helixEventNames.has(name)) {
|
|
41
|
-
|
|
42
|
-
|
|
51
|
+
reportRuntime({
|
|
52
|
+
kind: 'unknown-event',
|
|
53
|
+
message: `${tag} was given \`${key}\`, and nothing dispatches \`${name}\`. TypeScript cannot ` +
|
|
54
|
+
`check a hyphenated JSX prop, so this is the only place it shows up.`,
|
|
55
|
+
tag: element,
|
|
56
|
+
});
|
|
43
57
|
continue;
|
|
44
58
|
}
|
|
45
59
|
const mine = host instanceof Element ? eventsForTag(host.localName) : undefined;
|
|
46
60
|
if (mine && !mine.has(name)) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
61
|
+
reportRuntime({
|
|
62
|
+
kind: 'misplaced-handler',
|
|
63
|
+
message: `${tag} was given \`${key}\`, but it dispatches ${[...mine].map((one) => `\`${one}\``).join(', ')}. ` +
|
|
64
|
+
`\`${name}\` is sent by a different element, and React only wires an \`on\` prop on the ` +
|
|
65
|
+
'element that dispatches, so this handler will never run. Put it on that element.',
|
|
66
|
+
tag: element,
|
|
67
|
+
});
|
|
50
68
|
}
|
|
51
69
|
}
|
|
52
70
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -63,6 +63,8 @@ export { onUnlessFalse } from './utils/on-unless-false/on-unless-false.js';
|
|
|
63
63
|
export { type ColorBytes, readColor } from './utils/read-color/read-color.js';
|
|
64
64
|
export { type Row, type RowCell, readRows, readSeries, type Series, type SeriesPoint, } from './utils/read-series/read-series.js';
|
|
65
65
|
export { type Relative, relativeTime, } from './utils/relative-time/relative-time.js';
|
|
66
|
+
export { measuring, RENDER_SLOT, reportRender } from './utils/report-render/report-render.js';
|
|
67
|
+
export { RUNTIME_LOG, RUNTIME_SLOT, type RuntimeEvent, type RuntimeKind, reportRuntime, } from './utils/report-runtime/report-runtime.js';
|
|
66
68
|
export { noteVersion, reportUsage, USAGE_SLOT, VERSIONS_SLOT, } from './utils/report-usage/report-usage.js';
|
|
67
69
|
export { reportValues } from './utils/report-values/report-values.js';
|
|
68
70
|
export { type ChangeRequestOptions, requestChange, } from './utils/request-change/request-change.js';
|
package/dist/index.js
CHANGED
|
@@ -63,6 +63,8 @@ export { onUnlessFalse } from './utils/on-unless-false/on-unless-false.js';
|
|
|
63
63
|
export { readColor } from './utils/read-color/read-color.js';
|
|
64
64
|
export { readRows, readSeries, } from './utils/read-series/read-series.js';
|
|
65
65
|
export { relativeTime, } from './utils/relative-time/relative-time.js';
|
|
66
|
+
export { measuring, RENDER_SLOT, reportRender } from './utils/report-render/report-render.js';
|
|
67
|
+
export { RUNTIME_LOG, RUNTIME_SLOT, reportRuntime, } from './utils/report-runtime/report-runtime.js';
|
|
66
68
|
export { noteVersion, reportUsage, USAGE_SLOT, VERSIONS_SLOT, } from './utils/report-usage/report-usage.js';
|
|
67
69
|
export { reportValues } from './utils/report-values/report-values.js';
|
|
68
70
|
export { requestChange, } from './utils/request-change/request-change.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { reportRuntime } from '../report-runtime/report-runtime.js';
|
|
1
2
|
const reported = new Set();
|
|
2
3
|
const duplicates = new Set();
|
|
3
4
|
export const duplicateRegistrations = () => [...duplicates];
|
|
@@ -9,11 +10,15 @@ const warnDuplicate = (tagName) => {
|
|
|
9
10
|
}
|
|
10
11
|
reported.add(tagName);
|
|
11
12
|
duplicates.add(tagName);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
reportRuntime({
|
|
14
|
+
kind: 'duplicate-registration',
|
|
15
|
+
message: `<${tagName}> is already registered by a different class, so this page holds two copies of ` +
|
|
16
|
+
'Helix. The first one keeps the tag: every element of this name is built from it, whatever ' +
|
|
17
|
+
'the second copy exports, so `instanceof` against the second copy is false and its fixes are ' +
|
|
18
|
+
'not in the DOM. Two dependencies asking for different versions is the usual cause, and a ' +
|
|
19
|
+
'bundler shipping the same version twice is the other. Deduplicate the dependency.',
|
|
20
|
+
tag: tagName,
|
|
21
|
+
});
|
|
17
22
|
};
|
|
18
23
|
export const customElement = (tagName) => (target) => {
|
|
19
24
|
if (typeof customElements === 'undefined') {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an element's first update is timed, for whoever is measuring what the
|
|
3
|
+
* components cost.
|
|
4
|
+
*
|
|
5
|
+
* **One slot on `globalThis`, under a registered symbol, and empty by
|
|
6
|
+
* default**, as for usage: `@fusion.dev/helix-diagnostics` fills it where a
|
|
7
|
+
* project asked for performance. With nothing in the slot, an element pays one
|
|
8
|
+
* property read before its first update, and takes no time.
|
|
9
|
+
*
|
|
10
|
+
* **The element's own update, from the start of its first update to the end
|
|
11
|
+
* of it**: `willUpdate`, the render, the commit to the DOM, and the hooks
|
|
12
|
+
* after. Timed from its connection, a measure would also count the time it
|
|
13
|
+
* waited behind every element connected before it, so the last of a hundred
|
|
14
|
+
* elements on a page would read as the slowest.
|
|
15
|
+
*/
|
|
16
|
+
/** The key the listener is kept under. `@fusion.dev/helix-diagnostics` names the same string. */
|
|
17
|
+
export declare const RENDER_SLOT: unique symbol;
|
|
18
|
+
/** Whether anything is measuring, read before each first update. */
|
|
19
|
+
export declare const measuring: () => boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Tells the listener, where there is one, how long `element`'s first update
|
|
22
|
+
* took: from `start`, on the `performance.now()` clock, for `duration`
|
|
23
|
+
* milliseconds.
|
|
24
|
+
*
|
|
25
|
+
* **A listener that throws never breaks the element.** The error is printed
|
|
26
|
+
* once.
|
|
27
|
+
*/
|
|
28
|
+
export declare const reportRender: (element: HTMLElement, start: number, duration: number) => void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const RENDER_SLOT = Symbol.for('fusion.dev/helix/render');
|
|
2
|
+
export const measuring = () => typeof globalThis[RENDER_SLOT] === 'function';
|
|
3
|
+
let told = false;
|
|
4
|
+
export const reportRender = (element, start, duration) => {
|
|
5
|
+
const listener = globalThis[RENDER_SLOT];
|
|
6
|
+
if (typeof listener !== 'function') {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
listener(element, { duration, start });
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (!told) {
|
|
14
|
+
told = true;
|
|
15
|
+
console.error('helix: a render listener threw, and the element rendered as usual. Later failures are not printed.', error);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the library says, as it runs, that it was used wrong or could not do
|
|
3
|
+
* what it was asked: one channel for every such warning, in every package.
|
|
4
|
+
*
|
|
5
|
+
* **Each warning is an event with a kind**, stable across versions, so
|
|
6
|
+
* `@fusion.dev/helix-diagnostics` counts it by kind and tag, lists it beside
|
|
7
|
+
* the findings, and sends it where a project's settings say. The sentence
|
|
8
|
+
* prints in the console as it always did, unless the listener prints it in its
|
|
9
|
+
* own place, which a project asks for with `core.warnings: false`.
|
|
10
|
+
*
|
|
11
|
+
* **The same kind of slot on `globalThis` as usage**, under a registered
|
|
12
|
+
* symbol, so every copy of Helix on a page reports to one listener, and
|
|
13
|
+
* diagnostics needs nothing imported from here.
|
|
14
|
+
*
|
|
15
|
+
* **Kept from the start of the page, a few hundred at most**, since the first
|
|
16
|
+
* events happen as the modules load: a tag registered twice is reported before
|
|
17
|
+
* any diagnostics can have started.
|
|
18
|
+
*/
|
|
19
|
+
/** What went wrong, stable across versions, so it can be counted. */
|
|
20
|
+
export type RuntimeKind =
|
|
21
|
+
/** Another class asked for a tag that is already registered: two copies of Helix. */
|
|
22
|
+
'duplicate-registration'
|
|
23
|
+
/** The browser refused fullscreen, usually for a frame without the permission. */
|
|
24
|
+
| 'fullscreen-refused'
|
|
25
|
+
/** An Avatar Group's `max` is past the number the fold is written for. */
|
|
26
|
+
| 'max-past-fold'
|
|
27
|
+
/** A rating's `min` is no score between 0 and its `max`. */
|
|
28
|
+
| 'min-out-of-range'
|
|
29
|
+
/** A React handler prop names an event the element never dispatches itself. */
|
|
30
|
+
| 'misplaced-handler'
|
|
31
|
+
/** The three.js driver could not load its layout, so the notes stay where they started. */
|
|
32
|
+
| 'missing-layout'
|
|
33
|
+
/** A selectable Data Table has no `row-key`, so it knows each row by its place. */
|
|
34
|
+
| 'missing-row-key'
|
|
35
|
+
/** A stencil names parts the shape does not have. */
|
|
36
|
+
| 'missing-stencil-parts'
|
|
37
|
+
/** A tooltip's `for` names no element in its own tree. */
|
|
38
|
+
| 'missing-trigger'
|
|
39
|
+
/** An area chart was handed a negative number, which it draws as none. */
|
|
40
|
+
| 'negative-value'
|
|
41
|
+
/** A Graph connector was handed an element that is no Graph frame. */
|
|
42
|
+
| 'not-a-graph'
|
|
43
|
+
/** The browser refused picture in picture. */
|
|
44
|
+
| 'picture-in-picture-refused'
|
|
45
|
+
/** A React handler prop is a removed callback, which never ran from JSX. */
|
|
46
|
+
| 'removed-callback'
|
|
47
|
+
/** A React handler prop uses Solid's `on:`, which React reads as another event's name. */
|
|
48
|
+
| 'solid-handler-syntax'
|
|
49
|
+
/** A stencil's regions went unused: no named parts, or parts too small. */
|
|
50
|
+
| 'stencil-regions-unused'
|
|
51
|
+
/** A stencil has no inside to place the notes in. */
|
|
52
|
+
| 'stencil-without-inside'
|
|
53
|
+
/** A Data Table is drawing more rows at once than it stays responsive to. */
|
|
54
|
+
| 'too-many-rows'
|
|
55
|
+
/** A filter field marks more than one operator as its default. */
|
|
56
|
+
| 'two-default-operators'
|
|
57
|
+
/** A React handler prop names an event nothing dispatches. */
|
|
58
|
+
| 'unknown-event'
|
|
59
|
+
/** A tooltip's trigger does not name it in `aria-describedby`, so it is not read out. */
|
|
60
|
+
| 'unlinked-trigger'
|
|
61
|
+
/** A virtualized list's box has no height of its own, so its window never settles. */
|
|
62
|
+
| 'unsettled-window'
|
|
63
|
+
/** A slotted trigger is a plain element, which cannot be told it opens something. */
|
|
64
|
+
| 'untold-trigger'
|
|
65
|
+
/** A tooltip wraps its trigger, so its text reaches no screen reader. */
|
|
66
|
+
| 'wrapped-trigger';
|
|
67
|
+
/** One event: what went wrong, where, and the sentence that says what to do. */
|
|
68
|
+
export interface RuntimeEvent {
|
|
69
|
+
/** What went wrong. */
|
|
70
|
+
readonly kind: RuntimeKind;
|
|
71
|
+
/** Printed with `console.error` where `error`, and with `console.warn` otherwise. */
|
|
72
|
+
readonly level?: 'error' | 'warn';
|
|
73
|
+
/** The sentence the console prints, which says what to do. */
|
|
74
|
+
readonly message: string;
|
|
75
|
+
/** The tag of the element it happened on, where there is one. */
|
|
76
|
+
readonly tag?: string | undefined;
|
|
77
|
+
/** What else the console line carries, such as the error a platform call threw. */
|
|
78
|
+
readonly detail?: unknown;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The key the listener is kept under. `@fusion.dev/helix-diagnostics` names
|
|
82
|
+
* the same string.
|
|
83
|
+
*
|
|
84
|
+
* The listener returns `true` when it prints the event in its own place, and
|
|
85
|
+
* then the console line here is not printed.
|
|
86
|
+
*/
|
|
87
|
+
export declare const RUNTIME_SLOT: unique symbol;
|
|
88
|
+
/** The key the events reported so far are kept under, for a listener that starts late. */
|
|
89
|
+
export declare const RUNTIME_LOG: unique symbol;
|
|
90
|
+
/**
|
|
91
|
+
* Reports one event: to the log, to the listener where there is one, and to
|
|
92
|
+
* the console unless the listener prints it itself.
|
|
93
|
+
*
|
|
94
|
+
* **A listener that throws never stops the report.** The error is printed
|
|
95
|
+
* once, and the event is printed as if nothing listened.
|
|
96
|
+
*/
|
|
97
|
+
export declare const reportRuntime: (event: RuntimeEvent) => void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export const RUNTIME_SLOT = Symbol.for('fusion.dev/helix/runtime');
|
|
2
|
+
export const RUNTIME_LOG = Symbol.for('fusion.dev/helix/runtime-log');
|
|
3
|
+
const KEPT = 200;
|
|
4
|
+
let told = false;
|
|
5
|
+
export const reportRuntime = (event) => {
|
|
6
|
+
const store = globalThis;
|
|
7
|
+
const log = Array.isArray(store[RUNTIME_LOG]) ? store[RUNTIME_LOG] : [];
|
|
8
|
+
if (log.length < KEPT) {
|
|
9
|
+
log.push(event);
|
|
10
|
+
}
|
|
11
|
+
store[RUNTIME_LOG] = log;
|
|
12
|
+
let quiet = false;
|
|
13
|
+
const listener = store[RUNTIME_SLOT];
|
|
14
|
+
if (typeof listener === 'function') {
|
|
15
|
+
try {
|
|
16
|
+
quiet = listener(event) === true;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (!told) {
|
|
20
|
+
told = true;
|
|
21
|
+
console.error('helix: a runtime listener threw, and the warning is printed here. Later failures are not printed.', error);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (quiet) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const print = event.level === 'error' ? console.error : console.warn;
|
|
29
|
+
if (event.detail === undefined) {
|
|
30
|
+
print(event.message);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
print(event.message, event.detail);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { reportRuntime } from '../report-runtime/report-runtime.js';
|
|
1
2
|
const warned = new WeakSet();
|
|
2
3
|
export const tellDisclosure = (trigger, open, popup) => {
|
|
3
4
|
if (!trigger) {
|
|
@@ -16,9 +17,13 @@ export const tellDisclosure = (trigger, open, popup) => {
|
|
|
16
17
|
return;
|
|
17
18
|
}
|
|
18
19
|
warned.add(trigger);
|
|
19
|
-
|
|
20
|
-
'
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
reportRuntime({
|
|
21
|
+
kind: 'untold-trigger',
|
|
22
|
+
message: `<${trigger.localName}> is slotted as a trigger and cannot be told that it opens something. ` +
|
|
23
|
+
'The state would have to be written onto your markup as `aria-expanded`, which a React ' +
|
|
24
|
+
"consumer's hydration reports and does not patch up, so it is not written. Slot a " +
|
|
25
|
+
'`helix-button` or `helix-icon-button`, which carry it inside their own shadow root, or ' +
|
|
26
|
+
'add `aria-haspopup` and your own `aria-expanded` to this element.',
|
|
27
|
+
tag: trigger.localName,
|
|
28
|
+
});
|
|
24
29
|
};
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.140.0';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/helix-core",
|
|
3
3
|
"description": "Helix element primitives: base classes, mixins, decorators, utilities.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.140.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"bugs": "https://github.com/project-fusion/fusion/issues",
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@floating-ui/dom": "^1.8.0",
|
|
37
|
-
"@fusion.dev/helix-icons": "0.
|
|
37
|
+
"@fusion.dev/helix-icons": "0.140.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@fusion.dev/helix-cem": "0.
|
|
41
|
-
"@fusion.dev/helix-testing": "0.
|
|
40
|
+
"@fusion.dev/helix-cem": "0.140.0",
|
|
41
|
+
"@fusion.dev/helix-testing": "0.140.0",
|
|
42
42
|
"@lit-labs/ssr": "^4.1.0",
|
|
43
43
|
"lit": "^3.2.1"
|
|
44
44
|
},
|