diff --git a/packages/malloy-render/src/component/chart/chart.tsx b/packages/malloy-render/src/component/chart/chart.tsx
index ef00e0663..6868c7765 100644
--- a/packages/malloy-render/src/component/chart/chart.tsx
+++ b/packages/malloy-render/src/component/chart/chart.tsx
@@ -9,15 +9,14 @@ import {Explore, ExploreField, QueryData} from '@malloydata/malloy';
import {VegaChart, ViewInterface} from '../vega/vega-chart';
import {ChartTooltipEntry, RenderResultMetadata} from '../types';
import {Tooltip} from '../tooltip/tooltip';
-import {createEffect, createSignal, createMemo, lazy, Show} from 'solid-js';
+import {createEffect, createSignal, createMemo, Show} from 'solid-js';
import {DefaultChartTooltip} from './default-chart-tooltip';
import {EventListenerHandler, Runtime, View} from 'vega';
import {useResultStore, VegaBrushOutput} from '../result-store/result-store';
import css from './chart.css?raw';
import {useConfig} from '../render';
import {DebugIcon} from './debug_icon';
-
-const ChartDevTool = lazy(() => import('./chart-dev-tool'));
+import ChartDevTool from './chart-dev-tool';
let IS_STORYBOOK = false;
try {
diff --git a/packages/malloy-render/src/component/malloy-modal/malloy-modal-wc.tsx b/packages/malloy-render/src/component/malloy-modal/malloy-modal-wc.tsx
new file mode 100644
index 000000000..0b25beef1
--- /dev/null
+++ b/packages/malloy-render/src/component/malloy-modal/malloy-modal-wc.tsx
@@ -0,0 +1,21 @@
+import {ComponentOptions} from 'component-register';
+
+export type MalloyModalWCProps = {
+ stylesheet?: CSSStyleSheet;
+};
+
+export function MalloyModalWC(
+ props: MalloyModalWCProps,
+ {element}: ComponentOptions
+) {
+ const root = element.renderRoot;
+ if (root instanceof ShadowRoot && props.stylesheet) {
+ root.adoptedStyleSheets.push(props.stylesheet);
+ }
+
+ /*
+ Move child nodes into ShadowDOM. This probably only works if modal root elements stay consistent.
+ */
+ const allChildren = [...element['childNodes']];
+ return
{...allChildren}
;
+}
diff --git a/packages/malloy-render/src/component/malloy-modal/malloy-modal.tsx b/packages/malloy-render/src/component/malloy-modal/malloy-modal.tsx
new file mode 100644
index 000000000..2fa51b28d
--- /dev/null
+++ b/packages/malloy-render/src/component/malloy-modal/malloy-modal.tsx
@@ -0,0 +1,32 @@
+import {Portal} from 'solid-js/web';
+import {JSX, JSXElement} from 'solid-js';
+import {useConfig} from '../render';
+
+export function MalloyModal(props: {
+ style?: string | JSX.CSSProperties;
+ children?: JSXElement;
+ ref?: HTMLDivElement | ((el: HTMLDivElement) => void);
+}) {
+ const config = useConfig();
+ return (
+
+
+
+ );
+}
+
+declare module 'solid-js' {
+ // eslint-disable-next-line @typescript-eslint/no-namespace
+ namespace JSX {
+ interface IntrinsicElements {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ 'malloy-modal': any;
+ }
+ }
+}
diff --git a/packages/malloy-render/src/component/register-webcomponent.ts b/packages/malloy-render/src/component/register-webcomponent.ts
index 9cbb3dbf3..77a17ff2b 100644
--- a/packages/malloy-render/src/component/register-webcomponent.ts
+++ b/packages/malloy-render/src/component/register-webcomponent.ts
@@ -1,6 +1,10 @@
import {compose, register} from 'component-register';
import {withSolid} from 'solid-element';
import {MalloyRender, MalloyRenderProps} from './render';
+import {
+ MalloyModalWC,
+ MalloyModalWCProps,
+} from './malloy-modal/malloy-modal-wc';
export default function registerWebComponent({
customElements = window.customElements,
@@ -19,6 +23,7 @@ export default function registerWebComponent({
vegaConfigOverride: undefined,
tableConfig: undefined,
dashboardConfig: undefined,
+ modalElement: undefined,
},
{customElements, BaseElement: HTMLElement}
),
@@ -30,10 +35,24 @@ export default function registerWebComponent({
"The custom element 'malloy-render' has already been defined. Make sure you are not loading multiple versions of the malloy-render package as they could conflict."
);
}
+
+ if (!customElements.get('malloy-modal')) {
+ compose(
+ register(
+ 'malloy-modal',
+ {
+ stylesheet: undefined,
+ },
+ {customElements, BaseElement: HTMLElement}
+ ),
+ withSolid
+ )(MalloyModalWC);
+ }
}
declare global {
interface HTMLElementTagNameMap {
'malloy-render': HTMLElement & MalloyRenderProps;
+ 'malloy-modal': HTMLElement & MalloyModalWCProps;
}
}
diff --git a/packages/malloy-render/src/component/render.tsx b/packages/malloy-render/src/component/render.tsx
index 1a8fa603a..cc174588a 100644
--- a/packages/malloy-render/src/component/render.tsx
+++ b/packages/malloy-render/src/component/render.tsx
@@ -38,6 +38,7 @@ export type MalloyRenderProps = {
queryResult?: QueryResult;
modelDef?: ModelDef;
scrollEl?: HTMLElement;
+ modalElement?: HTMLElement;
onClick?: (payload: MalloyClickEventPayload) => void;
vegaConfigOverride?: VegaConfigHandler;
tableConfig?: Partial;
@@ -48,10 +49,12 @@ const ConfigContext = createContext<{
tableConfig: Accessor;
dashboardConfig: Accessor;
element: ICustomElement;
+ stylesheet: CSSStyleSheet;
addCSSToShadowRoot: (css: string) => void;
addCSSToDocument: (id: string, css: string) => void;
onClick?: (payload: MalloyClickEventPayload) => void;
vegaConfigOverride?: VegaConfigHandler;
+ modalElement?: HTMLElement;
}>();
export const useConfig = () => {
@@ -74,6 +77,12 @@ export function MalloyRender(
else return null;
});
+ // Create one stylesheet for web component to use for all styles
+ // This is so we can pass the stylesheet to other components to share, like
+ const stylesheet = new CSSStyleSheet();
+ if (element.renderRoot instanceof ShadowRoot)
+ element.renderRoot.adoptedStyleSheets.push(stylesheet);
+
const addedStylesheets = new Set();
function addCSSToShadowRoot(css: string) {
const root = element.renderRoot;
@@ -85,9 +94,13 @@ export function MalloyRender(
return;
}
if (!addedStylesheets.has(css)) {
- const stylesheet = new CSSStyleSheet();
- stylesheet.replaceSync(css);
- root.adoptedStyleSheets.push(stylesheet);
+ const newStyleSheetTexts: string[] = [];
+ for (let i = 0; i < stylesheet.cssRules.length; i++) {
+ const cssText = stylesheet.cssRules.item(i)?.cssText;
+ if (cssText) newStyleSheetTexts.push(cssText);
+ }
+ newStyleSheetTexts.push(css);
+ stylesheet.replaceSync(newStyleSheetTexts.join('\n'));
addedStylesheets.add(css);
}
}
@@ -100,6 +113,7 @@ export function MalloyRender(
document.head.appendChild(style);
}
}
+
addCSSToShadowRoot(css);
const tableConfig: Accessor = () =>
@@ -127,10 +141,12 @@ export function MalloyRender(
onClick: props.onClick,
vegaConfigOverride: props.vegaConfigOverride,
element,
+ stylesheet,
addCSSToShadowRoot,
addCSSToDocument,
tableConfig,
dashboardConfig,
+ modalElement: props.modalElement,
}}
>
{
if (props.element) {
const style = generateThemeStyle(tags().modelTheme, tags().localTheme);
- for (const [key, value] of Object.entries(style)) {
- props.element['style'].setProperty(key, value);
- }
+ config.addCSSToShadowRoot(style);
}
});
@@ -219,8 +235,6 @@ function getThemeValue(prop: string, ...themes: Array) {
}
function generateThemeStyle(modelTheme?: Tag, localTheme?: Tag) {
- const style: Record = {};
-
const tableRowHeight = getThemeValue(
'tableRowHeight',
localTheme,
@@ -270,17 +284,21 @@ function generateThemeStyle(modelTheme?: Tag, localTheme?: Tag) {
);
const fontFamily = getThemeValue('fontFamily', localTheme, modelTheme);
- style['--malloy-render--table-row-height'] = tableRowHeight;
- style['--malloy-render--table-body-color'] = tableBodyColor;
- style['--malloy-render--table-font-size'] = tableFontSize;
- style['--malloy-render--font-family'] = fontFamily;
- style['--malloy-render--table-header-color'] = tableHeaderColor;
- style['--malloy-render--table-header-weight'] = tableHeaderWeight;
- style['--malloy-render--table-body-weight'] = tableBodyWeight;
- style['--malloy-render--table-border'] = tableBorder;
- style['--malloy-render--table-background'] = tableBackground;
- style['--malloy-render--table-gutter-size'] = tableGutterSize;
- style['--malloy-render--table-pinned-background'] = tablePinnedBackground;
- style['--malloy-render--table-pinned-border'] = tablePinnedBorder;
- return style;
+ const css = `
+ :host {
+ --malloy-render--table-row-height: ${tableRowHeight};
+ --malloy-render--table-body-color: ${tableBodyColor};
+ --malloy-render--table-font-size: ${tableFontSize};
+ --malloy-render--font-family: ${fontFamily};
+ --malloy-render--table-header-color: ${tableHeaderColor};
+ --malloy-render--table-header-weight: ${tableHeaderWeight};
+ --malloy-render--table-body-weight: ${tableBodyWeight};
+ --malloy-render--table-border: ${tableBorder};
+ --malloy-render--table-background: ${tableBackground};
+ --malloy-render--table-gutter-size: ${tableGutterSize};
+ --malloy-render--table-pinned-background: ${tablePinnedBackground};
+ --malloy-render--table-pinned-border: ${tablePinnedBorder};
+ }
+`;
+ return css;
}
diff --git a/packages/malloy-render/src/component/tooltip/tooltip.tsx b/packages/malloy-render/src/component/tooltip/tooltip.tsx
index f9f453db2..ffdde91b0 100644
--- a/packages/malloy-render/src/component/tooltip/tooltip.tsx
+++ b/packages/malloy-render/src/component/tooltip/tooltip.tsx
@@ -7,6 +7,7 @@ import {
} from 'solid-js';
import tooltipCss from './tooltip.css?raw';
import {useConfig} from '../render';
+import {MalloyModal} from '../malloy-modal/malloy-modal';
export function Tooltip(props: {show: boolean; children: JSXElement}) {
const [pos, setPos] = createSignal<[number, number]>([0, 0]);
@@ -57,17 +58,16 @@ export function Tooltip(props: {show: boolean; children: JSXElement}) {
});
}
});
-
return (
-
+
);
}