Private
Public Access
1
0

feat: Fluent UI Outlook Lite + connections mockup

This commit is contained in:
2026-04-14 18:52:25 +00:00
parent 1199eff6c3
commit dfa4010406
34820 changed files with 1003813 additions and 205 deletions

View File

@@ -0,0 +1 @@
export { SpinButton, renderSpinButton_unstable, spinButtonClassNames, useSpinButtonStyles_unstable, useSpinButtonBase_unstable, useSpinButton_unstable } from './components/SpinButton/index';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/SpinButton.ts"],"sourcesContent":["export type {\n SpinButtonBaseProps,\n SpinButtonBaseState,\n SpinButtonBounds,\n SpinButtonChangeEvent,\n SpinButtonOnChangeData,\n SpinButtonProps,\n SpinButtonSlots,\n SpinButtonSpinState,\n SpinButtonState,\n} from './components/SpinButton/index';\nexport {\n SpinButton,\n renderSpinButton_unstable,\n spinButtonClassNames,\n useSpinButtonStyles_unstable,\n useSpinButtonBase_unstable,\n useSpinButton_unstable,\n} from './components/SpinButton/index';\n"],"names":["SpinButton","renderSpinButton_unstable","spinButtonClassNames","useSpinButtonStyles_unstable","useSpinButtonBase_unstable","useSpinButton_unstable"],"mappings":"AAWA,SACEA,UAAU,EACVC,yBAAyB,EACzBC,oBAAoB,EACpBC,4BAA4B,EAC5BC,0BAA0B,EAC1BC,sBAAsB,QACjB,gCAAgC"}

View File

