first commit

This commit is contained in:
Stefan Hacker
2026-04-03 09:38:48 +02:00
commit 37ad745546
47450 changed files with 3120798 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
import * as React from 'react';
import type { IToggleProps } from './Toggle.types';
export declare const ToggleBase: React.FunctionComponent<IToggleProps>;
+118
View File
@@ -0,0 +1,118 @@
import { __assign } from "tslib";
import * as React from 'react';
import { useControllableValue, useId, useWarnings } from '@fluentui/react-hooks';
import { classNamesFunction, getNativeProps, inputProperties, useFocusRects } from '@fluentui/utilities';
import { Label } from '../Label/Label';
var getClassNames = classNamesFunction();
var COMPONENT_NAME = 'Toggle';
export var ToggleBase = React.forwardRef(function (props, forwardedRef) {
var _a = props.as, RootType = _a === void 0 ? 'div' : _a, ariaLabel = props.ariaLabel, controlledChecked = props.checked, className = props.className, _b = props.defaultChecked, defaultChecked = _b === void 0 ? false : _b, disabled = props.disabled, inlineLabel = props.inlineLabel, label = props.label,
// eslint-disable-next-line @typescript-eslint/no-deprecated
offAriaLabel = props.offAriaLabel, offText = props.offText,
// eslint-disable-next-line @typescript-eslint/no-deprecated
onAriaLabel = props.onAriaLabel, onChange = props.onChange,
// eslint-disable-next-line @typescript-eslint/no-deprecated
onChanged = props.onChanged, onToggleClick = props.onClick, onText = props.onText, role = props.role, styles = props.styles, theme = props.theme;
var _c = useControllableValue(controlledChecked, defaultChecked, React.useCallback(function (ev, isChecked) {
onChange === null || onChange === void 0 ? void 0 : onChange(ev, isChecked);
onChanged === null || onChanged === void 0 ? void 0 : onChanged(isChecked);
}, [onChange, onChanged])), checked = _c[0], setChecked = _c[1];
var classNames = getClassNames(styles, {
theme: theme,
className: className,
disabled: disabled,
checked: checked,
inlineLabel: inlineLabel,
onOffMissing: !onText && !offText,
});
var badAriaLabel = checked ? onAriaLabel : offAriaLabel;
var id = useId(COMPONENT_NAME, props.id);
var labelId = "".concat(id, "-label");
var stateTextId = "".concat(id, "-stateText");
var stateText = checked ? onText : offText;
var toggleNativeProps = getNativeProps(props, inputProperties, [
'defaultChecked',
]);
// The following properties take priority for what Narrator should read:
// 1. ariaLabel
// 2. onAriaLabel (if checked) or offAriaLabel (if not checked)
// 3. label, if existent
var labelledById = undefined;
if (!ariaLabel && !badAriaLabel) {
if (label) {
labelledById = labelId;
}
if (stateText && !labelledById) {
labelledById = stateTextId;
}
}
var toggleButton = React.useRef(null);
useFocusRects(toggleButton);
useComponentRef(props, checked, toggleButton);
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line react-hooks/rules-of-hooks -- build-time conditional
useWarnings({
name: COMPONENT_NAME,
props: props,
deprecations: {
offAriaLabel: undefined,
onAriaLabel: 'ariaLabel',
onChanged: 'onChange',
},
mutuallyExclusive: { checked: 'defaultChecked' },
});
}
var onClick = function (ev) {
if (!disabled) {
setChecked(!checked, ev);
if (onToggleClick) {
onToggleClick(ev);
}
}
};
var slotProps = {
root: {
className: classNames.root,
hidden: toggleNativeProps.hidden,
},
label: {
children: label,
className: classNames.label,
htmlFor: id,
id: labelId,
},
container: {
className: classNames.container,
},
pill: __assign(__assign({}, toggleNativeProps), { 'aria-disabled': disabled, 'aria-checked': checked, 'aria-label': ariaLabel ? ariaLabel : badAriaLabel, 'aria-labelledby': labelledById, className: classNames.pill, 'data-is-focusable': true, 'data-ktp-target': true, disabled: disabled, id: id, onClick: onClick, ref: toggleButton, role: role ? role : 'switch', type: 'button' }),
thumb: {
className: classNames.thumb,
},
stateText: {
children: stateText,
className: classNames.text,
htmlFor: id,
id: stateTextId,
},
};
return (React.createElement(RootType, __assign({ ref: forwardedRef }, slotProps.root),
label && React.createElement(Label, __assign({}, slotProps.label)),
React.createElement("div", __assign({}, slotProps.container),
React.createElement("button", __assign({}, slotProps.pill),
React.createElement("span", __assign({}, slotProps.thumb))),
((checked && onText) || offText) && React.createElement(Label, __assign({}, slotProps.stateText)))));
});
ToggleBase.displayName = COMPONENT_NAME + 'Base';
var useComponentRef = function (props, isChecked, toggleButtonRef) {
React.useImperativeHandle(props.componentRef, function () { return ({
get checked() {
return !!isChecked;
},
focus: function () {
if (toggleButtonRef.current) {
toggleButtonRef.current.focus();
}
},
}); }, [isChecked, toggleButtonRef]);
};
//# sourceMappingURL=Toggle.base.js.map
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
import * as React from 'react';
import type { IToggleProps } from './Toggle.types';
export declare const Toggle: React.FunctionComponent<IToggleProps>;
+7
View File
@@ -0,0 +1,7 @@
import { styled } from '@fluentui/utilities';
import { ToggleBase } from './Toggle.base';
import { getStyles } from './Toggle.styles';
export var Toggle = styled(ToggleBase, getStyles, undefined, {
scope: 'Toggle',
});
//# sourceMappingURL=Toggle.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Toggle.js","sourceRoot":"../src/","sources":["components/Toggle/Toggle.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,MAAM,CAAC,IAAM,MAAM,GAA0C,MAAM,CACjE,UAAU,EACV,SAAS,EACT,SAAS,EACT;IACE,KAAK,EAAE,QAAQ;CAChB,CACF,CAAC","sourcesContent":["import * as React from 'react';\nimport { styled } from '@fluentui/utilities';\nimport { ToggleBase } from './Toggle.base';\nimport { getStyles } from './Toggle.styles';\nimport type { IToggleProps, IToggleStyleProps, IToggleStyles } from './Toggle.types';\n\nexport const Toggle: React.FunctionComponent<IToggleProps> = styled<IToggleProps, IToggleStyleProps, IToggleStyles>(\n ToggleBase,\n getStyles,\n undefined,\n {\n scope: 'Toggle',\n },\n);\n"]}
@@ -0,0 +1,2 @@
import type { IToggleStyleProps, IToggleStyles } from './Toggle.types';
export declare const getStyles: (props: IToggleStyleProps) => IToggleStyles;
+229
View File
@@ -0,0 +1,229 @@
import { __assign } from "tslib";
import { HighContrastSelector, getFocusStyle, FontWeights, getHighContrastNoAdjustStyle, } from '@fluentui/style-utilities';
var DEFAULT_PILL_WIDTH = 40;
var DEFAULT_PILL_HEIGHT = 20;
var DEFAULT_THUMB_SIZE = 12;
export var getStyles = function (props) {
var _a, _b, _c, _d, _e, _f, _g;
var theme = props.theme, className = props.className, disabled = props.disabled, checked = props.checked, inlineLabel = props.inlineLabel, onOffMissing = props.onOffMissing;
var semanticColors = theme.semanticColors, palette = theme.palette;
// Tokens
var pillUncheckedBackground = semanticColors.bodyBackground;
var pillCheckedBackground = semanticColors.inputBackgroundChecked;
var pillCheckedHoveredBackground = semanticColors.inputBackgroundCheckedHovered;
var thumbUncheckedHoveredBackground = palette.neutralDark;
var pillCheckedDisabledBackground = semanticColors.disabledBodySubtext;
var thumbBackground = semanticColors.smallInputBorder;
var thumbCheckedBackground = semanticColors.inputForegroundChecked;
var thumbDisabledBackground = semanticColors.disabledBodySubtext;
var thumbCheckedDisabledBackground = semanticColors.disabledBackground;
var pillBorderColor = semanticColors.smallInputBorder;
var pillBorderHoveredColor = semanticColors.inputBorderHovered;
var pillBorderDisabledColor = semanticColors.disabledBodySubtext;
var textDisabledColor = semanticColors.disabledText;
return {
root: [
'ms-Toggle',
checked && 'is-checked',
!disabled && 'is-enabled',
disabled && 'is-disabled',
theme.fonts.medium,
{
marginBottom: '8px',
},
inlineLabel && {
display: 'flex',
alignItems: 'center',
},
className,
],
label: [
'ms-Toggle-label',
{ display: 'inline-block' },
disabled && {
color: textDisabledColor,
selectors: (_a = {},
_a[HighContrastSelector] = {
color: 'GrayText',
},
_a),
},
inlineLabel &&
!onOffMissing && {
marginRight: 16,
},
onOffMissing &&
inlineLabel && {
order: 1,
marginLeft: 16,
},
inlineLabel && { wordBreak: 'break-word' },
],
container: [
'ms-Toggle-innerContainer',
{
display: 'flex',
position: 'relative',
},
],
pill: [
'ms-Toggle-background',
getFocusStyle(theme, { inset: -3 }),
{
fontSize: '20px',
boxSizing: 'border-box',
width: DEFAULT_PILL_WIDTH,
height: DEFAULT_PILL_HEIGHT,
borderRadius: DEFAULT_PILL_HEIGHT / 2,
transition: 'all 0.1s ease',
border: "1px solid ".concat(pillBorderColor),
background: pillUncheckedBackground,
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
padding: '0 3px',
overflow: 'visible',
},
!disabled && [
!checked && {
selectors: {
':hover': [
{
borderColor: pillBorderHoveredColor,
},
],
':hover .ms-Toggle-thumb': [
{
backgroundColor: thumbUncheckedHoveredBackground,
selectors: (_b = {},
_b[HighContrastSelector] = {
borderColor: 'Highlight',
},
_b),
},
],
},
},
checked && [
{
background: pillCheckedBackground,
borderColor: 'transparent',
justifyContent: 'flex-end',
},
{
selectors: (_c = {
':hover': [
{
backgroundColor: pillCheckedHoveredBackground,
borderColor: 'transparent',
selectors: (_d = {},
_d[HighContrastSelector] = {
backgroundColor: 'Highlight',
},
_d),
},
]
},
_c[HighContrastSelector] = __assign({ backgroundColor: 'Highlight' }, getHighContrastNoAdjustStyle()),
_c),
},
],
],
disabled && [
{
cursor: 'default',
},
!checked && [
{
borderColor: pillBorderDisabledColor,
},
],
checked && [
{
backgroundColor: pillCheckedDisabledBackground,
borderColor: 'transparent',
justifyContent: 'flex-end',
},
],
],
!disabled && {
selectors: {
'&:hover': {
selectors: (_e = {},
_e[HighContrastSelector] = {
borderColor: 'Highlight',
},
_e),
},
},
},
],
thumb: [
'ms-Toggle-thumb',
{
display: 'block',
width: DEFAULT_THUMB_SIZE,
height: DEFAULT_THUMB_SIZE,
borderRadius: '50%',
transition: 'all 0.1s ease',
backgroundColor: thumbBackground,
/* Border is added to handle high contrast mode for Firefox */
borderColor: 'transparent',
borderWidth: DEFAULT_THUMB_SIZE / 2,
borderStyle: 'solid',
boxSizing: 'border-box',
},
!disabled &&
checked && [
{
backgroundColor: thumbCheckedBackground,
selectors: (_f = {},
_f[HighContrastSelector] = {
backgroundColor: 'Window',
borderColor: 'Window',
},
_f),
},
],
disabled && [
!checked && [
{
backgroundColor: thumbDisabledBackground,
},
],
checked && [
{
backgroundColor: thumbCheckedDisabledBackground,
},
],
],
],
text: [
'ms-Toggle-stateText',
{
selectors: {
// Workaround: make rules more specific than Label rules.
'&&': {
padding: '0',
margin: '0 8px',
userSelect: 'none',
fontWeight: FontWeights.regular,
},
},
},
disabled && {
selectors: {
'&&': {
color: textDisabledColor,
selectors: (_g = {},
_g[HighContrastSelector] = {
color: 'GrayText',
},
_g),
},
},
},
],
};
};
//# sourceMappingURL=Toggle.styles.js.map
File diff suppressed because one or more lines are too long
+150
View File
@@ -0,0 +1,150 @@
import * as React from 'react';
import type { IStyle, ITheme } from '@fluentui/style-utilities';
import type { IRefObject, IStyleFunctionOrObject, IComponentAs } from '@fluentui/utilities';
import type { JSXElement } from '@fluentui/utilities';
/**
* {@docCategory Toggle}
*/
export interface IToggle {
focus: () => void;
}
/**
* Toggle component props.
* {@docCategory Toggle}
*/
export interface IToggleProps extends React.HTMLAttributes<HTMLElement>, React.RefAttributes<HTMLElement> {
/**
* Render the root element as another type.
*/
as?: IComponentAs<React.HTMLAttributes<HTMLElement>>;
/**
* Optional callback to access the IToggle interface. Use this instead of ref for accessing
* the public methods and properties of the component.
*/
componentRef?: IRefObject<IToggle>;
/**
* A label for the toggle.
*/
label?: string | JSXElement;
/**
* Text to display when toggle is ON.
* Caution: when not providing on/off text user may get confused in differentiating the on/off states of the toggle.
*/
onText?: string;
/**
* Text to display when toggle is OFF.
* Caution: when not providing on/off text user may get confused in differentiating the on/off states of the toggle.
*/
offText?: string;
/**
* Text for screen-reader to announce as the name of the toggle.
*/
ariaLabel?: string;
/**
* @deprecated Use `ariaLabel` for name, and let the metadata convey state
*/
onAriaLabel?: string;
/**
* @deprecated Use `ariaLabel` for name, and let the metadata convey state
*/
offAriaLabel?: string;
/**
* Checked state of the toggle. If you are maintaining state yourself, use this property.
* Otherwise use `defaultChecked`.
*/
checked?: boolean;
/**
* Initial state of the toggle. If you want the toggle to maintain its own state, use this.
* Otherwise use `checked`.
*/
defaultChecked?: boolean;
/**
* Optional disabled flag.
*/
disabled?: boolean;
/**
* Whether the label (not the onText/offText) should be positioned inline with the toggle control.
* Left (right in RTL) side when on/off text provided VS right (left in RTL) side when no on/off text.
* Caution: when not providing on/off text user may get confused in differentiating the on/off states of the toggle.
*/
inlineLabel?: boolean;
/**
* Callback issued when the value changes.
*/
onChange?: (event: React.MouseEvent<HTMLElement>, checked?: boolean) => void;
/**
* @deprecated Use `onChange` instead.
*/
onChanged?: (checked: boolean) => void;
/**
* Theme provided by HOC.
*/
theme?: ITheme;
/**
* Optional styles for the component.
*/
styles?: IStyleFunctionOrObject<IToggleStyleProps, IToggleStyles>;
/**
* Whether to use the 'switch' role (ARIA 1.1) or the 'checkbox' role (ARIA 1.0).
* @default 'switch'
*/
role?: 'checkbox' | 'switch' | 'menuitemcheckbox';
}
/**
* Properties required to build the styles for the Toggle component.
* {@docCategory Toggle}
*/
export interface IToggleStyleProps {
/**
* Theme values.
*/
theme: ITheme;
/**
* Root element class name.
*/
className?: string;
/**
* Component is disabled.
*/
disabled?: boolean;
/**
* Component is checked.
*/
checked?: boolean;
/**
* Whether label should be positioned inline with the toggle.
*/
inlineLabel?: boolean;
/**
* Whether the user did not specify a on/off text. Influencing only when inlineLabel is used.
*/
onOffMissing?: boolean;
}
/**
* Styles for the Toggle component.
* {@docCategory Toggle}
*/
export interface IToggleStyles {
/** Root element. */
root: IStyle;
/**
* Label element above the toggle.
*/
label: IStyle;
/**
* Container for the toggle pill and the text next to it.
*/
container: IStyle;
/**
* Pill, rendered as a button.
*/
pill: IStyle;
/**
* Thumb inside of the pill.
*/
thumb: IStyle;
/**
* Text next to the pill.
*/
text: IStyle;
}
+2
View File
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=Toggle.types.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Toggle.types.js","sourceRoot":"../src/","sources":["components/Toggle/Toggle.types.ts"],"names":[],"mappings":"","sourcesContent":["import * as React from 'react';\nimport type { IStyle, ITheme } from '@fluentui/style-utilities';\nimport type { IRefObject, IStyleFunctionOrObject, IComponentAs } from '@fluentui/utilities';\n\nimport type { JSXElement } from '@fluentui/utilities';\n\n/**\n * {@docCategory Toggle}\n */\nexport interface IToggle {\n focus: () => void;\n}\n\n/**\n * Toggle component props.\n * {@docCategory Toggle}\n */\nexport interface IToggleProps extends React.HTMLAttributes<HTMLElement>, React.RefAttributes<HTMLElement> {\n /**\n * Render the root element as another type.\n */\n as?: IComponentAs<React.HTMLAttributes<HTMLElement>>;\n\n /**\n * Optional callback to access the IToggle interface. Use this instead of ref for accessing\n * the public methods and properties of the component.\n */\n componentRef?: IRefObject<IToggle>;\n\n /**\n * A label for the toggle.\n */\n\n label?: string | JSXElement;\n\n /**\n * Text to display when toggle is ON.\n * Caution: when not providing on/off text user may get confused in differentiating the on/off states of the toggle.\n */\n onText?: string;\n\n /**\n * Text to display when toggle is OFF.\n * Caution: when not providing on/off text user may get confused in differentiating the on/off states of the toggle.\n */\n offText?: string;\n\n /**\n * Text for screen-reader to announce as the name of the toggle.\n */\n ariaLabel?: string;\n\n /**\n * @deprecated Use `ariaLabel` for name, and let the metadata convey state\n */\n onAriaLabel?: string;\n\n /**\n * @deprecated Use `ariaLabel` for name, and let the metadata convey state\n */\n offAriaLabel?: string;\n\n /**\n * Checked state of the toggle. If you are maintaining state yourself, use this property.\n * Otherwise use `defaultChecked`.\n */\n checked?: boolean;\n\n /**\n * Initial state of the toggle. If you want the toggle to maintain its own state, use this.\n * Otherwise use `checked`.\n */\n defaultChecked?: boolean;\n\n /**\n * Optional disabled flag.\n */\n disabled?: boolean;\n\n /**\n * Whether the label (not the onText/offText) should be positioned inline with the toggle control.\n * Left (right in RTL) side when on/off text provided VS right (left in RTL) side when no on/off text.\n * Caution: when not providing on/off text user may get confused in differentiating the on/off states of the toggle.\n */\n inlineLabel?: boolean;\n\n /**\n * Callback issued when the value changes.\n */\n onChange?: (event: React.MouseEvent<HTMLElement>, checked?: boolean) => void;\n\n /**\n * @deprecated Use `onChange` instead.\n */\n onChanged?: (checked: boolean) => void;\n\n /**\n * Theme provided by HOC.\n */\n theme?: ITheme;\n\n /**\n * Optional styles for the component.\n */\n styles?: IStyleFunctionOrObject<IToggleStyleProps, IToggleStyles>;\n\n /**\n * Whether to use the 'switch' role (ARIA 1.1) or the 'checkbox' role (ARIA 1.0).\n * @default 'switch'\n */\n role?: 'checkbox' | 'switch' | 'menuitemcheckbox';\n}\n\n/**\n * Properties required to build the styles for the Toggle component.\n * {@docCategory Toggle}\n */\nexport interface IToggleStyleProps {\n /**\n * Theme values.\n */\n theme: ITheme;\n\n /**\n * Root element class name.\n */\n className?: string;\n\n /**\n * Component is disabled.\n */\n disabled?: boolean;\n\n /**\n * Component is checked.\n */\n checked?: boolean;\n\n /**\n * Whether label should be positioned inline with the toggle.\n */\n inlineLabel?: boolean;\n\n /**\n * Whether the user did not specify a on/off text. Influencing only when inlineLabel is used.\n */\n onOffMissing?: boolean;\n}\n\n/**\n * Styles for the Toggle component.\n * {@docCategory Toggle}\n */\nexport interface IToggleStyles {\n /** Root element. */\n root: IStyle;\n\n /**\n * Label element above the toggle.\n */\n label: IStyle;\n\n /**\n * Container for the toggle pill and the text next to it.\n */\n container: IStyle;\n\n /**\n * Pill, rendered as a button.\n */\n pill: IStyle;\n\n /**\n * Thumb inside of the pill.\n */\n thumb: IStyle;\n\n /**\n * Text next to the pill.\n */\n text: IStyle;\n}\n"]}
+3
View File
@@ -0,0 +1,3 @@
export * from './Toggle';
export * from './Toggle.base';
export * from './Toggle.types';
+4
View File
@@ -0,0 +1,4 @@
export * from './Toggle';
export * from './Toggle.base';
export * from './Toggle.types';
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"../src/","sources":["components/Toggle/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC","sourcesContent":["export * from './Toggle';\nexport * from './Toggle.base';\nexport * from './Toggle.types';\n"]}