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,17 @@
'use client';
import * as React from 'react';
import { useRating_unstable } from './useRating';
import { renderRating_unstable } from './renderRating';
import { useRatingStyles_unstable } from './useRatingStyles.styles';
import { useRatingContextValues } from './useRatingContextValues';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';
/**
* Rating is a wrapper for one or more rating items that will be used to set a rating value.
*/ export const Rating = /*#__PURE__*/ React.forwardRef((props, ref)=>{
const state = useRating_unstable(props, ref);
const contextValues = useRatingContextValues(state);
useRatingStyles_unstable(state);
useCustomStyleHook_unstable('useRatingStyles_unstable')(state);
return renderRating_unstable(state, contextValues);
});
Rating.displayName = 'Rating';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Rating/Rating.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { ForwardRefComponent } from '@fluentui/react-utilities';\nimport { useRating_unstable } from './useRating';\nimport { renderRating_unstable } from './renderRating';\nimport { useRatingStyles_unstable } from './useRatingStyles.styles';\nimport type { RatingProps } from './Rating.types';\nimport { useRatingContextValues } from './useRatingContextValues';\nimport { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';\n\n/**\n * Rating is a wrapper for one or more rating items that will be used to set a rating value.\n */\nexport const Rating: ForwardRefComponent<RatingProps> = React.forwardRef((props, ref) => {\n const state = useRating_unstable(props, ref);\n const contextValues = useRatingContextValues(state);\n\n useRatingStyles_unstable(state);\n useCustomStyleHook_unstable('useRatingStyles_unstable')(state);\n return renderRating_unstable(state, contextValues);\n});\n\nRating.displayName = 'Rating';\n"],"names":["React","useRating_unstable","renderRating_unstable","useRatingStyles_unstable","useRatingContextValues","useCustomStyleHook_unstable","Rating","forwardRef","props","ref","state","contextValues","displayName"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAE/B,SAASC,kBAAkB,QAAQ,cAAc;AACjD,SAASC,qBAAqB,QAAQ,iBAAiB;AACvD,SAASC,wBAAwB,QAAQ,2BAA2B;AAEpE,SAASC,sBAAsB,QAAQ,2BAA2B;AAClE,SAASC,2BAA2B,QAAQ,kCAAkC;AAE9E;;CAEC,GACD,OAAO,MAAMC,uBAA2CN,MAAMO,UAAU,CAAC,CAACC,OAAOC;IAC/E,MAAMC,QAAQT,mBAAmBO,OAAOC;IACxC,MAAME,gBAAgBP,uBAAuBM;IAE7CP,yBAAyBO;IACzBL,4BAA4B,4BAA4BK;IACxD,OAAOR,sBAAsBQ,OAAOC;AACtC,GAAG;AAEHL,OAAOM,WAAW,GAAG"}

View File

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

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Rating/Rating.types.ts"],"sourcesContent":["import * as React from 'react';\nimport type { ComponentProps, ComponentState, EventData, EventHandler, Slot } from '@fluentui/react-utilities';\nimport { RatingItemContextValue } from '../RatingItem/RatingItem.types';\n\nexport type RatingSlots = {\n root: NonNullable<Slot<'div'>>;\n};\n\n/**\n * Rating Props\n */\nexport type RatingProps = Omit<ComponentProps<Partial<RatingSlots>>, 'onChange'> & {\n /**\n * Controls the color of the Rating.\n * @default neutral\n */\n color?: 'brand' | 'marigold' | 'neutral';\n /**\n * Default value of the Rating\n */\n defaultValue?: number;\n /**\n * The icon to display when the rating value is greater than or equal to the item's value.\n */\n iconFilled?: React.ElementType;\n /**\n * The icon to display when the rating value is less than the item's value.\n */\n iconOutline?: React.ElementType;\n /**\n * Prop to generate the aria-label for the rating inputs.\n * @default (rating) =\\> `${rating}`\n */\n itemLabel?: (rating: number) => string;\n /**\n * The max value of the rating. This controls the number of rating items displayed.\n * Must be a whole number greater than 1.\n * @default 5\n */\n max?: number;\n /**\n * Name for the Radio inputs. If not provided, one will be automatically generated\n */\n name?: string;\n /**\n * Callback when the rating value is changed by the user.\n */\n onChange?: EventHandler<RatingOnChangeEventData>;\n /**\n * Sets the precision to allow half-filled shapes in Rating\n * @default 1\n */\n step?: 0.5 | 1;\n /**\n * Sets the size of the Rating items.\n * @default extra-large\n */\n size?: 'small' | 'medium' | 'large' | 'extra-large';\n /**\n * The value of the rating\n */\n value?: number;\n};\n\n/**\n * Data for the onChange event for Rating.\n */\nexport type RatingOnChangeEventData = EventData<'change', React.FormEvent<HTMLDivElement>> & {\n /**\n * The new value of the rating.\n */\n value: number;\n};\n\n/**\n * Rating base props — excludes design props (color, size).\n */\nexport type RatingBaseProps = Omit<RatingProps, 'color' | 'size'>;\n\n/**\n * State used in rendering Rating\n */\nexport type RatingState = ComponentState<RatingSlots> &\n Required<Pick<RatingProps, 'color' | 'iconFilled' | 'iconOutline' | 'name' | 'step' | 'size' | 'value'>> &\n Pick<RatingProps, 'itemLabel'> & {\n hoveredValue?: number | undefined;\n };\n\n/**\n * Rating base state — excludes design props (color, size).\n */\nexport type RatingBaseState = Omit<RatingState, 'color' | 'size'>;\n\nexport type RatingContextValues = {\n ratingItem: RatingItemContextValue;\n};\n"],"names":["React"],"mappings":"AAAA,YAAYA,WAAW,QAAQ"}

View File

@@ -0,0 +1,5 @@
export { Rating } from './Rating';
export { renderRating_unstable } from './renderRating';
export { useRating_unstable, useRatingBase_unstable } from './useRating';
export { ratingClassNames, useRatingStyles_unstable } from './useRatingStyles.styles';
export { useRatingContextValues } from './useRatingContextValues';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Rating/index.ts"],"sourcesContent":["export { Rating } from './Rating';\nexport type {\n RatingContextValues,\n RatingOnChangeEventData,\n RatingProps,\n RatingBaseProps,\n RatingSlots,\n RatingState,\n RatingBaseState,\n} from './Rating.types';\nexport { renderRating_unstable } from './renderRating';\nexport { useRating_unstable, useRatingBase_unstable } from './useRating';\nexport { ratingClassNames, useRatingStyles_unstable } from './useRatingStyles.styles';\nexport { useRatingContextValues } from './useRatingContextValues';\n"],"names":["Rating","renderRating_unstable","useRating_unstable","useRatingBase_unstable","ratingClassNames","useRatingStyles_unstable","useRatingContextValues"],"mappings":"AAAA,SAASA,MAAM,QAAQ,WAAW;AAUlC,SAASC,qBAAqB,QAAQ,iBAAiB;AACvD,SAASC,kBAAkB,EAAEC,sBAAsB,QAAQ,cAAc;AACzE,SAASC,gBAAgB,EAAEC,wBAAwB,QAAQ,2BAA2B;AACtF,SAASC,sBAAsB,QAAQ,2BAA2B"}

View File

@@ -0,0 +1,12 @@
import { jsx as _jsx } from "@fluentui/react-jsx-runtime/jsx-runtime";
import { assertSlots } from '@fluentui/react-utilities';
import { RatingItemProvider } from '../../contexts/RatingItemContext';
/**
* Render the final JSX of Rating
*/ export const renderRating_unstable = (state, contextValues)=>{
assertSlots(state);
return /*#__PURE__*/ _jsx(RatingItemProvider, {
value: contextValues.ratingItem,
children: /*#__PURE__*/ _jsx(state.root, {})
});
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Rating/renderRating.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 { RatingBaseState, RatingSlots, RatingContextValues } from './Rating.types';\nimport { RatingItemProvider } from '../../contexts/RatingItemContext';\n\n/**\n * Render the final JSX of Rating\n */\nexport const renderRating_unstable = (state: RatingBaseState, contextValues: RatingContextValues): JSXElement => {\n assertSlots<RatingSlots>(state);\n\n return (\n <RatingItemProvider value={contextValues.ratingItem}>\n <state.root />\n </RatingItemProvider>\n );\n};\n"],"names":["assertSlots","RatingItemProvider","renderRating_unstable","state","contextValues","value","ratingItem","root"],"mappings":"AAAA,0BAA0B,GAC1B,iDAAiD;AAEjD,SAASA,WAAW,QAAQ,4BAA4B;AAGxD,SAASC,kBAAkB,QAAQ,mCAAmC;AAEtE;;CAEC,GACD,OAAO,MAAMC,wBAAwB,CAACC,OAAwBC;IAC5DJ,YAAyBG;IAEzB,qBACE,KAACF;QAAmBI,OAAOD,cAAcE,UAAU;kBACjD,cAAA,KAACH,MAAMI,IAAI;;AAGjB,EAAE"}

View File

@@ -0,0 +1,102 @@
'use client';
import * as React from 'react';
import { getIntrinsicElementProps, isHTMLElement, mergeCallbacks, slot, useControllableState, useId } from '@fluentui/react-utilities';
import { RatingItem } from '../../RatingItem';
import { StarFilled, StarRegular } from '@fluentui/react-icons';
/**
* Create the state required to render Rating.
*
* The returned state can be modified with hooks such as useRatingStyles_unstable,
* before being passed to renderRating_unstable.
*
* @param props - props from this instance of Rating
* @param ref - reference to root HTMLElement of Rating
*/ export const useRating_unstable = (props, ref)=>{
const { color = 'neutral', size = 'extra-large', iconFilled = StarFilled, iconOutline = StarRegular, ...baseProps } = props;
const state = useRatingBase_unstable({
iconFilled,
iconOutline,
...baseProps
}, ref);
return {
...state,
color,
size
};
};
/**
* Base hook for Rating component. Manages state related to controlled/uncontrolled
* rating value, hover state, radiogroup ARIA role, and keyboard/mouse interaction —
* without design props (color, size).
*
* @param props - props from this instance of Rating (without color, size)
* @param ref - reference to root HTMLElement of Rating
*/ export const useRatingBase_unstable = (props, ref)=>{
const generatedName = useId('rating-');
const { iconFilled = 'span', iconOutline = 'span', max = 5, name = generatedName, onChange, step = 1, itemLabel } = props;
const [value, setValue] = useControllableState({
state: props.value,
defaultState: props.defaultValue,
initialState: 0
});
const isRatingRadioItem = (target)=>isHTMLElement(target, {
constructorName: 'HTMLInputElement'
}) && target.type === 'radio' && target.name === name;
const [hoveredValue, setHoveredValue] = React.useState(undefined);
// Generate the child RatingItems and memoize them to prevent unnecessary re-rendering
const rootChildren = React.useMemo(()=>{
return Array.from(Array(max), (_, i)=>/*#__PURE__*/ React.createElement(RatingItem, {
value: i + 1,
key: i + 1
}));
}, [
max
]);
const state = {
iconFilled,
iconOutline,
name,
step,
itemLabel,
value,
hoveredValue,
components: {
root: 'div'
},
root: slot.always(getIntrinsicElementProps('div', {
ref,
children: rootChildren,
role: 'radiogroup',
...props
}, [
'onChange'
]), {
elementType: 'div'
})
};
state.root.onChange = (ev)=>{
if (isRatingRadioItem(ev.target)) {
const newValue = parseFloat(ev.target.value);
if (!isNaN(newValue)) {
setValue(newValue);
onChange === null || onChange === void 0 ? void 0 : onChange(ev, {
type: 'change',
event: ev,
value: newValue
});
}
}
};
state.root.onMouseOver = mergeCallbacks(props.onMouseOver, (ev)=>{
if (isRatingRadioItem(ev.target)) {
const newValue = parseFloat(ev.target.value);
if (!isNaN(newValue)) {
setHoveredValue(newValue);
}
}
});
state.root.onMouseLeave = mergeCallbacks(props.onMouseLeave, (ev)=>{
setHoveredValue(undefined);
});
return state;
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,30 @@
'use client';
import * as React from 'react';
export const useRatingContextValues = (ratingState)=>{
const { color, hoveredValue, iconFilled, iconOutline, itemLabel, name, step, size, value } = ratingState;
const ratingItem = React.useMemo(()=>({
color,
hoveredValue,
iconFilled,
iconOutline,
interactive: true,
itemLabel,
name,
step,
size,
value
}), [
color,
hoveredValue,
iconFilled,
iconOutline,
itemLabel,
name,
step,
size,
value
]);
return {
ratingItem
};
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Rating/useRatingContextValues.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { RatingContextValues, RatingState } from './Rating.types';\nimport { RatingItemContextValue } from '../RatingItem/RatingItem.types';\n\nexport const useRatingContextValues = (ratingState: RatingState): RatingContextValues => {\n const { color, hoveredValue, iconFilled, iconOutline, itemLabel, name, step, size, value } = ratingState;\n\n const ratingItem = React.useMemo<RatingItemContextValue>(\n () => ({\n color,\n hoveredValue,\n iconFilled,\n iconOutline,\n interactive: true,\n itemLabel,\n name,\n step,\n size,\n value,\n }),\n [color, hoveredValue, iconFilled, iconOutline, itemLabel, name, step, size, value],\n );\n\n return { ratingItem };\n};\n"],"names":["React","useRatingContextValues","ratingState","color","hoveredValue","iconFilled","iconOutline","itemLabel","name","step","size","value","ratingItem","useMemo","interactive"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAI/B,OAAO,MAAMC,yBAAyB,CAACC;IACrC,MAAM,EAAEC,KAAK,EAAEC,YAAY,EAAEC,UAAU,EAAEC,WAAW,EAAEC,SAAS,EAAEC,IAAI,EAAEC,IAAI,EAAEC,IAAI,EAAEC,KAAK,EAAE,GAAGT;IAE7F,MAAMU,aAAaZ,MAAMa,OAAO,CAC9B,IAAO,CAAA;YACLV;YACAC;YACAC;YACAC;YACAQ,aAAa;YACbP;YACAC;YACAC;YACAC;YACAC;QACF,CAAA,GACA;QAACR;QAAOC;QAAcC;QAAYC;QAAaC;QAAWC;QAAMC;QAAMC;QAAMC;KAAM;IAGpF,OAAO;QAAEC;IAAW;AACtB,EAAE"}

View File

@@ -0,0 +1,20 @@
'use client';
import { __resetStyles, mergeClasses } from '@griffel/react';
export const ratingClassNames = {
root: 'fui-Rating'
};
/**
* Styles for the root slot
*/
const useRootClassName = /*#__PURE__*/__resetStyles("r2imjyh", null, [".r2imjyh{display:flex;flex-wrap:wrap;}"]);
/**
* Apply styling to the Rating slots based on the state
*/
export const useRatingStyles_unstable = state => {
'use no memo';
const rootClassName = useRootClassName();
state.root.className = mergeClasses(ratingClassNames.root, rootClassName, state.root.className);
return state;
};

View File

@@ -0,0 +1 @@
{"version":3,"names":["__resetStyles","mergeClasses","ratingClassNames","root","useRootClassName","useRatingStyles_unstable","state","rootClassName","className"],"sources":["useRatingStyles.styles.js"],"sourcesContent":["'use client';\nimport { makeResetStyles, mergeClasses } from '@griffel/react';\nexport const ratingClassNames = {\n root: 'fui-Rating'\n};\n/**\n * Styles for the root slot\n */ const useRootClassName = makeResetStyles({\n display: 'flex',\n flexWrap: 'wrap'\n});\n/**\n * Apply styling to the Rating slots based on the state\n */ export const useRatingStyles_unstable = (state)=>{\n 'use no memo';\n const rootClassName = useRootClassName();\n state.root.className = mergeClasses(ratingClassNames.root, rootClassName, state.root.className);\n return state;\n};\n"],"mappings":"AAAA,YAAY;;AACZ,SAAAA,aAAA,EAA0BC,YAAY,QAAQ,gBAAgB;AAC9D,OAAO,MAAMC,gBAAgB,GAAG;EAC5BC,IAAI,EAAE;AACV,CAAC;AACD;AACA;AACA;AAAI,MAAMC,gBAAgB,gBAAGJ,aAAA,4DAG5B,CAAC;AACF;AACA;AACA;AAAI,OAAO,MAAMK,wBAAwB,GAAIC,KAAK,IAAG;EACjD,aAAa;;EACb,MAAMC,aAAa,GAAGH,gBAAgB,CAAC,CAAC;EACxCE,KAAK,CAACH,IAAI,CAACK,SAAS,GAAGP,YAAY,CAACC,gBAAgB,CAACC,IAAI,EAAEI,aAAa,EAAED,KAAK,CAACH,IAAI,CAACK,SAAS,CAAC;EAC/F,OAAOF,KAAK;AAChB,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,19 @@
'use client';
import { makeResetStyles, mergeClasses } from '@griffel/react';
export const ratingClassNames = {
root: 'fui-Rating'
};
/**
* Styles for the root slot
*/ const useRootClassName = makeResetStyles({
display: 'flex',
flexWrap: 'wrap'
});
/**
* Apply styling to the Rating slots based on the state
*/ export const useRatingStyles_unstable = (state)=>{
'use no memo';
const rootClassName = useRootClassName();
state.root.className = mergeClasses(ratingClassNames.root, rootClassName, state.root.className);
return state;
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Rating/useRatingStyles.styles.ts"],"sourcesContent":["'use client';\n\nimport { makeResetStyles, mergeClasses } from '@griffel/react';\nimport type { SlotClassNames } from '@fluentui/react-utilities';\nimport type { RatingSlots, RatingState } from './Rating.types';\n\nexport const ratingClassNames: SlotClassNames<RatingSlots> = {\n root: 'fui-Rating',\n};\n\n/**\n * Styles for the root slot\n */\n\nconst useRootClassName = makeResetStyles({\n display: 'flex',\n flexWrap: 'wrap',\n});\n\n/**\n * Apply styling to the Rating slots based on the state\n */\nexport const useRatingStyles_unstable = (state: RatingState): RatingState => {\n 'use no memo';\n\n const rootClassName = useRootClassName();\n state.root.className = mergeClasses(ratingClassNames.root, rootClassName, state.root.className);\n return state;\n};\n"],"names":["makeResetStyles","mergeClasses","ratingClassNames","root","useRootClassName","display","flexWrap","useRatingStyles_unstable","state","rootClassName","className"],"mappings":"AAAA;AAEA,SAASA,eAAe,EAAEC,YAAY,QAAQ,iBAAiB;AAI/D,OAAO,MAAMC,mBAAgD;IAC3DC,MAAM;AACR,EAAE;AAEF;;CAEC,GAED,MAAMC,mBAAmBJ,gBAAgB;IACvCK,SAAS;IACTC,UAAU;AACZ;AAEA;;CAEC,GACD,OAAO,MAAMC,2BAA2B,CAACC;IACvC;IAEA,MAAMC,gBAAgBL;IACtBI,MAAML,IAAI,CAACO,SAAS,GAAGT,aAAaC,iBAAiBC,IAAI,EAAEM,eAAeD,MAAML,IAAI,CAACO,SAAS;IAC9F,OAAOF;AACT,EAAE"}