@schukai/monster 4.154.11 → 5.0.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.
Files changed (100) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/package.json +1 -1
  3. package/source/components/accessibility/stylesheet/locale-picker.mjs +21 -23
  4. package/source/components/content/stylesheet/camera-capture.mjs +5 -1
  5. package/source/components/content/stylesheet/copy.mjs +5 -1
  6. package/source/components/content/stylesheet/fetch-box.mjs +60 -1
  7. package/source/components/content/stylesheet/viewer.mjs +21 -23
  8. package/source/components/content/viewer/stylesheet/html.mjs +1 -1
  9. package/source/components/content/viewer/stylesheet/message.mjs +1 -1
  10. package/source/components/data/stylesheet/kpi-tile.mjs +16 -22
  11. package/source/components/data/stylesheet/metric-graph.mjs +16 -22
  12. package/source/components/data/stylesheet/metric.mjs +16 -22
  13. package/source/components/datatable/stylesheet/change-button.mjs +21 -23
  14. package/source/components/datatable/stylesheet/column-bar.mjs +23 -25
  15. package/source/components/datatable/stylesheet/dataset.mjs +76 -23
  16. package/source/components/datatable/stylesheet/datatable.mjs +80 -27
  17. package/source/components/datatable/stylesheet/embedded-pagination.mjs +5 -1
  18. package/source/components/datatable/stylesheet/filter-button.mjs +1 -1
  19. package/source/components/datatable/stylesheet/filter-select.mjs +21 -23
  20. package/source/components/datatable/stylesheet/filter.mjs +21 -23
  21. package/source/components/datatable/stylesheet/pagination.mjs +21 -23
  22. package/source/components/datatable/stylesheet/save-button.mjs +21 -23
  23. package/source/components/datatable/stylesheet/status.mjs +21 -23
  24. package/source/components/files/style/file-manager.pcss +111 -0
  25. package/source/components/files/stylesheet/file-manager.mjs +3 -20
  26. package/source/components/form/stylesheet/action-button.mjs +9 -3
  27. package/source/components/form/stylesheet/button-bar.mjs +54 -41
  28. package/source/components/form/stylesheet/button.mjs +17 -23
  29. package/source/components/form/stylesheet/choice-cards.mjs +1 -1
  30. package/source/components/form/stylesheet/control-bar-spacer.mjs +1 -1
  31. package/source/components/form/stylesheet/control-bar.mjs +66 -47
  32. package/source/components/form/stylesheet/popper-button.mjs +16 -22
  33. package/source/components/form/stylesheet/quantity.mjs +1 -1
  34. package/source/components/form/stylesheet/select.mjs +2 -2
  35. package/source/components/form/stylesheet/sheet.mjs +1 -1
  36. package/source/components/form/stylesheet/wizard.mjs +5 -1
  37. package/source/components/host/stylesheet/call-button.mjs +21 -23
  38. package/source/components/host/stylesheet/host.mjs +5 -1
  39. package/source/components/host/stylesheet/toggle-button.mjs +21 -23
  40. package/source/components/layout/stylesheet/collapse.mjs +21 -23
  41. package/source/components/layout/stylesheet/details.mjs +21 -23
  42. package/source/components/layout/stylesheet/iframe.mjs +1 -1
  43. package/source/components/layout/stylesheet/overlay.mjs +5 -1
  44. package/source/components/layout/stylesheet/panel.mjs +5 -1
  45. package/source/components/layout/stylesheet/slider.mjs +5 -1
  46. package/source/components/layout/stylesheet/width-toggle.mjs +1 -1
  47. package/source/components/navigation/stylesheet/site-navigation.mjs +5 -1
  48. package/source/components/navigation/stylesheet/table-of-content.mjs +5 -1
  49. package/source/components/navigation/stylesheet/wizard-navigation.mjs +5 -1
  50. package/source/components/notify/stylesheet/message.mjs +1 -1
  51. package/source/components/notify/stylesheet/notify.mjs +1 -1
  52. package/source/components/state/style/thread-message.pcss +231 -0
  53. package/source/components/state/stylesheet/log.mjs +1 -1
  54. package/source/components/state/stylesheet/state.mjs +1 -1
  55. package/source/components/state/stylesheet/thread-message.mjs +2 -2
  56. package/source/components/state/stylesheet/thread.mjs +1 -1
  57. package/source/components/style/accessibility.css +1 -32
  58. package/source/components/style/badge.css +1 -147
  59. package/source/components/style/border.css +1 -65
  60. package/source/components/style/button.css +16 -22
  61. package/source/components/style/card.css +1 -155
  62. package/source/components/style/color.css +1 -166
  63. package/source/components/style/control.css +1 -14
  64. package/source/components/style/data-grid.css +1 -447
  65. package/source/components/style/display.css +1 -32
  66. package/source/components/style/floating-ui.css +1 -89
  67. package/source/components/style/host.css +1 -14
  68. package/source/components/style/icons.css +1 -1584
  69. package/source/components/style/popper.css +1 -101
  70. package/source/components/style/property.css +5 -1
  71. package/source/components/style/ripple.css +1 -13
  72. package/source/components/style/skeleton.css +56 -1
  73. package/source/components/style/space.css +1 -240
  74. package/source/components/style/spinner.css +1 -7
  75. package/source/components/style/table.css +1 -88
  76. package/source/components/style/theme-modern.css +4 -4
  77. package/source/components/style/theme.css +1 -388
  78. package/source/components/style/tree-menu.css +2 -0
  79. package/source/components/style/tree-menu.pcss +95 -0
  80. package/source/components/style/typography.css +1 -258
  81. package/source/components/stylesheet/button.mjs +16 -22
  82. package/source/components/stylesheet/icons.mjs +1 -1
  83. package/source/components/stylesheet/property.mjs +5 -1
  84. package/source/components/stylesheet/skeleton.mjs +56 -1
  85. package/source/components/stylesheet/spinner.mjs +1 -1
  86. package/source/components/stylesheet/theme-modern.mjs +4 -4
  87. package/source/components/stylesheet/tree-menu.mjs +3 -5
  88. package/source/components/time/stylesheet/day.mjs +16 -22
  89. package/source/components/time/timeline/stylesheet/appointment.mjs +21 -23
  90. package/source/components/time/timeline/stylesheet/segment.mjs +21 -23
  91. package/source/components/tree-menu/stylesheet/tree-menu.mjs +1 -1
  92. package/source/dom/customelement.mjs +49 -16
  93. package/source/types/version.mjs +1 -1
  94. package/test/cases/components/form/control-heights.mjs +2 -2
  95. package/test/cases/components/style/skeleton.mjs +2 -2
  96. package/test/cases/components/style/theme-modern.mjs +7 -13
  97. package/test/cases/dom/customelement.mjs +4 -8
  98. package/test/cases/dom/early-options-contract.mjs +40 -0
  99. package/test/cases/dom/options-lifecycle.mjs +216 -0
  100. package/test/util/early-options.mjs +84 -0