@@ -0,0 +1,15 @@
'use client';
import * as React from 'react';
import { useSpinButton_unstable } from './useSpinButton';
import { renderSpinButton_unstable } from './renderSpinButton';
import { useSpinButtonStyles_unstable } from './useSpinButtonStyles.styles';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';
/**
* A SpinButton allows someone to incrementally adjust a value in small steps.
*/ export const SpinButton = /*#__PURE__*/ React.forwardRef((props, ref)=>{
const state = useSpinButton_unstable(props, ref);
useSpinButtonStyles_unstable(state);
useCustomStyleHook_unstable('useSpinButtonStyles_unstable')(state);
return renderSpinButton_unstable(state);
});
SpinButton.displayName = 'SpinButton';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/SpinButton/SpinButton.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useSpinButton_unstable } from './useSpinButton';\nimport { renderSpinButton_unstable } from './renderSpinButton';\nimport { useSpinButtonStyles_unstable } from './useSpinButtonStyles.styles';\nimport type { SpinButtonProps } from './SpinButton.types';\nimport type { ForwardRefComponent } from '@fluentui/react-utilities';\nimport { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';\n\n/**\n * A SpinButton allows someone to incrementally adjust a value in small steps.\n */\nexport const SpinButton: ForwardRefComponent<SpinButtonProps> = React.forwardRef((props, ref) => {\n const state = useSpinButton_unstable(props, ref);\n\n useSpinButtonStyles_unstable(state);\n\n useCustomStyleHook_unstable('useSpinButtonStyles_unstable')(state);\n\n return renderSpinButton_unstable(state);\n});\n\nSpinButton.displayName = 'SpinButton';\n"],"names":["React","useSpinButton_unstable","renderSpinButton_unstable","useSpinButtonStyles_unstable","useCustomStyleHook_unstable","SpinButton","forwardRef","props","ref","state","displayName"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,sBAAsB,QAAQ,kBAAkB;AACzD,SAASC,yBAAyB,QAAQ,qBAAqB;AAC/D,SAASC,4BAA4B,QAAQ,+BAA+B;AAG5E,SAASC,2BAA2B,QAAQ,kCAAkC;AAE9E;;CAEC,GACD,OAAO,MAAMC,2BAAmDL,MAAMM,UAAU,CAAC,CAACC,OAAOC;IACvF,MAAMC,QAAQR,uBAAuBM,OAAOC;IAE5CL,6BAA6BM;IAE7BL,4BAA4B,gCAAgCK;IAE5D,OAAOP,0BAA0BO;AACnC,GAAG;AAEHJ,WAAWK,WAAW,GAAG"}

View File

@@ -0,0 +1 @@
import * as React from 'react';

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
export { SpinButton } from './SpinButton';
export { renderSpinButton_unstable } from './renderSpinButton';
export { useSpinButtonBase_unstable, useSpinButton_unstable } from './useSpinButton';
export { spinButtonClassNames, useSpinButtonStyles_unstable } from './useSpinButtonStyles.styles';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/SpinButton/index.ts"],"sourcesContent":["export { SpinButton } from './SpinButton';\nexport type {\n SpinButtonBaseProps,\n SpinButtonBaseState,\n SpinButtonBounds,\n SpinButtonChangeEvent,\n SpinButtonOnChangeData,\n SpinButtonProps,\n SpinButtonSlots,\n SpinButtonSpinState,\n SpinButtonState,\n} from './SpinButton.types';\nexport { renderSpinButton_unstable } from './renderSpinButton';\nexport { useSpinButtonBase_unstable, useSpinButton_unstable } from './useSpinButton';\nexport { spinButtonClassNames, useSpinButtonStyles_unstable } from './useSpinButtonStyles.styles';\n"],"names":["SpinButton","renderSpinButton_unstable","useSpinButtonBase_unstable","useSpinButton_unstable","spinButtonClassNames","useSpinButtonStyles_unstable"],"mappings":"AAAA,SAASA,UAAU,QAAQ,eAAe;AAY1C,SAASC,yBAAyB,QAAQ,qBAAqB;AAC/D,SAASC,0BAA0B,EAAEC,sBAAsB,QAAQ,kBAAkB;AACrF,SAASC,oBAAoB,EAAEC,4BAA4B,QAAQ,+BAA+B"}

View File

@@ -0,0 +1,14 @@
import { jsx as _jsx, jsxs as _jsxs } from "@fluentui/react-jsx-runtime/jsx-runtime";
import { assertSlots } from '@fluentui/react-utilities';
/**
* Render the final JSX of SpinButton
*/ export const renderSpinButton_unstable = (state)=>{
assertSlots(state);
return /*#__PURE__*/ _jsxs(state.root, {
children: [
/*#__PURE__*/ _jsx(state.input, {}),
/*#__PURE__*/ _jsx(state.incrementButton, {}),
/*#__PURE__*/ _jsx(state.decrementButton, {})
]
});
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/SpinButton/renderSpinButton.tsx"],"sourcesContent":["/** @jsxRuntime automatic */\n/** @jsxImportSource @fluentui/react-jsx-runtime */\n\nimport { assertSlots } from '@fluentui/react-utilities';\nimport type { JSXElement } from '@fluentui/react-utilities';\nimport type { SpinButtonBaseState, SpinButtonSlots } from './SpinButton.types';\n\n/**\n * Render the final JSX of SpinButton\n */\nexport const renderSpinButton_unstable = (state: SpinButtonBaseState): JSXElement => {\n assertSlots<SpinButtonSlots>(state);\n\n return (\n <state.root>\n <state.input />\n <state.incrementButton />\n <state.decrementButton />\n </state.root>\n );\n};\n"],"names":["assertSlots","renderSpinButton_unstable","state","root","input","incrementButton","decrementButton"],"mappings":"AAAA,0BAA0B,GAC1B,iDAAiD;AAEjD,SAASA,WAAW,QAAQ,4BAA4B;AAIxD;;CAEC,GACD,OAAO,MAAMC,4BAA4B,CAACC;IACxCF,YAA6BE;IAE7B,qBACE,MAACA,MAAMC,IAAI;;0BACT,KAACD,MAAME,KAAK;0BACZ,KAACF,MAAMG,eAAe;0BACtB,KAACH,MAAMI,eAAe;;;AAG5B,EAAE"}

View File

@@ -0,0 +1,295 @@
'use client';
import * as React from 'react';
import { useFieldControlProps_unstable } from '@fluentui/react-field';
import { getPartitionedNativeProps, mergeCallbacks, useControllableState, useTimeout, slot, useMergedRefs } from '@fluentui/react-utilities';
import { ArrowUp, ArrowDown, End, Enter, Escape, Home, PageDown, PageUp } from '@fluentui/keyboard-keys';
import { calculatePrecision, precisionRound, getBound, clamp } from '../../utils/index';
import { ChevronUp16Regular, ChevronDown16Regular } from '@fluentui/react-icons';
import { useOverrides_unstable as useOverrides } from '@fluentui/react-shared-contexts';
const DEFAULT_SPIN_DELAY_MS = 150;
const MIN_SPIN_DELAY_MS = 80;
const MAX_SPIN_TIME_MS = 1000;
// This is here to give an ease for the mouse held down case.
// Exact easing it to be defined. Once it is we'll likely
// pull this out into a util function in the SpinButton package.
const lerp = (start, end, percent)=>start + (end - start) * percent;
/**
* Create the base state required to render SpinButton without design-specific props.
*
* @param props - props from this instance of SpinButton (without appearance/size)
* @param ref - reference to root HTMLElement of SpinButton
*/ export const useSpinButtonBase_unstable = (props, ref)=>{
const nativeProps = getPartitionedNativeProps({
props,
primarySlotTagName: 'input',
excludedPropNames: [
'defaultValue',
'max',
'min',
'onChange',
'value'
]
});
const { value, displayValue, defaultValue, min, max, step = 1, stepPage = 1, precision: precisionFromProps, onChange, root, input, incrementButton, decrementButton } = props;
const precision = React.useMemo(()=>{
return precisionFromProps !== null && precisionFromProps !== void 0 ? precisionFromProps : Math.max(calculatePrecision(step), 0);
}, [
precisionFromProps,
step
]);
const [currentValue, setCurrentValue] = useControllableState({
state: value,
defaultState: defaultValue,
initialState: 0
});
const inputRef = React.useRef(null);
const isControlled = value !== undefined;
const [textValue, setTextValue] = React.useState(undefined);
const [keyboardSpinState, setKeyboardSpinState] = React.useState('rest');
const internalState = React.useRef({
value: currentValue,
spinState: 'rest',
spinTime: 0,
spinDelay: DEFAULT_SPIN_DELAY_MS,
atBound: currentValue !== null ? getBound(precisionRound(currentValue, precision), min, max) : 'none'
});
const [setStepTimeout, clearStepTimeout] = useTimeout();
const stepValue = (e, direction, startFrom)=>{
let startValue = internalState.current.value;
if (startFrom) {
const num = parseFloat(startFrom);
if (!isNaN(num)) {
startValue = num;
}
}
const val = startValue;
const dir = direction === 'up' || direction === 'upPage' ? 1 : -1;
const stepSize = direction === 'upPage' || direction === 'downPage' ? stepPage : step;
if (val === null) {
const stepStart = min === undefined ? 0 : min;
const nullStep = clamp(stepStart + stepSize * dir, min, max);
commit(e, nullStep);
return;
}
let newValue = val + stepSize * dir;
if (!Number.isNaN(newValue)) {
newValue = clamp(newValue, min, max);
}
commit(e, newValue);
if (internalState.current.spinState !== 'rest') {
setStepTimeout(()=>{
// Ease the step speed a bit
internalState.current.spinTime += internalState.current.spinDelay;
internalState.current.spinDelay = lerp(DEFAULT_SPIN_DELAY_MS, MIN_SPIN_DELAY_MS, internalState.current.spinTime / MAX_SPIN_TIME_MS);
stepValue(e, direction);
}, internalState.current.spinDelay);
}
};
const handleInputChange = (e)=>{
if (!internalState.current.previousTextValue) {
internalState.current.previousTextValue = textValue !== null && textValue !== void 0 ? textValue : String(currentValue);
}
const newValue = e.target.value;
setTextValue(newValue);
if (inputRef.current) {
// we need to set this here using the IDL attribute directly, because otherwise the timing of the ARIA value update
// is not in sync with the user-entered native input value, and some screen readers end up reading the wrong value.
// eslint-disable-next-line react-compiler/react-compiler
inputRef.current.ariaValueNow = newValue;
}
};
const handleIncrementMouseDown = (e)=>{
commit(e, currentValue, textValue);
internalState.current.spinState = 'up';
stepValue(e, 'up');
};
const handleDecrementMouseDown = (e)=>{
commit(e, currentValue, textValue);
internalState.current.spinState = 'down';
stepValue(e, 'down');
};
const handleStepMouseUpOrLeave = (e)=>{
clearStepTimeout();
internalState.current.spinState = 'rest';
internalState.current.spinDelay = DEFAULT_SPIN_DELAY_MS;
internalState.current.spinTime = 0;
};
const handleBlur = (e)=>{
commit(e, currentValue, textValue);
internalState.current.previousTextValue = undefined;
};
const handleKeyDown = (e)=>{
let nextKeyboardSpinState = 'rest';
if (e.currentTarget.readOnly) {
return;
}
if (e.key === ArrowUp) {
stepValue(e, 'up', textValue);
nextKeyboardSpinState = 'up';
} else if (e.key === ArrowDown) {
stepValue(e, 'down', textValue);
nextKeyboardSpinState = 'down';
} else if (e.key === PageUp) {
e.preventDefault();
stepValue(e, 'upPage', textValue);
nextKeyboardSpinState = 'up';
} else if (e.key === PageDown) {
e.preventDefault();
stepValue(e, 'downPage', textValue);
nextKeyboardSpinState = 'down';
} else if (!e.shiftKey && e.key === Home && min !== undefined) {
commit(e, min);
nextKeyboardSpinState = 'down';
} else if (!e.shiftKey && e.key === End && max !== undefined) {
commit(e, max);
nextKeyboardSpinState = 'up';
} else if (e.key === Enter) {
commit(e, currentValue, textValue);
internalState.current.previousTextValue = undefined;
} else if (e.key === Escape) {
if (internalState.current.previousTextValue) {
setTextValue(undefined);
internalState.current.previousTextValue = undefined;
}
}
if (keyboardSpinState !== nextKeyboardSpinState) {
setKeyboardSpinState(nextKeyboardSpinState);
}
};
const handleKeyUp = (e)=>{
if (keyboardSpinState !== 'rest') {
setKeyboardSpinState('rest');
internalState.current.spinState = 'rest';
}
};
const commit = (e, newValue, newDisplayValue)=>{
const valueChanged = newValue !== undefined && currentValue !== newValue;
const displayValueChanged = newDisplayValue !== undefined && internalState.current.previousTextValue !== undefined && internalState.current.previousTextValue !== newDisplayValue;
let roundedValue;
if (valueChanged) {
roundedValue = precisionRound(newValue, precision);
setCurrentValue(roundedValue);
internalState.current.value = roundedValue;
} else if (displayValueChanged && !isControlled) {
const nextValue = parseFloat(newDisplayValue);
if (!isNaN(nextValue)) {
setCurrentValue(precisionRound(nextValue, precision));
internalState.current.value = precisionRound(nextValue, precision);
}
}
if (valueChanged || displayValueChanged) {
onChange === null || onChange === void 0 ? void 0 : onChange(e, {
value: roundedValue,
displayValue: newDisplayValue
});
}
setTextValue(undefined);
};
let valueToDisplay;
if (textValue !== undefined) {
valueToDisplay = textValue;
} else if (value === null || currentValue === null) {
valueToDisplay = displayValue !== null && displayValue !== void 0 ? displayValue : '';
internalState.current.value = null;
internalState.current.atBound = 'none';
} else {
const roundedValue = precisionRound(currentValue, precision);
internalState.current.value = roundedValue;
internalState.current.atBound = getBound(roundedValue, min, max);
if (isControlled) {
valueToDisplay = displayValue !== null && displayValue !== void 0 ? displayValue : String(roundedValue);
} else {
valueToDisplay = String(roundedValue);
}
}
const state = {
spinState: keyboardSpinState,
atBound: internalState.current.atBound,
components: {
root: 'span',
input: 'input',
incrementButton: 'button',
decrementButton: 'button'
},
root: slot.always(root, {
defaultProps: nativeProps.root,
elementType: 'span'
}),
input: slot.always(input, {
defaultProps: {
autoComplete: 'off',
role: 'spinbutton',
type: 'text',
...nativeProps.primary
},
elementType: 'input'
}),
incrementButton: slot.always(incrementButton, {
defaultProps: {
tabIndex: -1,
disabled: nativeProps.primary.readOnly || nativeProps.primary.disabled || internalState.current.atBound === 'max' || internalState.current.atBound === 'both',
'aria-label': 'Increment value',
type: 'button'
},
elementType: 'button'
}),
decrementButton: slot.always(decrementButton, {
defaultProps: {
tabIndex: -1,
disabled: nativeProps.primary.readOnly || nativeProps.primary.disabled || internalState.current.atBound === 'min' || internalState.current.atBound === 'both',
'aria-label': 'Decrement value',
type: 'button'
},
elementType: 'button'
})
};
state.input.value = valueToDisplay;
state.input.ref = useMergedRefs(inputRef, ref);
state.input['aria-valuemin'] = min;
state.input['aria-valuemax'] = max;
var _internalState_current_value;
state.input['aria-valuenow'] = (_internalState_current_value = internalState.current.value) !== null && _internalState_current_value !== void 0 ? _internalState_current_value : undefined;
var _state_input_ariavaluetext;
state.input['aria-valuetext'] = (_state_input_ariavaluetext = state.input['aria-valuetext']) !== null && _state_input_ariavaluetext !== void 0 ? _state_input_ariavaluetext : value !== undefined && displayValue || undefined;
state.input.onChange = mergeCallbacks(state.input.onChange, handleInputChange);
state.input.onInput = mergeCallbacks(state.input.onInput, handleInputChange);
state.input.onBlur = mergeCallbacks(state.input.onBlur, handleBlur);
state.input.onKeyDown = mergeCallbacks(state.input.onKeyDown, handleKeyDown);
state.input.onKeyUp = mergeCallbacks(state.input.onKeyUp, handleKeyUp);
state.incrementButton.onMouseDown = mergeCallbacks(handleIncrementMouseDown, state.incrementButton.onMouseDown);
state.incrementButton.onMouseUp = mergeCallbacks(state.incrementButton.onMouseUp, handleStepMouseUpOrLeave);
state.incrementButton.onMouseLeave = mergeCallbacks(state.incrementButton.onMouseLeave, handleStepMouseUpOrLeave);
state.decrementButton.onMouseDown = mergeCallbacks(handleDecrementMouseDown, state.decrementButton.onMouseDown);
state.decrementButton.onMouseUp = mergeCallbacks(state.decrementButton.onMouseUp, handleStepMouseUpOrLeave);
state.decrementButton.onMouseLeave = mergeCallbacks(state.decrementButton.onMouseLeave, handleStepMouseUpOrLeave);
return state;
};
/**
* Create the state required to render SpinButton.
*
* The returned state can be modified with hooks such as useSpinButtonStyles_unstable,
* before being passed to renderSpinButton_unstable.
*
* @param props - props from this instance of SpinButton
* @param ref - reference to root HTMLElement of SpinButton
*/ export const useSpinButton_unstable = (props, ref)=>{
var _state_incrementButton, _state_decrementButton;
// Merge props from surrounding <Field>, if any
props = useFieldControlProps_unstable(props, {
supportsLabelFor: true,
supportsRequired: true
});
const overrides = useOverrides();
var _overrides_inputDefaultAppearance;
const { appearance = (_overrides_inputDefaultAppearance = overrides.inputDefaultAppearance) !== null && _overrides_inputDefaultAppearance !== void 0 ? _overrides_inputDefaultAppearance : 'outline', size = 'medium', ...baseProps } = props;
const state = useSpinButtonBase_unstable(baseProps, ref);
var _children;
(_children = (_state_incrementButton = state.incrementButton).children) !== null && _children !== void 0 ? _children : _state_incrementButton.children = /*#__PURE__*/ React.createElement(ChevronUp16Regular, null);
var _children1;
(_children1 = (_state_decrementButton = state.decrementButton).children) !== null && _children1 !== void 0 ? _children1 : _state_decrementButton.children = /*#__PURE__*/ React.createElement(ChevronDown16Regular, null);
return {
...state,
appearance,
size
};
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,236 @@
'use client';
import { __resetStyles, __styles, mergeClasses, shorthands } from '@griffel/react';
import { tokens, typographyStyles } from '@fluentui/react-theme';
export const spinButtonClassNames = {
root: 'fui-SpinButton',
input: 'fui-SpinButton__input',
incrementButton: 'fui-SpinButton__incrementButton',
decrementButton: 'fui-SpinButton__decrementButton'
};
const spinButtonExtraClassNames = {
buttonActive: 'fui-SpinButton__button_active'
};
const fieldHeights = {
small: '24px',
medium: '32px'
};
const useRootClassName = /*#__PURE__*/__resetStyles("r109xulx", "r1h2jnch", {
r: [".r109xulx{display:inline-grid;grid-template-columns:1fr 24px;grid-template-rows:1fr 1fr;column-gap:var(--spacingHorizontalXS);row-gap:0;position:relative;isolation:isolate;vertical-align:middle;background-color:var(--colorNeutralBackground1);min-height:32px;padding:0 0 0 var(--spacingHorizontalMNudge);border-radius:var(--borderRadiusMedium);}", ".r109xulx::before{content:\"\";box-sizing:border-box;position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;z-index:10;border:1px solid var(--colorNeutralStroke1);border-bottom-color:var(--colorNeutralStrokeAccessible);border-radius:var(--borderRadiusMedium);}", ".r109xulx::after{box-sizing:border-box;content:\"\";position:absolute;right:0;bottom:0;left:0;z-index:20;height:max(2px, var(--borderRadiusMedium));border-bottom-left-radius:var(--borderRadiusMedium);border-bottom-right-radius:var(--borderRadiusMedium);border-bottom:2px solid var(--colorCompoundBrandStroke);clip-path:inset(calc(100% - 2px) 0 0 0);transform:scaleX(0);transition-property:transform;transition-duration:var(--durationUltraFast);transition-delay:var(--curveAccelerateMid);}", ".r109xulx:focus-within::after{transform:scaleX(1);transition-property:transform;transition-duration:var(--durationNormal);transition-delay:var(--curveDecelerateMid);}", ".r109xulx:focus-within:active::after{border-bottom-color:var(--colorCompoundBrandStrokePressed);}", ".r109xulx:focus-within{outline:2px solid transparent;}", ".r1h2jnch{display:inline-grid;grid-template-columns:1fr 24px;grid-template-rows:1fr 1fr;column-gap:var(--spacingHorizontalXS);row-gap:0;position:relative;isolation:isolate;vertical-align:middle;background-color:var(--colorNeutralBackground1);min-height:32px;padding:0 var(--spacingHorizontalMNudge) 0 0;border-radius:var(--borderRadiusMedium);}", ".r1h2jnch::before{content:\"\";box-sizing:border-box;position:absolute;top:0;left:0;bottom:0;right:0;pointer-events:none;z-index:10;border:1px solid var(--colorNeutralStroke1);border-bottom-color:var(--colorNeutralStrokeAccessible);border-radius:var(--borderRadiusMedium);}", ".r1h2jnch::after{box-sizing:border-box;content:\"\";position:absolute;left:0;bottom:0;right:0;z-index:20;height:max(2px, var(--borderRadiusMedium));border-bottom-right-radius:var(--borderRadiusMedium);border-bottom-left-radius:var(--borderRadiusMedium);border-bottom:2px solid var(--colorCompoundBrandStroke);clip-path:inset(calc(100% - 2px) 0 0 0);transform:scaleX(0);transition-property:transform;transition-duration:var(--durationUltraFast);transition-delay:var(--curveAccelerateMid);}", ".r1h2jnch:focus-within::after{transform:scaleX(1);transition-property:transform;transition-duration:var(--durationNormal);transition-delay:var(--curveDecelerateMid);}", ".r1h2jnch:focus-within:active::after{border-bottom-color:var(--colorCompoundBrandStrokePressed);}", ".r1h2jnch:focus-within{outline:2px solid transparent;}"],
s: ["@media screen and (prefers-reduced-motion: reduce){.r109xulx::after{transition-duration:0.01ms;transition-delay:0.01ms;}}", "@media screen and (prefers-reduced-motion: reduce){.r109xulx:focus-within::after{transition-duration:0.01ms;transition-delay:0.01ms;}}", "@media screen and (prefers-reduced-motion: reduce){.r1h2jnch::after{transition-duration:0.01ms;transition-delay:0.01ms;}}", "@media screen and (prefers-reduced-motion: reduce){.r1h2jnch:focus-within::after{transition-duration:0.01ms;transition-delay:0.01ms;}}"]
});
const useRootStyles = /*#__PURE__*/__styles({
small: {
sshi5w: "f1pha7fy",
Bahqtrf: "fk6fouc",
Be2twd7: "fy9rknc",
Bhrd7zp: "figsok6",
Bg96gwp: "fwrc4pm",
uwmqm3: ["f1f5gg8d", "f1vdfbxk"]
},
medium: {},
outline: {},
outlineInteractive: {
Bo3r8zu: "f1w2y1rc",
Hpvxnh: ["f1gofhvl", "f18htlvq"],
Bx11ytk: "ffcnd28",
B1rg0w0: ["f18htlvq", "f1gofhvl"],
Bsg1tlv: "f6lmxco",
Brjw370: ["fcoc0mf", "f15r4wkl"],
xcfy85: "f1ipdth8",
Bcc6kan: ["f15r4wkl", "fcoc0mf"]
},
underline: {
B0qfbqy: "f1o236ok",
B4f6apu: ["faeg28l", "f64aojp"],
y0oebl: "fdw6hkg",
uvfttm: ["f64aojp", "faeg28l"],
r59vdv: 0,
Budzafs: 0,
ck0cow: 0,
n07z76: 0,
Gng75u: "f1xyh2jw"
},
underlineInteractive: {
Bx11ytk: "ffcnd28",
xcfy85: "f1ipdth8",
d9w3h3: 0,
B3778ie: 0,
B4j8arr: 0,
Bl18szs: 0,
Blrzh8d: "fkp7w9h"
},
filled: {
Bcgcnre: 0,
Bqjgrrk: 0,
qa3bma: 0,
y0oebl: 0,
Biqmznv: 0,
Bm6vgfq: 0,
Bbv0w2i: 0,
uvfttm: 0,
eqrjj: 0,
Bk5zm6e: 0,
m598lv: 0,
B4f6apu: 0,
ydt019: 0,
Bq4z7u6: 0,
Bdkvgpv: 0,
B0qfbqy: 0,
kj8mxx: "f1kc0wz4"
},
"filled-darker": {
De3pzq: "f16xq7d1"
},
"filled-lighter": {
De3pzq: "fxugw4r"
},
filledInteractive: {
B05mzqr: "f1xqt08",
tb9y6h: ["fzt5lgo", "f8tv3r9"],
jcehpj: "fyhrops",
B23o0hn: ["f8tv3r9", "fzt5lgo"]
},
invalid: {
emecyz: "fl48pg9",
lz0pba: ["f1a168p3", "f1pvdymy"],
Bo1k74p: "f11knvgl",
Ba322q7: ["f1pvdymy", "f1a168p3"]
},
disabled: {
Bceei9c: "fdrzuqr",
De3pzq: "f1c21dwh",
Bq4z7u6: "f1a0lfh7",
Bk5zm6e: ["f1p2ejm6", "fmzytvz"],
Bqjgrrk: "fas2e61",
Bm6vgfq: ["fmzytvz", "f1p2ejm6"],
Bvljrlq: "f1p5b8em",
Cqojjj: ["fs6f9xf", "f11b7h5x"],
G3zxag: "f1vrn6tw",
H8270r: ["f11b7h5x", "fs6f9xf"]
}
}, {
d: [".f1pha7fy{min-height:24px;}", ".fk6fouc{font-family:var(--fontFamilyBase);}", ".fy9rknc{font-size:var(--fontSizeBase200);}", ".figsok6{font-weight:var(--fontWeightRegular);}", ".fwrc4pm{line-height:var(--lineHeightBase200);}", ".f1f5gg8d{padding-left:var(--spacingHorizontalS);}", ".f1vdfbxk{padding-right:var(--spacingHorizontalS);}", ".f1o236ok::before{border-top-width:0;}", ".faeg28l::before{border-right-width:0;}", ".f64aojp::before{border-left-width:0;}", ".fdw6hkg::before{border-bottom-width:1px;}", [".f1xyh2jw::before{border-radius:var(--borderRadiusNone);}", {
p: -1
}], [".fkp7w9h::after{border-radius:var(--borderRadiusNone);}", {
p: -1
}], [".f1kc0wz4::before{border:1px solid var(--colorTransparentStroke);}", {
p: -2
}], ".f16xq7d1{background-color:var(--colorNeutralBackground3);}", ".fxugw4r{background-color:var(--colorNeutralBackground1);}", ".fl48pg9:not(:focus-within)::before,.fl48pg9:hover:not(:focus-within)::before{border-top-color:var(--colorPaletteRedBorder2);}", ".f1a168p3:not(:focus-within)::before,.f1a168p3:hover:not(:focus-within)::before{border-right-color:var(--colorPaletteRedBorder2);}", ".f1pvdymy:not(:focus-within)::before,.f1pvdymy:hover:not(:focus-within)::before{border-left-color:var(--colorPaletteRedBorder2);}", ".f11knvgl:not(:focus-within)::before,.f11knvgl:hover:not(:focus-within)::before{border-bottom-color:var(--colorPaletteRedBorder2);}", ".fdrzuqr{cursor:not-allowed;}", ".f1c21dwh{background-color:var(--colorTransparentBackground);}", ".f1a0lfh7::before{border-top-color:var(--colorNeutralStrokeDisabled);}", ".f1p2ejm6::before{border-right-color:var(--colorNeutralStrokeDisabled);}", ".fmzytvz::before{border-left-color:var(--colorNeutralStrokeDisabled);}", ".fas2e61::before{border-bottom-color:var(--colorNeutralStrokeDisabled);}"],
h: [".f1w2y1rc:hover::before{border-top-color:var(--colorNeutralStroke1Hover);}", ".f1gofhvl:hover::before{border-right-color:var(--colorNeutralStroke1Hover);}", ".f18htlvq:hover::before{border-left-color:var(--colorNeutralStroke1Hover);}", ".ffcnd28:hover::before{border-bottom-color:var(--colorNeutralStrokeAccessibleHover);}", ".f1xqt08:hover::before,.f1xqt08:focus-within::before{border-top-color:var(--colorTransparentStrokeInteractive);}", ".fzt5lgo:hover::before,.fzt5lgo:focus-within::before{border-right-color:var(--colorTransparentStrokeInteractive);}", ".f8tv3r9:hover::before,.f8tv3r9:focus-within::before{border-left-color:var(--colorTransparentStrokeInteractive);}", ".fyhrops:hover::before,.fyhrops:focus-within::before{border-bottom-color:var(--colorTransparentStrokeInteractive);}"],
a: [".f6lmxco:active::before,.f6lmxco:focus-within::before{border-top-color:var(--colorNeutralStroke1Pressed);}", ".fcoc0mf:active::before,.fcoc0mf:focus-within::before{border-right-color:var(--colorNeutralStroke1Pressed);}", ".f15r4wkl:active::before,.f15r4wkl:focus-within::before{border-left-color:var(--colorNeutralStroke1Pressed);}", ".f1ipdth8:active::before,.f1ipdth8:focus-within::before{border-bottom-color:var(--colorNeutralStrokeAccessiblePressed);}"],
m: [["@media (forced-colors: active){.f1p5b8em::before{border-top-color:GrayText;}}", {
m: "(forced-colors: active)"
}], ["@media (forced-colors: active){.f11b7h5x::before{border-left-color:GrayText;}.fs6f9xf::before{border-right-color:GrayText;}}", {
m: "(forced-colors: active)"
}], ["@media (forced-colors: active){.f1vrn6tw::before{border-bottom-color:GrayText;}}", {
m: "(forced-colors: active)"
}]]
});
const useInputClassName = /*#__PURE__*/__resetStyles("r1ljrqje", null, [".r1ljrqje{grid-column-start:1;grid-column-end:2;grid-row-start:1;grid-row-end:3;outline-style:none;border:0;padding:0;color:var(--colorNeutralForeground1);background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;width:100%;}", ".r1ljrqje::-webkit-input-placeholder{color:var(--colorNeutralForeground4);opacity:1;}", ".r1ljrqje::-moz-placeholder{color:var(--colorNeutralForeground4);opacity:1;}", ".r1ljrqje::placeholder{color:var(--colorNeutralForeground4);opacity:1;}"]);
const useInputStyles = /*#__PURE__*/__styles({
disabled: {
sj55zd: "f1s2aq7o",
Bceei9c: "fdrzuqr",
De3pzq: "f1c21dwh",
yvdlaj: "fahhnxm"
}
}, {
d: [".f1s2aq7o{color:var(--colorNeutralForegroundDisabled);}", ".fdrzuqr{cursor:not-allowed;}", ".f1c21dwh{background-color:var(--colorTransparentBackground);}", ".fahhnxm::-webkit-input-placeholder{color:var(--colorNeutralForegroundDisabled);}", ".fahhnxm::-moz-placeholder{color:var(--colorNeutralForegroundDisabled);}"]
});
const useBaseButtonClassName = /*#__PURE__*/__resetStyles("r1g4chgs", null, [".r1g4chgs{display:inline-flex;width:24px;align-items:center;justify-content:center;border:0;position:absolute;outline-style:none;height:16px;background-color:transparent;color:var(--colorNeutralForeground3);grid-column-start:2;border-radius:0;padding:0 5px 0 5px;}", ".r1g4chgs:active{outline-style:none;}", ".r1g4chgs:enabled:hover{cursor:pointer;color:var(--colorNeutralForeground3Hover);background-color:var(--colorSubtleBackgroundHover);}", ".r1g4chgs:enabled:active{color:var(--colorNeutralForeground3Pressed);background-color:var(--colorSubtleBackgroundPressed);}", ".r1g4chgs:enabled.fui-SpinButton__button_active{color:var(--colorNeutralForeground3Pressed);background-color:var(--colorSubtleBackgroundPressed);}", ".r1g4chgs:disabled{cursor:not-allowed;color:var(--colorNeutralForegroundDisabled);}"]);
const useButtonStyles = /*#__PURE__*/__styles({
increment: {
Ijaq50: "f16hsg94",
B7oj6ja: ["f1jar5jt", "fyu767a"],
z8tnut: "f10ra9hq",
Byoj8tv: "f1brlhvm"
},
decrement: {
Ijaq50: "faunodf",
Bbmb7ep: ["f1aa9q02", "f16jpd5f"],
z8tnut: "f1sl3k7w",
Byoj8tv: "f1y2xyjm"
},
incrementButtonSmall: {
Byoj8tv: 0,
uwmqm3: 0,
z189sj: 0,
z8tnut: 0,
B0ocmuz: ["f4lv8q1", "fm3uwd2"],
Bqenvij: "fvblgha"
},
decrementButtonSmall: {
Byoj8tv: 0,
uwmqm3: 0,
z189sj: 0,
z8tnut: 0,
B0ocmuz: ["f1q86st8", "frkrfqj"],
Bqenvij: "fvblgha"
},
outline: {},
underline: {
De3pzq: "f3rmtva",
sj55zd: "f11d4kpn",
r4wkhp: "f1no7wuu",
B95qlz1: "f1bifk9c",
p743kt: "fp1zg4s",
B7xitij: "fo6hitd",
B6siaa6: "f1wiab75",
Ba9qmo4: "fj9zm5z",
Dyrjrp: "f1cqwcg4"
},
"filled-darker": {
De3pzq: "f3rmtva",
sj55zd: "f11d4kpn",
r4wkhp: "f1no7wuu",
B95qlz1: "fwwxidx",
p743kt: "fp1zg4s",
B7xitij: "f14i52sd",
B6siaa6: "f1wiab75",
Ba9qmo4: "fwry2ka",
Dyrjrp: "f1cqwcg4"
},
"filled-lighter": {
De3pzq: "f3rmtva",
sj55zd: "f11d4kpn",
r4wkhp: "f1no7wuu",
B95qlz1: "f1yywxnv",
drw0cw: "fzaa11h",
idzz8t: "f4fpmm9",
Dyrjrp: "f1cqwcg4"
}
}, {
d: [".f16hsg94{grid-row-start:1;}", ".f1jar5jt{border-top-right-radius:var(--borderRadiusMedium);}", ".fyu767a{border-top-left-radius:var(--borderRadiusMedium);}", ".f10ra9hq{padding-top:4px;}", ".f1brlhvm{padding-bottom:1px;}", ".faunodf{grid-row-start:2;}", ".f1aa9q02{border-bottom-right-radius:var(--borderRadiusMedium);}", ".f16jpd5f{border-bottom-left-radius:var(--borderRadiusMedium);}", ".f1sl3k7w{padding-top:1px;}", ".f1y2xyjm{padding-bottom:4px;}", [".f4lv8q1{padding:3px 6px 0px 4px;}", {
p: -1
}], [".fm3uwd2{padding:3px 4px 0px 6px;}", {
p: -1
}], ".fvblgha{height:12px;}", [".f1q86st8{padding:0px 6px 3px 4px;}", {
p: -1
}], [".frkrfqj{padding:0px 4px 3px 6px;}", {
p: -1
}], ".f3rmtva{background-color:transparent;}", ".f11d4kpn{color:var(--colorNeutralForeground3);}", ".f1no7wuu:enabled:hover{color:var(--colorNeutralForeground3Hover);}", ".f1bifk9c:enabled:hover{background-color:var(--colorSubtleBackgroundHover);}", ".fp1zg4s:enabled:active{color:var(--colorNeutralForeground3Pressed);}", ".fo6hitd:enabled:active{background-color:var(--colorSubtleBackgroundPressed);}", ".f1wiab75:enabled.fui-SpinButton__button_active{color:var(--colorNeutralForeground3Pressed);}", ".fj9zm5z:enabled.fui-SpinButton__button_active{background-color:var(--colorSubtleBackgroundPressed);}", ".f1cqwcg4:disabled{color:var(--colorNeutralForegroundDisabled);}", ".fwwxidx:enabled:hover{background-color:var(--colorNeutralBackground3Hover);}", ".f14i52sd:enabled:active{background-color:var(--colorNeutralBackground3Pressed);}", ".fwry2ka:enabled.fui-SpinButton__button_active{background-color:var(--colorNeutralBackground3Pressed);}", ".f1yywxnv:enabled:hover{background-color:var(--colorNeutralBackground1Hover);}", ".fzaa11h:enabled:active,.fzaa11h:enabled.fui-SpinButton__button_active{color:var(--colorNeutralForeground3Pressed);}", ".f4fpmm9:enabled:active,.f4fpmm9:enabled.fui-SpinButton__button_active{background-color:var(--colorNeutralBackground1Pressed);}"]
});
/**
* Apply styling to the SpinButton slots based on the state
*/
export const useSpinButtonStyles_unstable = state => {
'use no memo';
const {
appearance,
spinState,
size
} = state;
const disabled = state.input.disabled;
const invalid = `${state.input['aria-invalid']}` === 'true';
const filled = appearance.startsWith('filled');
const rootStyles = useRootStyles();
const buttonStyles = useButtonStyles();
const inputStyles = useInputStyles();
state.root.className = mergeClasses(spinButtonClassNames.root, useRootClassName(), rootStyles[size], rootStyles[appearance], filled && rootStyles.filled, !disabled && appearance === 'outline' && rootStyles.outlineInteractive, !disabled && appearance === 'underline' && rootStyles.underlineInteractive, !disabled && filled && rootStyles.filledInteractive, !disabled && invalid && rootStyles.invalid, disabled && rootStyles.disabled, state.root.className);
state.incrementButton.className = mergeClasses(spinButtonClassNames.incrementButton, spinState === 'up' && `${spinButtonExtraClassNames.buttonActive}`, useBaseButtonClassName(), buttonStyles.increment, buttonStyles[appearance], size === 'small' && buttonStyles.incrementButtonSmall, state.incrementButton.className);
state.decrementButton.className = mergeClasses(spinButtonClassNames.decrementButton, spinState === 'down' && `${spinButtonExtraClassNames.buttonActive}`, useBaseButtonClassName(), buttonStyles.decrement, buttonStyles[appearance], size === 'small' && buttonStyles.decrementButtonSmall, state.decrementButton.className);
state.input.className = mergeClasses(spinButtonClassNames.input, useInputClassName(), disabled && inputStyles.disabled, state.input.className);
return state;
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,360 @@
'use client';
import { makeResetStyles, makeStyles, mergeClasses, shorthands } from '@griffel/react';
import { tokens, typographyStyles } from '@fluentui/react-theme';
export const spinButtonClassNames = {
root: 'fui-SpinButton',
input: 'fui-SpinButton__input',
incrementButton: 'fui-SpinButton__incrementButton',
decrementButton: 'fui-SpinButton__decrementButton'
};
const spinButtonExtraClassNames = {
buttonActive: 'fui-SpinButton__button_active'
};
const fieldHeights = {
small: '24px',
medium: '32px'
};
const useRootClassName = makeResetStyles({
display: 'inline-grid',
gridTemplateColumns: `1fr 24px`,
gridTemplateRows: '1fr 1fr',
columnGap: tokens.spacingHorizontalXS,
rowGap: 0,
position: 'relative',
isolation: 'isolate',
verticalAlign: 'middle',
backgroundColor: tokens.colorNeutralBackground1,
minHeight: fieldHeights.medium,
padding: `0 0 0 ${tokens.spacingHorizontalMNudge}`,
borderRadius: tokens.borderRadiusMedium,
// Apply border styles on the ::before pseudo element.
// We cannot use ::after since that is used for selection.
// Using the pseudo element allows us to place the border
// above content in the component which ensures the buttons
// line up visually with the border as expected. Without this
// there is a bit of a gap which can become very noticeable
// at high zoom or when OS zoom levels are not divisible by 2
// (e.g., 150% on Windows in Firefox)
// This is most noticeable on the "outline" appearance which is
// also the default so it feels worth the extra ceremony to get right.
'::before': {
content: '""',
boxSizing: 'border-box',
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0,
pointerEvents: 'none',
zIndex: 10,
border: `1px solid ${tokens.colorNeutralStroke1}`,
borderBottomColor: tokens.colorNeutralStrokeAccessible,
borderRadius: tokens.borderRadiusMedium
},
'::after': {
boxSizing: 'border-box',
content: '""',
position: 'absolute',
right: 0,
bottom: 0,
left: 0,
zIndex: 20,
// Maintaining the correct corner radius:
// Use the whole border-radius as the height and only put radii on the bottom corners.
// (Otherwise the radius would be automatically reduced to fit available space.)
// max() ensures the focus border still shows up even if someone sets tokens.borderRadiusMedium to 0.
height: `max(2px, ${tokens.borderRadiusMedium})`,
borderBottomLeftRadius: tokens.borderRadiusMedium,
borderBottomRightRadius: tokens.borderRadiusMedium,
// Flat 2px border:
// By default borderBottom will cause little "horns" on the ends. The clipPath trims them off.
// (This could be done without trimming using `background: linear-gradient(...)`, but using
// borderBottom makes it easier for people to override the color if needed.)
borderBottom: `2px solid ${tokens.colorCompoundBrandStroke}`,
clipPath: 'inset(calc(100% - 2px) 0 0 0)',
// Animation for focus OUT
transform: 'scaleX(0)',
transitionProperty: 'transform',
transitionDuration: tokens.durationUltraFast,
transitionDelay: tokens.curveAccelerateMid,
'@media screen and (prefers-reduced-motion: reduce)': {
transitionDuration: '0.01ms',
transitionDelay: '0.01ms'
}
},
':focus-within::after': {
// Animation for focus IN
transform: 'scaleX(1)',
transitionProperty: 'transform',
transitionDuration: tokens.durationNormal,
transitionDelay: tokens.curveDecelerateMid,
'@media screen and (prefers-reduced-motion: reduce)': {
transitionDuration: '0.01ms',
transitionDelay: '0.01ms'
}
},
':focus-within:active::after': {
// This is if the user clicks the field again while it's already focused
borderBottomColor: tokens.colorCompoundBrandStrokePressed
},
':focus-within': {
outline: '2px solid transparent'
}
});
const useRootStyles = makeStyles({
small: {
minHeight: fieldHeights.small,
...typographyStyles.caption1,
paddingLeft: tokens.spacingHorizontalS
},
medium: {
},
outline: {
},
outlineInteractive: {
':hover::before': {
...shorthands.borderColor(tokens.colorNeutralStroke1Hover),
borderBottomColor: tokens.colorNeutralStrokeAccessibleHover
},
// DO NOT add a space between the selectors! It changes the behavior of make-styles.
':active,:focus-within': {
'::before': {
...shorthands.borderColor(tokens.colorNeutralStroke1Pressed),
borderBottomColor: tokens.colorNeutralStrokeAccessiblePressed
}
}
},
underline: {
'::before': {
...shorthands.borderWidth(0, 0, '1px', 0),
borderRadius: tokens.borderRadiusNone
}
},
underlineInteractive: {
':hover::before': {
borderBottomColor: tokens.colorNeutralStrokeAccessibleHover
},
// DO NOT add a space between the selectors! It changes the behavior of make-styles.
':active,:focus-within': {
'::before': {
borderBottomColor: tokens.colorNeutralStrokeAccessiblePressed
}
},
'::after': {
borderRadius: tokens.borderRadiusNone
}
},
filled: {
'::before': {
border: `1px solid ${tokens.colorTransparentStroke}`
}
},
'filled-darker': {
backgroundColor: tokens.colorNeutralBackground3
},
'filled-lighter': {
backgroundColor: tokens.colorNeutralBackground1
},
filledInteractive: {
// DO NOT add a space between the selectors! It changes the behavior of make-styles.
':hover,:focus-within': {
'::before': {
// also handles pressed border color (:active)
...shorthands.borderColor(tokens.colorTransparentStrokeInteractive)
}
}
},
invalid: {
':not(:focus-within),:hover:not(:focus-within)': {
'::before': {
...shorthands.borderColor(tokens.colorPaletteRedBorder2)
}
}
},
disabled: {
cursor: 'not-allowed',
backgroundColor: tokens.colorTransparentBackground,
'::before': {
...shorthands.borderColor(tokens.colorNeutralStrokeDisabled),
'@media (forced-colors: active)': {
...shorthands.borderColor('GrayText')
}
}
}
});
const useInputClassName = makeResetStyles({
gridColumnStart: '1',
gridColumnEnd: '2',
gridRowStart: '1',
gridRowEnd: '3',
outlineStyle: 'none',
border: '0',
padding: '0',
color: tokens.colorNeutralForeground1,
// Use literal "transparent" (not from the theme) to always let the color from the root show through
backgroundColor: 'transparent',
fontFamily: 'inherit',
fontSize: 'inherit',
fontWeight: 'inherit',
lineHeight: 'inherit',
width: '100%',
'::placeholder': {
color: tokens.colorNeutralForeground4,
opacity: 1
}
});
const useInputStyles = makeStyles({
disabled: {
color: tokens.colorNeutralForegroundDisabled,
cursor: 'not-allowed',
backgroundColor: tokens.colorTransparentBackground,
'::placeholder': {
color: tokens.colorNeutralForegroundDisabled
}
}
});
const useBaseButtonClassName = makeResetStyles({
display: 'inline-flex',
width: '24px',
alignItems: 'center',
justifyContent: 'center',
border: '0',
position: 'absolute',
outlineStyle: 'none',
height: '16px',
// Use literal "transparent" (not from the theme) to always let the color from the root show through
backgroundColor: 'transparent',
color: tokens.colorNeutralForeground3,
// common button layout
gridColumnStart: '2',
borderRadius: '0',
padding: '0 5px 0 5px',
':active': {
outlineStyle: 'none'
},
':enabled': {
':hover': {
cursor: 'pointer',
color: tokens.colorNeutralForeground3Hover,
backgroundColor: tokens.colorSubtleBackgroundHover
},
':active': {
color: tokens.colorNeutralForeground3Pressed,
backgroundColor: tokens.colorSubtleBackgroundPressed
},
[`&.${spinButtonExtraClassNames.buttonActive}`]: {
color: tokens.colorNeutralForeground3Pressed,
backgroundColor: tokens.colorSubtleBackgroundPressed
}
},
':disabled': {
cursor: 'not-allowed',
color: tokens.colorNeutralForegroundDisabled
}
});
const useButtonStyles = makeStyles({
increment: {
gridRowStart: '1',
borderTopRightRadius: tokens.borderRadiusMedium,
paddingTop: '4px',
paddingBottom: '1px'
},
decrement: {
gridRowStart: '2',
borderBottomRightRadius: tokens.borderRadiusMedium,
paddingTop: '1px',
paddingBottom: '4px'
},
// Padding values numbers don't align with design specs
// but visually the padding aligns.
// The icons are set in a 16x16px square but the artwork is inset from that
// so these padding values are computed by hand.
// Additionally the design uses fractional values so these are
// rounded to the nearest integer.
incrementButtonSmall: {
padding: '3px 6px 0px 4px',
height: '12px'
},
decrementButtonSmall: {
padding: '0px 6px 3px 4px',
height: '12px'
},
outline: {
},
underline: {
backgroundColor: 'transparent',
color: tokens.colorNeutralForeground3,
':enabled': {
':hover': {
color: tokens.colorNeutralForeground3Hover,
backgroundColor: tokens.colorSubtleBackgroundHover
},
':active': {
color: tokens.colorNeutralForeground3Pressed,
backgroundColor: tokens.colorSubtleBackgroundPressed
},
[`&.${spinButtonExtraClassNames.buttonActive}`]: {
color: tokens.colorNeutralForeground3Pressed,
backgroundColor: tokens.colorSubtleBackgroundPressed
}
},
':disabled': {
color: tokens.colorNeutralForegroundDisabled
}
},
'filled-darker': {
backgroundColor: 'transparent',
color: tokens.colorNeutralForeground3,
':enabled': {
':hover': {
color: tokens.colorNeutralForeground3Hover,
backgroundColor: tokens.colorNeutralBackground3Hover
},
':active': {
color: tokens.colorNeutralForeground3Pressed,
backgroundColor: tokens.colorNeutralBackground3Pressed
},
[`&.${spinButtonExtraClassNames.buttonActive}`]: {
color: tokens.colorNeutralForeground3Pressed,
backgroundColor: tokens.colorNeutralBackground3Pressed
}
},
':disabled': {
color: tokens.colorNeutralForegroundDisabled
}
},
'filled-lighter': {
backgroundColor: 'transparent',
color: tokens.colorNeutralForeground3,
':enabled': {
':hover': {
color: tokens.colorNeutralForeground3Hover,
backgroundColor: tokens.colorNeutralBackground1Hover
},
[`:active,&.${spinButtonExtraClassNames.buttonActive}`]: {
color: tokens.colorNeutralForeground3Pressed,
backgroundColor: tokens.colorNeutralBackground1Pressed
}
},
':disabled': {
color: tokens.colorNeutralForegroundDisabled
}
}
});
/**
* Apply styling to the SpinButton slots based on the state
*/ export const useSpinButtonStyles_unstable = (state)=>{
'use no memo';
const { appearance, spinState, size } = state;
const disabled = state.input.disabled;
const invalid = `${state.input['aria-invalid']}` === 'true';
const filled = appearance.startsWith('filled');
const rootStyles = useRootStyles();
const buttonStyles = useButtonStyles();
const inputStyles = useInputStyles();
state.root.className = mergeClasses(spinButtonClassNames.root, useRootClassName(), rootStyles[size], rootStyles[appearance], filled && rootStyles.filled, !disabled && appearance === 'outline' && rootStyles.outlineInteractive, !disabled && appearance === 'underline' && rootStyles.underlineInteractive, !disabled && filled && rootStyles.filledInteractive, !disabled && invalid && rootStyles.invalid, disabled && rootStyles.disabled, state.root.className);
state.incrementButton.className = mergeClasses(spinButtonClassNames.incrementButton, spinState === 'up' && `${spinButtonExtraClassNames.buttonActive}`, useBaseButtonClassName(), buttonStyles.increment, buttonStyles[appearance], size === 'small' && buttonStyles.incrementButtonSmall, state.incrementButton.className);
state.decrementButton.className = mergeClasses(spinButtonClassNames.decrementButton, spinState === 'down' && `${spinButtonExtraClassNames.buttonActive}`, useBaseButtonClassName(), buttonStyles.decrement, buttonStyles[appearance], size === 'small' && buttonStyles.decrementButtonSmall, state.decrementButton.className);
state.input.className = mergeClasses(spinButtonClassNames.input, useInputClassName(), disabled && inputStyles.disabled, state.input.className);
return state;
};

File diff suppressed because one or more lines are too long

1
node_modules/@fluentui/react-spinbutton/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1 @@
export { SpinButton, renderSpinButton_unstable, spinButtonClassNames, useSpinButtonStyles_unstable, useSpinButtonBase_unstable, useSpinButton_unstable } from './SpinButton';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {\n SpinButton,\n renderSpinButton_unstable,\n spinButtonClassNames,\n useSpinButtonStyles_unstable,\n useSpinButtonBase_unstable,\n useSpinButton_unstable,\n} from './SpinButton';\nexport type {\n SpinButtonBaseProps,\n SpinButtonBaseState,\n SpinButtonOnChangeData,\n SpinButtonChangeEvent,\n SpinButtonProps,\n SpinButtonSlots,\n SpinButtonState,\n SpinButtonSpinState,\n SpinButtonBounds,\n} from './SpinButton';\n"],"names":["SpinButton","renderSpinButton_unstable","spinButtonClassNames","useSpinButtonStyles_unstable","useSpinButtonBase_unstable","useSpinButton_unstable"],"mappings":"AAAA,SACEA,UAAU,EACVC,yBAAyB,EACzBC,oBAAoB,EACpBC,4BAA4B,EAC5BC,0BAA0B,EAC1BC,sBAAsB,QACjB,eAAe"}

View File

@@ -0,0 +1,23 @@
export const clamp = (value, min, max)=>{
let nextValue = value;
if (min !== undefined) {
if (max !== undefined && min > max) {
const error = new Error();
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
console.error([
`"min" value "${min}" is greater than "max" value "${max}".`,
'"min" must be less than or equal to "max".',
`Returning value "${value}".`,
error.stack
].join());
}
return value;
}
nextValue = Math.max(min, nextValue);
}
if (max !== undefined) {
nextValue = Math.min(max, nextValue);
}
return nextValue;
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/clamp.ts"],"sourcesContent":["export const clamp = (value: number, min?: number, max?: number): number => {\n let nextValue = value;\n if (min !== undefined) {\n if (max !== undefined && min > max) {\n const error = new Error();\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line no-console\n console.error(\n [\n `\"min\" value \"${min}\" is greater than \"max\" value \"${max}\".`,\n '\"min\" must be less than or equal to \"max\".',\n `Returning value \"${value}\".`,\n error.stack,\n ].join(),\n );\n }\n return value;\n }\n\n nextValue = Math.max(min, nextValue);\n }\n\n if (max !== undefined) {\n nextValue = Math.min(max, nextValue);\n }\n\n return nextValue;\n};\n"],"names":["clamp","value","min","max","nextValue","undefined","error","Error","process","env","NODE_ENV","console","stack","join","Math"],"mappings":"AAAA,OAAO,MAAMA,QAAQ,CAACC,OAAeC,KAAcC;IACjD,IAAIC,YAAYH;IAChB,IAAIC,QAAQG,WAAW;QACrB,IAAIF,QAAQE,aAAaH,MAAMC,KAAK;YAClC,MAAMG,QAAQ,IAAIC;YAClB,IAAIC,QAAQC,GAAG,CAACC,QAAQ,KAAK,cAAc;gBACzC,sCAAsC;gBACtCC,QAAQL,KAAK,CACX;oBACE,CAAC,aAAa,EAAEJ,IAAI,+BAA+B,EAAEC,IAAI,EAAE,CAAC;oBAC5D;oBACA,CAAC,iBAAiB,EAAEF,MAAM,EAAE,CAAC;oBAC7BK,MAAMM,KAAK;iBACZ,CAACC,IAAI;YAEV;YACA,OAAOZ;QACT;QAEAG,YAAYU,KAAKX,GAAG,CAACD,KAAKE;IAC5B;IAEA,IAAID,QAAQE,WAAW;QACrBD,YAAYU,KAAKZ,GAAG,CAACC,KAAKC;IAC5B;IAEA,OAAOA;AACT,EAAE"}

View File

@@ -0,0 +1,11 @@
export const getBound = (value, min, max)=>{
if (min !== undefined && value === min) {
if (max === min) {
return 'both';
}
return 'min';
} else if (max !== undefined && value === max) {
return 'max';
}
return 'none';
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/getBound.ts"],"sourcesContent":["import type { SpinButtonBounds } from '../SpinButton';\n\nexport const getBound = (value: number, min?: number, max?: number): SpinButtonBounds => {\n if (min !== undefined && value === min) {\n if (max === min) {\n return 'both';\n }\n return 'min';\n } else if (max !== undefined && value === max) {\n return 'max';\n }\n\n return 'none';\n};\n"],"names":["getBound","value","min","max","undefined"],"mappings":"AAEA,OAAO,MAAMA,WAAW,CAACC,OAAeC,KAAcC;IACpD,IAAID,QAAQE,aAAaH,UAAUC,KAAK;QACtC,IAAIC,QAAQD,KAAK;YACf,OAAO;QACT;QACA,OAAO;IACT,OAAO,IAAIC,QAAQC,aAAaH,UAAUE,KAAK;QAC7C,OAAO;IACT;IAEA,OAAO;AACT,EAAE"}

View File

@@ -0,0 +1,3 @@
export { clamp } from './clamp';
export { getBound } from './getBound';
export { calculatePrecision, precisionRound } from './precision';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/index.ts"],"sourcesContent":["export { clamp } from './clamp';\nexport { getBound } from './getBound';\nexport { calculatePrecision, precisionRound } from './precision';\n"],"names":["clamp","getBound","calculatePrecision","precisionRound"],"mappings":"AAAA,SAASA,KAAK,QAAQ,UAAU;AAChC,SAASC,QAAQ,QAAQ,aAAa;AACtC,SAASC,kBAAkB,EAAEC,cAAc,QAAQ,cAAc"}

View File

@@ -0,0 +1,32 @@
/**
* Calculates a number's precision based on the number of trailing
* zeros if the number does not have a decimal indicated by a negative
* precision. Otherwise, it calculates the number of digits after
* the decimal point indicated by a positive precision.
* @param value - the value to determine the precision of
*/ export function calculatePrecision(value) {
/**
* Group 1:
* [1-9]([0]+$) matches trailing zeros
* Group 2:
* \.([0-9]*) matches all digits after a decimal point.
*/ const groups = /[1-9]([0]+$)|\.([0-9]*)/.exec(String(value));
if (!groups) {
return 0;
}
if (groups[1]) {
return -groups[1].length;
}
if (groups[2]) {
return groups[2].length;
}
return 0;
}
/**
* Rounds a number to a certain level of precision. Accepts negative precision.
* @param value - The value that is being rounded.
* @param precision - The number of decimal places to round the number to
*/ export function precisionRound(value, precision, base = 10) {
const exp = base ** precision;
return Math.round(value * exp) / exp;
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/precision.ts"],"sourcesContent":["/**\n * Calculates a number's precision based on the number of trailing\n * zeros if the number does not have a decimal indicated by a negative\n * precision. Otherwise, it calculates the number of digits after\n * the decimal point indicated by a positive precision.\n * @param value - the value to determine the precision of\n */\nexport function calculatePrecision(value: number | string): number {\n /**\n * Group 1:\n * [1-9]([0]+$) matches trailing zeros\n * Group 2:\n * \\.([0-9]*) matches all digits after a decimal point.\n */\n const groups = /[1-9]([0]+$)|\\.([0-9]*)/.exec(String(value));\n if (!groups) {\n return 0;\n }\n if (groups[1]) {\n return -groups[1].length;\n }\n if (groups[2]) {\n return groups[2].length;\n }\n return 0;\n}\n\n/**\n * Rounds a number to a certain level of precision. Accepts negative precision.\n * @param value - The value that is being rounded.\n * @param precision - The number of decimal places to round the number to\n */\nexport function precisionRound(value: number, precision: number, base: number = 10): number {\n const exp = base ** precision;\n return Math.round(value * exp) / exp;\n}\n"],"names":["calculatePrecision","value","groups","exec","String","length","precisionRound","precision","base","exp","Math","round"],"mappings":"AAAA;;;;;;CAMC,GACD,OAAO,SAASA,mBAAmBC,KAAsB;IACvD;;;;;GAKC,GACD,MAAMC,SAAS,0BAA0BC,IAAI,CAACC,OAAOH;IACrD,IAAI,CAACC,QAAQ;QACX,OAAO;IACT;IACA,IAAIA,MAAM,CAAC,EAAE,EAAE;QACb,OAAO,CAACA,MAAM,CAAC,EAAE,CAACG,MAAM;IAC1B;IACA,IAAIH,MAAM,CAAC,EAAE,EAAE;QACb,OAAOA,MAAM,CAAC,EAAE,CAACG,MAAM;IACzB;IACA,OAAO;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASC,eAAeL,KAAa,EAAEM,SAAiB,EAAEC,OAAe,EAAE;IAChF,MAAMC,MAAMD,QAAQD;IACpB,OAAOG,KAAKC,KAAK,CAACV,QAAQQ,OAAOA;AACnC"}