@heartlandone/vega-react 2.78.0 → 2.79.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.
@@ -79,6 +79,9 @@ export declare const VegaRichTextEditor: import("react").ForwardRefExoticCompone
79
79
  export declare const VegaRichTextEditorToolbarButton: import("react").ForwardRefExoticComponent<VegaReactComponentWithNativeEvent<JSX.VegaRichTextEditorToolbarButton, Omit<import("react").HTMLAttributes<HTMLVegaRichTextEditorToolbarButtonElement>, "style">, "onClick"> & import("./react-component-lib/interfaces").StyleReactProps & import("react").RefAttributes<HTMLVegaRichTextEditorToolbarButtonElement>>;
80
80
  export declare const VegaRichTextImageEditor: import("react").ForwardRefExoticComponent<VegaReactComponentWithNativeEvent<JSX.VegaRichTextImageEditor, Omit<import("react").HTMLAttributes<HTMLVegaRichTextImageEditorElement>, "style">, "onChange"> & import("./react-component-lib/interfaces").StyleReactProps & import("react").RefAttributes<HTMLVegaRichTextImageEditorElement>>;
81
81
  export declare const VegaRichTextLinkEditor: import("react").ForwardRefExoticComponent<VegaReactComponentWithNativeEvent<JSX.VegaRichTextLinkEditor, Omit<import("react").HTMLAttributes<HTMLVegaRichTextLinkEditorElement>, "style">, "onChange"> & import("./react-component-lib/interfaces").StyleReactProps & import("react").RefAttributes<HTMLVegaRichTextLinkEditorElement>>;
82
+ export declare const VegaRichTextTableProperties: import("react").ForwardRefExoticComponent<JSX.VegaRichTextTableProperties & Omit<import("react").HTMLAttributes<HTMLVegaRichTextTablePropertiesElement>, "style"> & import("./react-component-lib/interfaces").StyleReactProps & import("react").RefAttributes<HTMLVegaRichTextTablePropertiesElement>>;
83
+ export declare const VegaRichTextTableSelectionWidget: import("react").ForwardRefExoticComponent<JSX.VegaRichTextTableSelectionWidget & Omit<import("react").HTMLAttributes<HTMLVegaRichTextTableSelectionWidgetElement>, "style"> & import("./react-component-lib/interfaces").StyleReactProps & import("react").RefAttributes<HTMLVegaRichTextTableSelectionWidgetElement>>;
84
+ export declare const VegaRichTextTableSetting: import("react").ForwardRefExoticComponent<JSX.VegaRichTextTableSetting & Omit<import("react").HTMLAttributes<HTMLVegaRichTextTableSettingElement>, "style"> & import("./react-component-lib/interfaces").StyleReactProps & import("react").RefAttributes<HTMLVegaRichTextTableSettingElement>>;
82
85
  export declare const VegaSectionTitle: import("react").ForwardRefExoticComponent<JSX.VegaSectionTitle & Omit<import("react").HTMLAttributes<HTMLVegaSectionTitleElement>, "style"> & import("./react-component-lib/interfaces").StyleReactProps & import("react").RefAttributes<HTMLVegaSectionTitleElement>>;
83
86
  export declare const VegaSegmentControl: import("react").ForwardRefExoticComponent<VegaReactComponentWithNativeEvent<JSX.VegaSegmentControl, Omit<import("react").HTMLAttributes<HTMLVegaSegmentControlElement>, "style">, "onChange"> & import("./react-component-lib/interfaces").StyleReactProps & import("react").RefAttributes<HTMLVegaSegmentControlElement>>;
84
87
  export declare const VegaSelectionChip: import("react").ForwardRefExoticComponent<VegaReactComponentWithNativeEvent<JSX.VegaSelectionChip, Omit<import("react").HTMLAttributes<HTMLVegaSelectionChipElement>, "style">, "onChange"> & import("./react-component-lib/interfaces").StyleReactProps & import("react").RefAttributes<HTMLVegaSelectionChipElement>>;