@@ -0,0 +1,216 @@
1
+ import { expect } from "chai";
2
+ import { initJSDOM } from "../../util/jsdom.mjs";
3
+
4
+ describe("Strict options lifecycle (#596)", function () {
5
+ let api;
6
+ let fixture;
7
+ let sequence = 0;
8
+ const tick = () => new Promise((resolve) => setTimeout(resolve, 30));
9
+
10
+ before(async () => {
11
+ await initJSDOM({});
12
+ api = await import("../../../source/dom/customelement.mjs");
13
+ });
14
+ beforeEach(() => {
15
+ fixture = document.createElement("div");
16
+ document.getElementById("mocks").append(fixture);
17
+ });
18
+ afterEach(() => fixture.remove());
19
+
20
+ function register(Constructor) {
21
+ const tag = `monster-options-596-${++sequence}`;
22
+ customElements.define(tag, Constructor);
23
+ return tag;
24
+ }
25
+
26
+ for (const phase of ["defaults", "customization"]) {
27
+ for (const [method, args] of [
28
+ ["getOption", ["value", "fallback"]],
29
+ ["setOption", ["value", "early"]],
30
+ ["setOptions", [{ value: "early" }]],
31
+ ["setOptions", ["invalid JSON"]],
32
+ ]) {
33
+ it(`rejects ${method}(${JSON.stringify(args)}) in ${phase}`, () => {
34
+ class EarlyOptions extends api.CustomElement {}
35
+ Object.defineProperty(EarlyOptions.prototype, phase, {
36
+ get() {
37
+ return this[method](...args);
38
+ },
39
+ });
40
+ register(EarlyOptions);
41
+ let failure;
42
+ try {
43
+ new EarlyOptions();
44
+ } catch (error) {
45
+ failure = error;
46
+ }
47
+ expect(failure).to.be.instanceOf(api.OptionsNotInitializedError);
48
+ expect(failure.name).to.equal("OptionsNotInitializedError");
49
+ expect(failure.method).to.equal(method);
50
+ expect(failure.component).to.equal("EarlyOptions");
51
+ expect(failure.message).to.include("initMethodSymbol");
52
+ });
53
+ }
54
+ }
55
+
56
+ it("evaluates customization once and makes reads and writes available in init", () => {
57
+ let evaluations = 0;
58
+ class Initialized extends api.CustomElement {
59
+ get defaults() {
60
+ return { ...super.defaults, value: "default", nested: { kept: true } };
61
+ }
62
+ get customization() {
63
+ evaluations++;
64
+ return new Map([["value", "custom"]]);
65
+ }
66
+ [api.initMethodSymbol]() {
67
+ super[api.initMethodSymbol]();
68
+ expect(this.getOption("value")).to.equal("custom");
69
+ expect(this.setOption("nested.added", 1)).to.equal(this);
70
+ expect(this.setOptions('{"nested":{"other":2}}')).to.equal(this);
71
+ }
72
+ }
73
+ const element = document.createElement(register(Initialized));
74
+ expect(element).to.be.instanceOf(Initialized);
75
+ expect(evaluations).to.equal(1);
76
+ expect(element.getOption("nested")).to.deep.equal({
77
+ kept: true,
78
+ added: 1,
79
+ other: 2,
80
+ });
81
+ });
82
+
83
+ it("preserves fallback and falsy values, and propagates unrelated failures", () => {
84
+ class Options extends api.CustomElement {}
85
+ const element = document.createElement(register(Options));
86
+ for (const value of [null, false, 0, ""]) {
87
+ element.setOption("value", value);
88
+ expect(element.getOption("value", "fallback")).to.equal(value);
89
+ }
90
+ element.setOption("value", undefined);
91
+ expect(element.getOption("value", "fallback")).to.equal("fallback");
92
+ expect(element.getOption("missing.deep", "fallback")).to.equal("fallback");
93
+ expect(element.getOption("missing.deep")).to.equal(undefined);
94
+ expect(() => element.setOptions("invalid JSON")).to.throw();
95
+ const failure = new Error("property failure");
96
+ element.setOption(
97
+ "broken",
98
+ Object.defineProperty({}, "value", {
99
+ get() {
100
+ throw failure;
101
+ },
102
+ enumerable: true,
103
+ }),
104
+ );
105
+ expect(() => element.getOption("broken.value", "fallback")).to.throw(
106
+ failure,
107
+ );
108
+ });
109
+
110
+ it("preserves attribute/customization precedence on upgrade and permits deferred defaults callbacks", async () => {
111
+ class Upgraded extends api.CustomElement {
112
+ get defaults() {
113
+ return {
114
+ ...super.defaults,
115
+ value: "default",
116
+ fromAttribute: "default",
117
+ readLater: () => this.getOption("value"),
118
+ templates: { main: "<span></span>" },
119
+ };
120
+ }
121
+ get customization() {
122
+ return new Map([["value", "custom"]]);
123
+ }
124
+ [api.initMethodSymbol]() {
125
+ super[api.initMethodSymbol]();
126
+ this.initialValue = this.getOption("value");
127
+ this.initialAttribute = this.getOption("fromAttribute");
128
+ }
129
+ }
130
+ const tag = `monster-options-596-${++sequence}`;
131
+ const holder = document.createElement("div");
132
+ holder.innerHTML = `<${tag} data-monster-option-value="attribute" data-monster-option-from-attribute="present"></${tag}>`;
133
+ const element = holder.firstElementChild;
134
+ customElements.define(tag, Upgraded);
135
+ customElements.upgrade(element);
136
+ expect(element).to.be.instanceOf(Upgraded);
137
+ expect(element.initialValue).to.equal("custom");
138
+ expect(element.initialAttribute).to.equal("present");
139
+ expect(element.getOption("readLater")()).to.equal("custom");
140
+ fixture.append(element);
141
+ await tick();
142
+ expect(element.getOption("readLater")()).to.equal("attribute");
143
+ });
144
+
145
+ it("applies late attributes, JSON and script before rendering; reconnect keeps state", async () => {
146
+ let assemblies = 0;
147
+ class Configured extends api.CustomElement {
148
+ get defaults() {
149
+ return {
150
+ ...super.defaults,
151
+ value: "default",
152
+ flag: false,
153
+ count: 0,
154
+ templates: {
155
+ main: '<span data-monster-replace="path:value"></span>',
156
+ },
157
+ };
158
+ }
159
+ get customization() {
160
+ return new Map([["value", "custom"]]);
161
+ }
162
+ [api.initMethodSymbol]() {
163
+ super[api.initMethodSymbol]();
164
+ this.initialValue = this.getOption("value");
165
+ }
166
+ [api.assembleMethodSymbol]() {
167
+ assemblies++;
168
+ super[api.assembleMethodSymbol]();
169
+ this.assembledValue = this.getOption("value");
170
+ }
171
+ }
172
+ const element = document.createElement(register(Configured));
173
+ expect(element.initialValue).to.equal("custom");
174
+ element.setOption("value", "runtime-before-connect");
175
+ element.setAttribute("data-monster-option-value", "attribute");
176
+ element.setAttribute("data-monster-option-flag", "true");
177
+ element.setAttribute("data-monster-option-count", "7");
178
+ element.setAttribute("data-monster-options", '{"value":"json"}');
179
+ const script = document.createElement("script");
180
+ script.type = "application/json";
181
+ script.id = "options-script-596";
182
+ script.textContent = '{"value":"script"}';
183
+ fixture.append(script);
184
+ element.setAttribute(
185
+ "data-monster-options-selector",
186
+ "#options-script-596",
187
+ );
188
+ fixture.append(element);
189
+ await tick();
190
+ expect(element.assembledValue).to.equal("script");
191
+ expect(element.getOption("flag")).to.equal(true);
192
+ expect(element.getOption("count")).to.equal(7);
193
+ expect(element.shadowRoot.querySelector("span").textContent).to.equal(
194
+ "script",
195
+ );
196
+ element.removeAttribute("data-monster-option-value");
197
+ await tick();
198
+ element.setOption("value", "runtime");
199
+ await tick();
200
+ expect(element.shadowRoot.querySelector("span").textContent).to.equal(
201
+ "runtime",
202
+ );
203
+ element.remove();
204
+ script.textContent = '{"value":"must-not-reload"}';
205
+ fixture.append(element);
206
+ await tick();
207
+ expect(assemblies).to.equal(1);
208
+ expect(element.getOption("value")).to.equal("runtime");
209
+ element.setOption("value", "reconnected");
210
+ await tick();
211
+ expect(element.shadowRoot.querySelector("span").textContent).to.equal(
212
+ "reconnected",
213
+ );
214
+ expect(element.hasAttribute("data-monster-error")).to.equal(false);
215
+ });
216
+ });
@@ -0,0 +1,84 @@
1
+ import { parse } from "espree";
2
+
3
+ const optionMethods = new Set(["getOption", "setOption", "setOptions"]);
4
+ const functions = new Set([
5
+ "FunctionDeclaration",
6
+ "FunctionExpression",
7
+ "ArrowFunctionExpression",
8
+ ]);
9
+ const children = (node) =>
10
+ Object.values(node)
11
+ .flat()
12
+ .filter((value) => value && typeof value.type === "string");
13
+ const property = (node) =>
14
+ node.computed ? node.property?.value : node.property?.name;
15
+
16
+ // A conservative local call-graph check. Imported/dynamic dispatch is covered
17
+ // by the actual component construction tests, not claimed as statically proven.
18
+ export function findEarlyOptions(source) {
19
+ const ast = parse(source, {
20
+ ecmaVersion: "latest",
21
+ sourceType: "module",
22
+ loc: true,
23
+ });
24
+ const helpers = new Map();
25
+ const getters = [];
26
+ function collect(node, methods = new Map()) {
27
+ if (node.type === "ClassBody") {
28
+ methods = new Map(
29
+ node.body
30
+ .filter((entry) => !entry.computed && entry.value)
31
+ .map((entry) => [entry.key.name, entry.value]),
32
+ );
33
+ }
34
+ if (node.type === "FunctionDeclaration" && node.id)
35
+ helpers.set(node.id.name, node);
36
+ if (node.type === "VariableDeclarator" && functions.has(node.init?.type))
37
+ helpers.set(node.id.name, node.init);
38
+ if (
39
+ node.type === "MethodDefinition" &&
40
+ node.kind === "get" &&
41
+ ["defaults", "customization"].includes(node.key.name)
42
+ ) {
43
+ getters.push({ node, methods });
44
+ }
45
+ for (const child of children(node)) collect(child, methods);
46
+ }
47
+ collect(ast);
48
+ const failures = [];
49
+ for (const { node: getter, methods } of getters) {
50
+ const visited = new Set();
51
+ function execute(fn) {
52
+ if (!fn || visited.has(fn)) return;
53
+ visited.add(fn);
54
+ walk(fn.body);
55
+ }
56
+ function walk(node) {
57
+ if (!node || functions.has(node.type)) return; // callbacks are deferred unless invoked
58
+ if (node.type === "CallExpression") {
59
+ let callee = node.callee;
60
+ if (
61
+ callee.type === "MemberExpression" &&
62
+ ["call", "apply"].includes(property(callee))
63
+ )
64
+ callee = callee.object;
65
+ if (callee.type === "MemberExpression") {
66
+ const name = property(callee);
67
+ if (optionMethods.has(name))
68
+ failures.push({
69
+ phase: getter.key.name,
70
+ method: name,
71
+ line: node.loc.start.line,
72
+ });
73
+ if (callee.object.type === "ThisExpression")
74
+ execute(methods.get(name));
75
+ } else if (callee.type === "Identifier")
76
+ execute(helpers.get(callee.name));
77
+ else if (functions.has(callee.type)) execute(callee);
78
+ }
79
+ for (const child of children(node)) walk(child);
80
+ }
81
+ execute(getter.value);
82
+ }
83
+ return failures;
84
+ }