Skip to content

Commit 33d7e6c

Browse files
committed
Prevent state leakage
1 parent 242fb28 commit 33d7e6c

File tree

1 file changed

+52
-21
lines changed

1 file changed

+52
-21
lines changed

streamlit_bokeh/frontend/src/index.ts

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,25 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { Theme } from "streamlit-component-lib"
18-
import { StV2ComponentArgs } from "./StTypes_TEMPORARY"
1917
import { streamlitTheme } from "./streamlit-theme"
2018

2119
import bokehMin from "./assets/bokeh/bokeh-3.7.3.min.js?url"
22-
import bokehWidgets from "./assets/bokeh/bokeh-widgets-3.7.3.min.js?url"
23-
import bokehTables from "./assets/bokeh/bokeh-tables-3.7.3.min.js?url"
2420
import bokehApi from "./assets/bokeh/bokeh-api-3.7.3.min.js?url"
2521
import bokehGl from "./assets/bokeh/bokeh-gl-3.7.3.min.js?url"
2622
import bokehMathjax from "./assets/bokeh/bokeh-mathjax-3.7.3.min.js?url"
23+
import bokehTables from "./assets/bokeh/bokeh-tables-3.7.3.min.js?url"
24+
import bokehWidgets from "./assets/bokeh/bokeh-widgets-3.7.3.min.js?url"
2725

26+
import SourceSansProBold from "./assets/fonts/SourceSansPro-Bold.woff2?url"
2827
import SourceSansProRegular from "./assets/fonts/SourceSansPro-Regular.woff2?url"
2928
import SourceSansProSemiBold from "./assets/fonts/SourceSansPro-SemiBold.woff2?url"
30-
import SourceSansProBold from "./assets/fonts/SourceSansPro-Bold.woff2?url"
3129

30+
import {
31+
Component,
32+
ComponentArgs,
33+
StreamlitTheme,
34+
StreamlitThemeCssProperties,
35+
} from "@streamlit/component-v2-lib"
3236
import indexCss from "./assets/index.css?url"
3337

3438
declare global {
@@ -66,13 +70,12 @@ export const getChartDataGenerator = () => {
6670
return { data: savedChartData[key], hasChanged: false }
6771
}
6872
}
69-
const getChartData = getChartDataGenerator()
7073

7174
export const setChartThemeGenerator = () => {
7275
let currentTheme: string | null = null
7376
let appTheme: string | null = null
7477

75-
return (newTheme: string, newAppTheme: Theme) => {
78+
return (newTheme: string, newAppTheme: StreamlitTheme) => {
7679
let themeChanged = false
7780
const renderedAppTheme = JSON.stringify(newAppTheme)
7881

@@ -102,7 +105,6 @@ export const setChartThemeGenerator = () => {
102105
return themeChanged
103106
}
104107
}
105-
const setChartTheme = setChartThemeGenerator()
106108

107109
export function getChartDimensions(
108110
plot: any,
@@ -262,9 +264,23 @@ const getOrCreateChart = (container: HTMLDivElement, key: string) => {
262264
*/
263265
const hasInitialized: Record<string, boolean> = {}
264266

265-
export default async function (
266-
component: StV2ComponentArgs<{}, ComponentData>
267-
) {
267+
/**
268+
* Component-specific theme setters to avoid state leakage between instances
269+
*/
270+
const componentThemeSetters: Record<
271+
string,
272+
ReturnType<typeof setChartThemeGenerator>
273+
> = {}
274+
275+
/**
276+
* Component-specific chart data getters to avoid state leakage between instances
277+
*/
278+
const componentChartDataGetters: Record<
279+
string,
280+
ReturnType<typeof getChartDataGenerator>
281+
> = {}
282+
283+
const bokehComponent: Component<{}, ComponentData> = async component => {
268284
const { parentElement, key } = component
269285
const {
270286
figure,
@@ -281,6 +297,20 @@ export default async function (
281297
hasInitialized[key] = true
282298
}
283299

300+
// Create a component-specific theme setter to avoid state leakage between
301+
// instances
302+
if (!componentThemeSetters[key]) {
303+
componentThemeSetters[key] = setChartThemeGenerator()
304+
}
305+
const setChartTheme = componentThemeSetters[key]
306+
307+
// Create a component-specific chart data getter to avoid state leakage
308+
// between instances
309+
if (!componentChartDataGetters[key]) {
310+
componentChartDataGetters[key] = getChartDataGenerator()
311+
}
312+
const getChartData = componentChartDataGetters[key]
313+
284314
const container =
285315
parentElement.querySelector<HTMLDivElement>(".stBokehContainer")
286316

@@ -294,20 +324,21 @@ export default async function (
294324
throw new Error("Chart not found")
295325
}
296326

297-
const getCssPropertyValue = (property: string) => {
327+
const getCssPropertyValue = (property: keyof StreamlitThemeCssProperties) => {
298328
const style = getComputedStyle(container)
299329
return style.getPropertyValue(property)
300330
}
301331

302332
const { data: chartData, hasChanged } = getChartData(figure, key)
303333
const themeChanged = setChartTheme(bokehTheme, {
304-
backgroundColor: getCssPropertyValue("--st-colors-bg-color"),
305-
primaryColor: getCssPropertyValue("--st-colors-primary"),
306-
secondaryBackgroundColor: getCssPropertyValue("--st-colors-secondary-bg"),
307-
textColor: getCssPropertyValue("--st-colors-heading-color"),
308-
// These are unused properties, but we need to provide them to satisfy the type
309-
base: "",
310-
font: "",
334+
backgroundColor: getCssPropertyValue("--st-background-color"),
335+
primaryColor: getCssPropertyValue("--st-primary-color"),
336+
secondaryBackgroundColor: getCssPropertyValue(
337+
"--st-secondary-background-color"
338+
),
339+
textColor: getCssPropertyValue("--st-text-color"),
340+
base: getCssPropertyValue("--st-base"),
341+
font: getCssPropertyValue("--st-font"),
311342
})
312343

313344
// NOTE: Each script run forces Bokeh to provide different ids for their
@@ -317,6 +348,6 @@ export default async function (
317348
if (hasChanged || themeChanged) {
318349
await updateChart(chartData, useContainerWidth, chart, container, key)
319350
}
320-
321-
return () => {}
322351
}
352+
353+
export default bokehComponent

0 commit comments

Comments
 (0)