@@ -86,6 +86,9 @@ export const VegaRichTextEditor = /*@__PURE__*/ createReactComponent('vega-rich-
86
86
  export const VegaRichTextEditorToolbarButton = /*@__PURE__*/ createReactComponent('vega-rich-text-editor-toolbar-button');
87
87
  export const VegaRichTextImageEditor = /*@__PURE__*/ createReactComponent('vega-rich-text-image-editor');
88
88
  export const VegaRichTextLinkEditor = /*@__PURE__*/ createReactComponent('vega-rich-text-link-editor');
89
+ export const VegaRichTextTableProperties = /*@__PURE__*/ createReactComponent('vega-rich-text-table-properties');
90
+ export const VegaRichTextTableSelectionWidget = /*@__PURE__*/ createReactComponent('vega-rich-text-table-selection-widget');
91
+ export const VegaRichTextTableSetting = /*@__PURE__*/ createReactComponent('vega-rich-text-table-setting');
89
92
  export const VegaSectionTitle = /*@__PURE__*/ createReactComponent('vega-section-title');
90
93
  export const VegaSegmentControl = /*@__PURE__*/ createReactComponent('vega-segment-control');
91
94
  export const VegaSelectionChip = /*@__PURE__*/ createReactComponent('vega-selection-chip');
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./components";
2
+ export { VegaPopover } from "./overrides/vega-popover";
2
3
  export * from "./hooks/use-vega-ref";
3
4
  export * from "./global";
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./components";
2
+ export { VegaPopover } from "./overrides/vega-popover";
2
3
  export * from "./hooks/use-vega-ref";
3
4
  export * from "./global";
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import { StencilReactExternalProps } from "../../react-component-lib/utils";
3
+ import type { JSX } from "@heartlandone/vega";
4
+ declare type VegaPopoverProps = React.PropsWithChildren<StencilReactExternalProps<JSX.VegaPopover, HTMLVegaPopoverElement>>;
5
+ declare type VegaPopoverComponent = React.ForwardRefExoticComponent<React.PropsWithoutRef<VegaPopoverProps> & React.RefAttributes<HTMLVegaPopoverElement>>;
6
+ export declare const VegaPopover: VegaPopoverComponent;
7
+ export {};
@@ -0,0 +1,151 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React from "react";
13
+ import ReactDOM from "react-dom";
14
+ import { createReactComponent } from "../../react-component-lib";
15
+ import { setRef, } from "../../react-component-lib/utils";
16
+ const VegaPopoverBase = createReactComponent("vega-popover");
17
+ /** Splits children into `[slot="popover"]` overlay nodes and all others (trigger etc.). */
18
+ function splitChildren(children) {
19
+ const popover = [];
20
+ const other = [];
21
+ React.Children.forEach(children, (child) => {
22
+ if (!React.isValidElement(child)) {
23
+ other.push(child);
24
+ return;
25
+ }
26
+ const slot = child.props
27
+ .slot;
28
+ (slot === "popover" ? popover : other).push(child);
29
+ });
30
+ return [popover, other];
31
+ }
32
+ class VegaPopoverInner extends React.PureComponent {
33
+ constructor(props) {
34
+ super(props);
35
+ this.host = null;
36
+ this.popoverMount = null;
37
+ this.contentBox = null;
38
+ this.contentBoxObserver = null;
39
+ this.isUnmounting = false;
40
+ this.disconnectContentBoxObserver = () => {
41
+ if (this.contentBoxObserver) {
42
+ this.contentBoxObserver.disconnect();
43
+ this.contentBoxObserver = null;
44
+ }
45
+ };
46
+ this.syncContentBox = () => {
47
+ var _a, _b, _c;
48
+ const nextContentBox = (_c = (_b = (_a = this.host) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector("vega-popover-content-box")) !== null && _c !== void 0 ? _c : null;
49
+ if (this.contentBox === nextContentBox) {
50
+ this.ensurePopoverMount();
51
+ return;
52
+ }
53
+ this.contentBox = nextContentBox;
54
+ this.ensurePopoverMount();
55
+ };
56
+ this.ensurePopoverMount = () => {
57
+ if (!this.contentBox || !this.popoverMount) {
58
+ return;
59
+ }
60
+ if (this.popoverMount.parentElement !== this.contentBox) {
61
+ this.contentBox.appendChild(this.popoverMount);
62
+ }
63
+ };
64
+ this.attachContentBoxObserver = (host) => {
65
+ this.disconnectContentBoxObserver();
66
+ if (typeof MutationObserver === "undefined" || !host.shadowRoot) {
67
+ return;
68
+ }
69
+ this.contentBoxObserver = new MutationObserver(() => {
70
+ this.syncContentBox();
71
+ });
72
+ this.contentBoxObserver.observe(host.shadowRoot, {
73
+ childList: true,
74
+ subtree: true,
75
+ });
76
+ };
77
+ this.connectHost = (host) => {
78
+ // Reset the unmounting flag so re-connections work after React 18 StrictMode
79
+ // simulates unmount+remount on the same class instance.
80
+ this.isUnmounting = false;
81
+ // Re-create popoverMount if componentWillUnmount destroyed it (StrictMode remount).
82
+ let needsRender = false;
83
+ if (!this.popoverMount && typeof document !== "undefined") {
84
+ this.popoverMount = document.createElement("div");
85
+ this.popoverMount.setAttribute("slot", "popover");
86
+ needsRender = true;
87
+ }
88
+ const ready = typeof host.componentOnReady === "function"
89
+ ? host.componentOnReady()
90
+ : Promise.resolve();
91
+ void ready.then(() => {
92
+ if (this.host !== host || this.isUnmounting) {
93
+ return;
94
+ }
95
+ this.syncContentBox();
96
+ this.attachContentBoxObserver(host);
97
+ // If popoverMount was recreated we need a new render pass so the portal
98
+ // picks up the fresh mount node.
99
+ if (needsRender) {
100
+ this.forceUpdate();
101
+ }
102
+ });
103
+ };
104
+ this.setHostRef = (el) => {
105
+ const { forwardedRef } = this.props;
106
+ setRef(forwardedRef, el);
107
+ if (this.host === el) {
108
+ return;
109
+ }
110
+ if (el === null && this.host !== null && !this.isUnmounting) {
111
+ return;
112
+ }
113
+ if (this.host && el !== this.host) {
114
+ this.disconnectContentBoxObserver();
115
+ }
116
+ this.host = el;
117
+ if (el) {
118
+ this.connectHost(el);
119
+ }
120
+ else {
121
+ this.contentBox = null;
122
+ }
123
+ };
124
+ if (typeof document !== "undefined") {
125
+ this.popoverMount = document.createElement("div");
126
+ this.popoverMount.setAttribute("slot", "popover");
127
+ }
128
+ }
129
+ componentWillUnmount() {
130
+ var _a;
131
+ this.isUnmounting = true;
132
+ this.disconnectContentBoxObserver();
133
+ if ((_a = this.popoverMount) === null || _a === void 0 ? void 0 : _a.parentElement) {
134
+ this.popoverMount.parentElement.removeChild(this.popoverMount);
135
+ }
136
+ this.host = null;
137
+ this.popoverMount = null;
138
+ this.contentBox = null;
139
+ }
140
+ render() {
141
+ const _a = this.props, { children, forwardedRef } = _a, restProps = __rest(_a, ["children", "forwardedRef"]);
142
+ const [popoverChildren, otherChildren] = splitChildren(children);
143
+ return (React.createElement(React.Fragment, null,
144
+ React.createElement(VegaPopoverBase, Object.assign({}, restProps, { ref: this.setHostRef }), otherChildren),
145
+ popoverChildren.length > 0 &&
146
+ this.popoverMount &&
147
+ ReactDOM.createPortal(popoverChildren, this.popoverMount)));
148
+ }
149
+ }
150
+ export const VegaPopover = React.forwardRef((props, ref) => React.createElement(VegaPopoverInner, Object.assign({}, props, { forwardedRef: ref })));
151
+ VegaPopover.displayName = "VegaPopover";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * NOTE: This test file is for vega-popover React wrapper.
3
+ * It validates portal wrapping and slot-based child routing.
4
+ * Tests use the real VegaPopover component with mocked Shadow DOM support.
5
+ */
6
+ import "jest";
@@ -0,0 +1,108 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ /**
11
+ * NOTE: This test file is for vega-popover React wrapper.
12
+ * It validates portal wrapping and slot-based child routing.
13
+ * Tests use the real VegaPopover component with mocked Shadow DOM support.
14
+ */
15
+ import "jest";
16
+ import React from "react";
17
+ import ReactDOM from "react-dom";
18
+ import { VegaPopover } from "../index";
19
+ // @ts-ignore - @testing-library/react is installed and resolved by jest, but TypeScript LSP may not find it
20
+ import { render, waitFor } from "@testing-library/react";
21
+ jest.mock("@heartlandone/vega", () => ({
22
+ FeatureFlag: {
23
+ isEnabled: () => false,
24
+ },
25
+ }), { virtual: true });
26
+ /**
27
+ * Helper to inject a mocked Shadow DOM structure into an element.
28
+ * Used for jsdom compatibility where native Shadow DOM is not supported.
29
+ */
30
+ function injectShadowRootMock(element) {
31
+ if (!element.shadowRoot) {
32
+ const contentBox = document.createElement("vega-popover-content-box");
33
+ Object.defineProperty(element, "shadowRoot", {
34
+ configurable: true,
35
+ value: {
36
+ querySelector: (selector) => {
37
+ return selector === "vega-popover-content-box" ? contentBox : null;
38
+ },
39
+ },
40
+ });
41
+ element.componentOnReady = () => Promise.resolve(element);
42
+ }
43
+ return element;
44
+ }
45
+ describe("VegaPopover (React portal wrapper)", () => {
46
+ beforeEach(() => {
47
+ // Mock createElement to inject shadowRoot on vega-popover elements
48
+ const originalCreateElement = document.createElement;
49
+ jest
50
+ .spyOn(document, "createElement")
51
+ .mockImplementation(function (tagName, ...args) {
52
+ const element = originalCreateElement.call(document, tagName, ...args);
53
+ if (tagName.toLowerCase() === "vega-popover") {
54
+ injectShadowRootMock(element);
55
+ }
56
+ return element;
57
+ });
58
+ });
59
+ afterEach(() => {
60
+ jest.restoreAllMocks();
61
+ document.body.innerHTML = "";
62
+ });
63
+ test("creates host and content-box portals for trigger and popover content", () => __awaiter(void 0, void 0, void 0, function* () {
64
+ var _a;
65
+ const createPortalSpy = jest.spyOn(ReactDOM, "createPortal");
66
+ createPortalSpy.mockImplementation((children) => children);
67
+ render(React.createElement(VegaPopover, { placement: "top", alignment: "start" },
68
+ React.createElement("button", { slot: "popover-content" }, "Click Me"),
69
+ React.createElement("div", { slot: "popover" }, "Popover Content")));
70
+ const host = document.querySelector("vega-popover");
71
+ const contentBox = (_a = host === null || host === void 0 ? void 0 : host.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector("vega-popover-content-box");
72
+ expect(host).toBeTruthy();
73
+ expect(contentBox).toBeTruthy();
74
+ yield waitFor(() => {
75
+ expect(createPortalSpy).toHaveBeenCalled();
76
+ const containers = createPortalSpy.mock.calls.map((call) => call[1]);
77
+ expect(containers).toContain(host);
78
+ expect(containers).toContain(contentBox);
79
+ });
80
+ }));
81
+ test("routes children by slot to the expected portal container", () => __awaiter(void 0, void 0, void 0, function* () {
82
+ var _b;
83
+ const createPortalSpy = jest.spyOn(ReactDOM, "createPortal");
84
+ createPortalSpy.mockImplementation((children) => children);
85
+ render(React.createElement(VegaPopover, { placement: "top", alignment: "start" },
86
+ React.createElement("button", { slot: "popover-content" }, "Trigger Button"),
87
+ React.createElement("div", { slot: "popover" }, "Popover Body")));
88
+ const host = document.querySelector("vega-popover");
89
+ const contentBox = (_b = host === null || host === void 0 ? void 0 : host.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector("vega-popover-content-box");
90
+ yield waitFor(() => {
91
+ expect(createPortalSpy.mock.calls.length).toBeGreaterThanOrEqual(2);
92
+ });
93
+ const hostPortalCall = createPortalSpy.mock.calls.find((call) => call[1] === host);
94
+ const contentPortalCall = createPortalSpy.mock.calls.find((call) => call[1] === contentBox);
95
+ expect(hostPortalCall).toBeTruthy();
96
+ expect(contentPortalCall).toBeTruthy();
97
+ const hostChildren = hostPortalCall
98
+ ? React.Children.toArray(hostPortalCall[0])
99
+ : [];
100
+ const contentChildren = contentPortalCall
101
+ ? React.Children.toArray(contentPortalCall[0])
102
+ : [];
103
+ if (hostChildren[0] && contentChildren[0]) {
104
+ expect(hostChildren[0].props.children).toBe("Trigger Button");
105
+ expect(contentChildren[0].props.children).toBe("Popover Body");
106
+ }
107
+ }));
108
+ });
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@heartlandone/vega-react",
3
+ "version": "2.78.0",
4
+ "description": "React specific wrapper for @heartlandone/vega",
5
+ "license": "UNLICENSED",
6
+ "sideEffects": false,
7
+ "main": "./index.js",
8
+ "module": "./index.js",
9
+ "types": "./index.d.ts",
10
+ "dependencies": {
11
+ "@heartlandone/vega": "2.78.0"
12
+ },
13
+ "peerDependencies": {
14
+ "react": ">=16.7.0",
15
+ "react-dom": ">=16.7.0"
16
+ }
17
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * NOTE: This utility is only for **SPEC** test cases.
3
+ *
4
+ * Mocked MutationObserver for testing in jsdom environment.
5
+ * Provides observe, disconnect, and trigger methods for controlling
6
+ * mutation observations in tests.
7
+ *
8
+ * @callback MutationCallback - The callback function triggered when mutations occur
9
+ * @returns {jest.Mock} - A Jest mock function constructor for MutationObserver
10
+ */
11
+ export declare const MockedMutationObserver: jest.Mock;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * NOTE: This utility is only for **SPEC** test cases.
3
+ *
4
+ * Mocked MutationObserver for testing in jsdom environment.
5
+ * Provides observe, disconnect, and trigger methods for controlling
6
+ * mutation observations in tests.
7
+ *
8
+ * @callback MutationCallback - The callback function triggered when mutations occur
9
+ * @returns {jest.Mock} - A Jest mock function constructor for MutationObserver
10
+ */
11
+ export const MockedMutationObserver = jest.fn(function MutationObserver(callback) {
12
+ this.observe = jest.fn();
13
+ this.disconnect = jest.fn();
14
+ /**
15
+ * Mock the trigger for spec test to trigger observer callback
16
+ *
17
+ * @param {MutationRecord[]} mutations - mocked MutationObserver entries
18
+ */
19
+ this.trigger = (mutations) => {
20
+ callback(mutations, this);
21
+ };
22
+ });
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@heartlandone/vega-react",
3
3
  "sideEffects": false,
4
- "version": "2.78.0",
4
+ "version": "2.79.0",
5
5
  "description": "React specific wrapper for @heartlandone/vega",
6
6
  "license": "UNLICENSED",
7
7
  "scripts": {
8
8
  "stencil-postbuild": "node ./src/scripts/stencil-post-build-script.js",
9
- "build": "npm run clean && npm run compile && npm run override-type",
9
+ "build": "npm run clean && npm run compile && npm run override-type && npm run create-dist-package-json",
10
10
  "clean": "rm -rf dist",
11
11
  "compile": "npm run tsc",
12
12
  "tsc": "tsc -p .",
@@ -16,6 +16,8 @@
16
16
  "publish:minor": "node ../scripts/publish-version.js minor",
17
17
  "publish:major": "node ../scripts/publish-version.js major",
18
18
  "override-type": "node ./src/scripts/override-component-native-event-type.js",
19
+ "create-dist-package-json": "node ./src/scripts/create-dist-package-json.js",
20
+ "test": "jest",
19
21
  "pr-codesandbox-auto": "node ../scripts/pr-codesandbox-auto/change-package-name.js"
20
22
  },
21
23
  "main": "./dist/index.js",
@@ -38,10 +40,11 @@
38
40
  "np": "^3.1.0",
39
41
  "react": "^16.7.0",
40
42
  "react-dom": "^16.7.0",
43
+ "ts-jest": "^23.10.5",
41
44
  "typescript": "^4.0.0"
42
45
  },
43
46
  "dependencies": {
44
- "@heartlandone/vega": "2.78.0"
47
+ "@heartlandone/vega": "2.79.0"
45
48
  },
46
49
  "peerDependencies": {
47
50
  "react": ">=16.7.0",
@@ -53,7 +56,12 @@
53
56
  "testPathIgnorePatterns": [
54
57
  "node_modules",
55
58
  "dist"
56
- ]
59
+ ],
60
+ "globals": {
61
+ "ts-jest": {
62
+ "tsConfig": "tsconfig.test.json"
63
+ }
64
+ }
57
65
  },
58
66
  "resolutions": {
59
67
  "yargs-parser": "^21.1.1"