/
vshmidt
/
streamlit
Обзор
Документация
Войти
/
vshmidt
/
streamlit
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
frontend/lib/src/components/widgets/Checkbox/Checkbox.tsx
269 строк
8 KB
Maya Barnes
Bind widgets to query params - `st.checkbox` & `st.toggle` (#13900)
11 фев 2026, 19:42
Не верифицирован
11 фев 2026, 19:42
e91dc7e
Код
Авторство
О чём код?
/** * Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { memo, ReactElement, useCallback } from "react" import { LABEL_PLACEMENT, STYLE_TYPE, Checkbox as UICheckbox, } from "baseui/checkbox" import { Checkbox as CheckboxProto } from "@streamlit/protobuf" import StreamlitMarkdown from "~lib/components/shared/StreamlitMarkdown" import { Placement } from "~lib/components/shared/Tooltip" import { WidgetLabelHelpIconInline } from "~lib/components/widgets/BaseWidget" import { useBasicWidgetState, ValueWithSource, } from "~lib/hooks/useBasicWidgetState" import { useEmotionTheme } from "~lib/hooks/useEmotionTheme" import { hasLightBackgroundColor } from "~lib/theme" import { labelVisibilityProtoValueToEnum } from "~lib/util/utils" import { WidgetStateManager } from "~lib/WidgetStateManager" import { StyledCheckbox, StyledContent } from "./styled-components" export interface Props { disabled: boolean element: CheckboxProto widgetMgr: WidgetStateManager fragmentId?: string } function Checkbox({ element, disabled, widgetMgr, fragmentId, }: Readonly<Props>): ReactElement { const queryParamBinding = element.queryParamKey ? { paramKey: element.queryParamKey, valueType: "bool_value" as const, // Checkbox/toggle is not clearable (always true or false) clearable: false, } : undefined const [value, setValueWithSource] = useBasicWidgetState< boolean, CheckboxProto >({ getStateFromWidgetMgr, getDefaultStateFromProto, getCurrStateFromProto, updateWidgetMgrState, element, widgetMgr, fragmentId, queryParamBinding, }) const onChange = useCallback( (e: React.ChangeEvent<HTMLInputElement>): void => { setValueWithSource({ value: e.target.checked, fromUi: true }) }, // ESLint complains if we remove this unnecessary dep. [setValueWithSource] ) const theme = useEmotionTheme() const { colors, spacing, sizes } = theme const lightTheme = hasLightBackgroundColor(theme) const color = disabled ? colors.fadedText40 : colors.bodyText return ( <StyledCheckbox className="row-widget stCheckbox" data-testid="stCheckbox"> <UICheckbox checked={value} disabled={disabled} onChange={onChange} aria-label={element.label} checkmarkType={ element.type === CheckboxProto.StyleType.TOGGLE ? STYLE_TYPE.toggle : STYLE_TYPE.default } labelPlacement={LABEL_PLACEMENT.right} overrides={{ Root: { style: ({ $isFocusVisible }: { $isFocusVisible: boolean }) => ({ marginBottom: spacing.none, marginTop: spacing.none, backgroundColor: $isFocusVisible ? colors.darkenedBgMix25 : "", display: "flex", alignItems: "start", }), }, Toggle: { style: ({ $checked }: { $checked: boolean }) => { let backgroundColor = lightTheme ? colors.bgColor : colors.bodyText if (disabled) { backgroundColor = lightTheme ? colors.gray70 : colors.gray90 } return { width: `calc(${sizes.checkbox} - ${theme.spacing.twoXS})`, height: `calc(${sizes.checkbox} - ${theme.spacing.twoXS})`, transform: $checked ? `translateX(${sizes.checkbox})` : "", backgroundColor, boxShadow: "", } }, }, ToggleTrack: { style: ({ $checked, $isHovered, }: { $checked: boolean $isHovered: boolean }) => { let backgroundColor = colors.borderColor if ($isHovered && !disabled) { backgroundColor = colors.darkenedBgMix15 } if ($checked && !disabled) { backgroundColor = colors.primary } return { marginRight: 0, marginLeft: 0, marginBottom: 0, marginTop: theme.spacing.twoXS, paddingLeft: theme.spacing.threeXS, paddingRight: theme.spacing.threeXS, width: `calc(2 * ${sizes.checkbox})`, minWidth: `calc(2 * ${sizes.checkbox})`, height: sizes.checkbox, minHeight: sizes.checkbox, borderBottomLeftRadius: theme.radii.full, borderTopLeftRadius: theme.radii.full, borderBottomRightRadius: theme.radii.full, borderTopRightRadius: theme.radii.full, backgroundColor, } }, }, Checkmark: { style: ({ $isFocusVisible, $checked, }: { $isFocusVisible: boolean $checked: boolean }) => { const borderColor = $checked && !disabled ? colors.primary : colors.borderColor return { outline: 0, width: sizes.checkbox, height: sizes.checkbox, marginTop: theme.spacing.twoXS, marginLeft: 0, marginBottom: 0, boxShadow: $isFocusVisible && $checked ? theme.shadows.focusRing : "", // This is painfully verbose, but baseweb seems to internally // use the long-hand version, which means we can't use the // shorthand names here as if we do we'll end up with warn // logs spamming us every time a checkbox is rendered. borderLeftWidth: sizes.borderWidth, borderRightWidth: sizes.borderWidth, borderTopWidth: sizes.borderWidth, borderBottomWidth: sizes.borderWidth, borderLeftColor: borderColor, borderRightColor: borderColor, borderTopColor: borderColor, borderBottomColor: borderColor, } }, }, Label: { style: { lineHeight: theme.lineHeights.small, paddingLeft: theme.spacing.sm, position: "relative", color, }, }, }} > <StyledContent visibility={labelVisibilityProtoValueToEnum( element.labelVisibility?.value )} data-testid="stWidgetLabel" > <StreamlitMarkdown source={element.label} allowHTML={false} isLabel largerLabel /> {element.help && ( <WidgetLabelHelpIconInline content={element.help} placement={Placement.TOP_RIGHT} label={element.label} /> )} </StyledContent> </UICheckbox> </StyledCheckbox> ) } function getStateFromWidgetMgr( widgetMgr: WidgetStateManager, element: CheckboxProto ): boolean | undefined { return widgetMgr.getBoolValue(element) } function getDefaultStateFromProto(element: CheckboxProto): boolean { return element.default ?? false } function getCurrStateFromProto(element: CheckboxProto): boolean { return element.value ?? false } function updateWidgetMgrState( element: CheckboxProto, widgetMgr: WidgetStateManager, vws: ValueWithSource<boolean>, fragmentId?: string ): void { widgetMgr.setBoolValue( element, vws.value, { fromUi: vws.fromUi }, fragmentId ) } export default memo(Checkbox)