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
+120
View File
@@ -0,0 +1,120 @@
import * as React from 'react';
import { IStyle, IStyleSetBase, ITheme } from '@fluentui/style-utilities';
/**
* Helper interface for accessing user props children.
* @deprecated Use React.PropsWithChildren.
*/
export type IPropsWithChildren<TProps> = React.PropsWithChildren<TProps>;
/**
* Helper type defining style sections, one for each component slot.
*/
export type IComponentStyles<TSlots> = {
[key in keyof TSlots]?: IStyle;
};
/**
* Function declaration for component styles functions.
*/
export type IStylesFunction<TViewProps, TTokens, TStyleSet extends IStyleSetBase> = (props: TViewProps, theme: ITheme, tokens: TTokens) => TStyleSet;
/**
* Composite type for component styles functions and objects.
*/
export type IStylesFunctionOrObject<TViewProps, TTokens, TStyleSet extends IStyleSetBase> = IStylesFunction<TViewProps, TTokens, TStyleSet> | TStyleSet;
/**
* Tokens can be defined as an object, function, or an array of objects and functions.
*/
export type IToken<TViewProps, TTokens> = ITokenBase<TViewProps, TTokens> | ITokenBaseArray<TViewProps, TTokens>;
/**
* Function declaration for component token functions.
*/
export type ITokenFunction<TViewProps, TTokens> = (props: TViewProps, theme: ITheme) => IToken<TViewProps, TTokens>;
/**
* Composite type for component token functions and objects.
*/
export type ITokenFunctionOrObject<TViewProps, TTokens> = ITokenFunction<TViewProps, TTokens> | TTokens;
/**
* Composite base type that includes all possible resolutions of token functions in an array.
*/
export type ITokenBase<TViewProps, TTokens> = ITokenFunctionOrObject<TViewProps, TTokens> | false | null | undefined;
/**
* Composite token base array type allowing for token objects, functions, and function resolutions.
*/
export interface ITokenBaseArray<TViewProps, TTokens> extends Array<IToken<TViewProps, TTokens>> {
}
/**
* Optional props for styleable components. If these props are present, they will automatically be
* used by Foundation when applying theming and styling.
*/
export interface IStyleableComponentProps<TViewProps, TTokens, TStyleSet extends IStyleSetBase> {
className?: string;
styles?: IStylesFunctionOrObject<TViewProps, TTokens, TStyleSet>;
theme?: ITheme;
tokens?: ITokenFunctionOrObject<TViewProps, TTokens>;
}
export type ICustomizationProps<TViewProps, TTokens, TStyleSet extends IStyleSetBase> = IStyleableComponentProps<TViewProps, TTokens, TStyleSet> & Required<Pick<IStyleableComponentProps<TViewProps, TTokens, TStyleSet>, 'theme'>>;
/**
* Defines the contract for state components.
*/
export type IStateComponentType<TComponentProps, TViewProps> = (props: Readonly<TComponentProps>) => TViewProps;
/**
* Defines the contract for view components.
*/
export type IViewComponent<TViewProps> = (props: React.PropsWithChildren<TViewProps>) => ReturnType<React.FunctionComponent>;
/**
* Component options used by foundation to tie elements together.
*
* * TComponentProps: A styleable props interface for the created component.
* * TTokens: The type for tokens props.
* * TStyleSet: The type for styles properties.
* * TViewProps: The props specific to the view, including processed properties outputted by optional state component.
* If state component is not provided, TComponentProps is the same as TViewProps.
* * TStatics: Static type for statics applied to created component object.
*/
export interface IComponentOptions<TComponentProps, TTokens, TStyleSet extends IStyleSetBase, TViewProps = TComponentProps, TStatics = {}> {
/**
* Display name to identify component in React hierarchy. This parameter is required for targeted component styling
* via theming.
*/
displayName?: string;
/**
* List of fields which can be customized.
*/
fields?: string[];
/**
* Styles prop to pass into component.
*/
styles?: IStylesFunctionOrObject<TViewProps, TTokens, TStyleSet>;
/**
* Optional state component that processes TComponentProps into TViewProps.
*/
state?: IStateComponentType<TComponentProps, TViewProps>;
/**
* Optional static object to assign to constructed component.
*/
statics?: TStatics;
/**
* Tokens prop to pass into component.
*/
tokens?: ITokenFunctionOrObject<TViewProps, TTokens>;
/**
* Default prop for which to map primitive values.
*/
factoryOptions?: IFactoryOptions<TComponentProps>;
}
/**
* Component helper that defines options as required for ease of use by component consumers.
*/
export type IComponent<TComponentProps, TTokens, TStyleSet extends IStyleSetBase, TViewProps = TComponentProps, TStatics = {}> = Required<IComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TStatics>> & {
/**
* Component that generates view output.
*/
view: IViewComponent<TViewProps>;
};
/**
* Factory options for creating component.
*/
export interface IFactoryOptions<TProps> {
/**
* Default prop for which to map primitive values.
*/
defaultProp?: keyof TProps | 'children';
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=IComponent.js.map
File diff suppressed because one or more lines are too long
+15
View File
@@ -0,0 +1,15 @@
import * as React from 'react';
import type { JSXIntrinsicElement, JSXIntrinsicElementKeys } from '@fluentui/utilities';
import { ISlotProp } from './ISlots';
/**
* Generic slot definition allowing common HTML attributes. Applicable for most intrinsic slots. Please note certain
* elements such as buttons and inputs should make use of IHTMLElementSlot to provide access to specialized attributes
* of those elements.
*/
export type IHTMLSlot = ISlotProp<React.DetailedHTMLProps<React.HTMLAttributes<any>, any>>;
/**
* Optional HTML element typing to confine or expand HTML attribute usage for an intrinsic slot.
* Useful for slots that need to allow access to specialized HTML attributes, such as for buttons and inputs.
* Example usage: root?: IHTMLElementSlot\<'button'\>;
*/
export type IHTMLElementSlot<TElement extends JSXIntrinsicElementKeys> = ISlotProp<JSXIntrinsicElement<TElement>>;
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=IHTMLSlots.js.map
@@ -0,0 +1 @@
{"version":3,"file":"IHTMLSlots.js","sourceRoot":"../src/","sources":["IHTMLSlots.ts"],"names":[],"mappings":"","sourcesContent":["import * as React from 'react';\nimport type { JSXIntrinsicElement, JSXIntrinsicElementKeys } from '@fluentui/utilities';\nimport { ISlotProp } from './ISlots';\n\n/**\n * Generic slot definition allowing common HTML attributes. Applicable for most intrinsic slots. Please note certain\n * elements such as buttons and inputs should make use of IHTMLElementSlot to provide access to specialized attributes\n * of those elements.\n */\nexport type IHTMLSlot = ISlotProp<React.DetailedHTMLProps<React.HTMLAttributes<any>, any>>;\n\n/**\n * Optional HTML element typing to confine or expand HTML attribute usage for an intrinsic slot.\n * Useful for slots that need to allow access to specialized HTML attributes, such as for buttons and inputs.\n * Example usage: root?: IHTMLElementSlot\\<'button'\\>;\n */\nexport type IHTMLElementSlot<TElement extends JSXIntrinsicElementKeys> = ISlotProp<JSXIntrinsicElement<TElement>>;\n"]}
+94
View File
@@ -0,0 +1,94 @@
import * as React from 'react';
import { IStyle, ITheme } from '@fluentui/style-utilities';
import { IComponentStyles } from './IComponent';
/**
* Signature of components that have component factories.
*/
export interface ISlotCreator<TProps extends ValidProps, TShorthandProp extends ValidShorthand> {
create?: ISlotFactory<TProps, TShorthandProp>;
}
/**
* Slottable version of React.ComponentType.
*/
export type ISlottableComponentType<TProps extends ValidProps, TShorthandProp extends ValidShorthand> = React.ComponentType<TProps> & ISlotCreator<TProps, TShorthandProp>;
/**
* Slottable version of React.ReactType.
*/
export type ISlottableReactType<TProps extends ValidProps, TShorthandProp extends ValidShorthand> = React.ElementType<TProps> & ISlotCreator<TProps, TShorthandProp>;
/**
* Props generated by Foundation.
*/
export interface IProcessedSlotProps {
className?: string;
}
/**
* An interface for defining slots. Each key in TSlot must point to an ISlottableType.
*/
export type ISlotDefinition<TSlots> = {
[slot in keyof TSlots]: React.ElementType<ExtractProps<TSlots[slot]>>;
};
/**
* Created Slot structure used for rendering by components.
*/
export interface ISlot<TProps> {
(componentProps: React.PropsWithChildren<TProps> | undefined | null): ReturnType<React.FunctionComponent>;
isSlot?: boolean;
}
/**
* Interface for a slot factory that consumes both component and user slot prop and generates rendered output.
*/
export type ISlotFactory<TProps extends ValidProps, TShorthandProp extends ValidShorthand> = (componentProps: TProps & IProcessedSlotProps, userProps: ISlotProp<TProps, TShorthandProp>, slotOptions: ISlotOptions<TProps> | undefined, defaultStyles: IStyle, theme?: ITheme) => ReturnType<React.FunctionComponent<TProps>>;
/**
* Defines valid shorthand prop types. These should match the defaultProp type provided to createComponent.
*/
export type ValidShorthand = string | number | boolean;
/**
* Defines valid prop types.
*/
export type ValidProps = object;
/**
* Extracts props type from ISlotProp definition.
*/
export type ExtractProps<TUnion> = TUnion extends ISlotProp<infer TProps> ? TProps : never;
/**
* Extracts shorthand type from union of ValidShorthand types.
*/
export type ExtractShorthand<TUnion> = TUnion extends boolean ? boolean : TUnion extends number ? number : TUnion extends string ? string : never;
/**
* Interface for aggregated slots objects used internally by components. Extract the TProps type passed
* into ISlotProp<TProps> to define the ISlot using TProps.
*/
export type ISlots<TSlots> = {
[slot in keyof TSlots]: ISlot<ExtractProps<TSlots[slot]>>;
};
/**
* Automatically defines 'slots' prop based on TSlots props.
*/
export type ISlottableProps<TSlots> = TSlots & {
slots?: {
[key in keyof TSlots]+?: ISlotOptions<ExtractProps<TSlots[key]>>;
};
};
/**
* Defines user properties that are automatically applied by Slot utilities using slot name.
*/
export interface IDefaultSlotProps<TSlots> {
_defaultStyles: IComponentStyles<TSlots>;
}
/**
* Defines the primary slot prop interface components should use to define their slot props.
*/
export type ISlotProp<TProps extends ValidProps, TShorthandProp extends ValidShorthand = never> = TShorthandProp | TProps;
/**
* Defines the slot options object for all slot props:
* 1. ISlotRender function.
* 2. React component with TProps interface.
*/
export interface ISlotOptions<TProps> {
component?: React.ElementType<TProps>;
render?: ISlotRender<TProps>;
}
/**
* Content rendering provided by component.
*/
export type ISlotRender<TProps> = (props: React.PropsWithChildren<TProps>, defaultComponent: React.ComponentType<React.PropsWithChildren<TProps>>) => ReturnType<React.FunctionComponent<React.PropsWithChildren<TProps>>>;
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=ISlots.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"ISlots.js","sourceRoot":"../src/","sources":["ISlots.ts"],"names":[],"mappings":"","sourcesContent":["import * as React from 'react';\nimport { IStyle, ITheme } from '@fluentui/style-utilities';\nimport { IComponentStyles } from './IComponent';\n\n/**\n * Signature of components that have component factories.\n */\nexport interface ISlotCreator<TProps extends ValidProps, TShorthandProp extends ValidShorthand> {\n create?: ISlotFactory<TProps, TShorthandProp>;\n}\n\n/**\n * Slottable version of React.ComponentType.\n */\nexport type ISlottableComponentType<\n TProps extends ValidProps,\n TShorthandProp extends ValidShorthand,\n> = React.ComponentType<TProps> & ISlotCreator<TProps, TShorthandProp>;\n\n/**\n * Slottable version of React.ReactType.\n */\nexport type ISlottableReactType<\n TProps extends ValidProps,\n TShorthandProp extends ValidShorthand,\n> = React.ElementType<TProps> & ISlotCreator<TProps, TShorthandProp>;\n\n/**\n * Props generated by Foundation.\n */\nexport interface IProcessedSlotProps {\n className?: string;\n}\n\n/**\n * An interface for defining slots. Each key in TSlot must point to an ISlottableType.\n */\nexport type ISlotDefinition<TSlots> = { [slot in keyof TSlots]: React.ElementType<ExtractProps<TSlots[slot]>> };\n\n/**\n * Created Slot structure used for rendering by components.\n */\nexport interface ISlot<TProps> {\n (componentProps: React.PropsWithChildren<TProps> | undefined | null): ReturnType<React.FunctionComponent>;\n isSlot?: boolean;\n}\n\n/**\n * Interface for a slot factory that consumes both component and user slot prop and generates rendered output.\n */\nexport type ISlotFactory<TProps extends ValidProps, TShorthandProp extends ValidShorthand> = (\n componentProps: TProps & IProcessedSlotProps,\n userProps: ISlotProp<TProps, TShorthandProp>,\n slotOptions: ISlotOptions<TProps> | undefined,\n defaultStyles: IStyle,\n theme?: ITheme,\n) => ReturnType<React.FunctionComponent<TProps>>;\n\n/**\n * Defines valid shorthand prop types. These should match the defaultProp type provided to createComponent.\n */\nexport type ValidShorthand = string | number | boolean;\n\n/**\n * Defines valid prop types.\n */\n// We can constrain TProps more clearly (notably also exclude Functions) once this TS PR is merged:\n// https://github.com/Microsoft/TypeScript/pull/29317\nexport type ValidProps = object;\n\n/**\n * Extracts props type from ISlotProp definition.\n */\nexport type ExtractProps<TUnion> = TUnion extends ISlotProp<infer TProps> ? TProps : never;\n\n/**\n * Extracts shorthand type from union of ValidShorthand types.\n */\nexport type ExtractShorthand<TUnion> = TUnion extends boolean\n ? boolean\n : TUnion extends number\n ? number\n : TUnion extends string\n ? string\n : never;\n\n/**\n * Interface for aggregated slots objects used internally by components. Extract the TProps type passed\n * into ISlotProp<TProps> to define the ISlot using TProps.\n */\nexport type ISlots<TSlots> = { [slot in keyof TSlots]: ISlot<ExtractProps<TSlots[slot]>> };\n\n/**\n * Automatically defines 'slots' prop based on TSlots props.\n */\nexport type ISlottableProps<TSlots> = TSlots & {\n slots?: { [key in keyof TSlots]+?: ISlotOptions<ExtractProps<TSlots[key]>> };\n};\n\n/**\n * Defines user properties that are automatically applied by Slot utilities using slot name.\n */\nexport interface IDefaultSlotProps<TSlots> {\n _defaultStyles: IComponentStyles<TSlots>;\n}\n\n/**\n * Defines the primary slot prop interface components should use to define their slot props.\n */\n// TODO: Constrain TProps more clearly (notably also exclude Functions) once this TS PR is merged:\n// https://github.com/Microsoft/TypeScript/pull/29317\nexport type ISlotProp<TProps extends ValidProps, TShorthandProp extends ValidShorthand = never> =\n | TShorthandProp\n | TProps;\n\n/**\n * Defines the slot options object for all slot props:\n * 1. ISlotRender function.\n * 2. React component with TProps interface.\n */\n\n// TODO: create mutually exclusive type for component & render, but only if it's a readable error for users.\nexport interface ISlotOptions<TProps> {\n component?: React.ElementType<TProps>;\n render?: ISlotRender<TProps>;\n}\n\n/**\n * Content rendering provided by component.\n */\nexport type ISlotRender<TProps> = (\n props: React.PropsWithChildren<TProps>,\n defaultComponent: React.ComponentType<React.PropsWithChildren<TProps>>,\n) => ReturnType<React.FunctionComponent<React.PropsWithChildren<TProps>>>;\n"]}
@@ -0,0 +1,15 @@
import * as React from 'react';
import { ISchemeNames, ITheme } from '@fluentui/style-utilities';
export interface IThemeProviderProps {
scheme?: ISchemeNames;
theme?: ITheme;
}
/**
* Theme provider is a simplified version of Customizer that activates the appropriate theme data
* for a given scheme name.
*
* @param providers - Injected providers for accessing theme data and providing it via a Customizer component.
* @deprecated This is an old ThemeProvider implementation. New code should use the ThemeProvider exported from
* `@fluentui/react` (or `@fluentui/react/lib/Theme`) instead.
*/
export declare const ThemeProvider: React.FunctionComponent<React.PropsWithChildren<IThemeProviderProps>>;
+28
View File
@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ThemeProvider = void 0;
var tslib_1 = require("tslib");
var React = require("react");
var style_utilities_1 = require("@fluentui/style-utilities");
var utilities_1 = require("@fluentui/utilities");
/**
* Theme provider is a simplified version of Customizer that activates the appropriate theme data
* for a given scheme name.
*
* @param providers - Injected providers for accessing theme data and providing it via a Customizer component.
* @deprecated This is an old ThemeProvider implementation. New code should use the ThemeProvider exported from
* `@fluentui/react` (or `@fluentui/react/lib/Theme`) instead.
*/
var ThemeProvider = function (props) {
var scheme = props.scheme, theme = props.theme, rest = tslib_1.__rest(props, ["scheme", "theme"]);
// TODO: consider merging implementation with theme-proto, which only stores a reference / scheme name to theme
// in context and uses quick global store accessor to trigger change by passing in theme object as child and
// triggering re-render. (perf benefits need verification)
var contextTransform = function (context) {
return (0, style_utilities_1.getThemedContext)(context, scheme, theme);
};
// eslint-disable-next-line react/jsx-no-bind, @typescript-eslint/no-deprecated
return React.createElement(utilities_1.Customizer, tslib_1.__assign({}, rest, { contextTransform: contextTransform }));
};
exports.ThemeProvider = ThemeProvider;
//# sourceMappingURL=ThemeProvider.js.map
@@ -0,0 +1 @@
{"version":3,"file":"ThemeProvider.js","sourceRoot":"../src/","sources":["ThemeProvider.tsx"],"names":[],"mappings":";;;;AAAA,6BAA+B;AAC/B,6DAAmF;AACnF,iDAAmE;AAOnE;;;;;;;GAOG;AACI,IAAM,aAAa,GAA0E,UAClG,KAA0B;IAElB,IAAA,MAAM,GAAqB,KAAK,OAA1B,EAAE,KAAK,GAAc,KAAK,MAAnB,EAAK,IAAI,kBAAK,KAAK,EAAlC,mBAA0B,CAAF,CAAW;IAEzC,+GAA+G;IAC/G,8GAA8G;IAC9G,4DAA4D;IAC5D,IAAM,gBAAgB,GAAyC,UAAA,OAAO;QACpE,OAAO,IAAA,kCAAgB,EAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC;IAEF,+EAA+E;IAC/E,OAAO,oBAAC,sBAAU,uBAAK,IAAI,IAAE,gBAAgB,EAAE,gBAAgB,IAAI,CAAC;AACtE,CAAC,CAAC;AAdW,QAAA,aAAa,iBAcxB","sourcesContent":["import * as React from 'react';\nimport { getThemedContext, ISchemeNames, ITheme } from '@fluentui/style-utilities';\nimport { Customizer, ICustomizerProps } from '@fluentui/utilities';\n\nexport interface IThemeProviderProps {\n scheme?: ISchemeNames;\n theme?: ITheme;\n}\n\n/**\n * Theme provider is a simplified version of Customizer that activates the appropriate theme data\n * for a given scheme name.\n *\n * @param providers - Injected providers for accessing theme data and providing it via a Customizer component.\n * @deprecated This is an old ThemeProvider implementation. New code should use the ThemeProvider exported from\n * `@fluentui/react` (or `@fluentui/react/lib/Theme`) instead.\n */\nexport const ThemeProvider: React.FunctionComponent<React.PropsWithChildren<IThemeProviderProps>> = (\n props: IThemeProviderProps,\n) => {\n const { scheme, theme, ...rest } = props;\n\n // TODO: consider merging implementation with theme-proto, which only stores a reference / scheme name to theme\n // in context and uses quick global store accessor to trigger change by passing in theme object as child and\n // triggering re-render. (perf benefits need verification)\n const contextTransform: ICustomizerProps['contextTransform'] = context => {\n return getThemedContext(context, scheme, theme);\n };\n\n // eslint-disable-next-line react/jsx-no-bind, @typescript-eslint/no-deprecated\n return <Customizer {...rest} contextTransform={contextTransform} />;\n};\n"]}
@@ -0,0 +1,24 @@
import * as React from 'react';
import { IStyleSetBase } from '@fluentui/style-utilities';
import { IComponentOptions, IViewComponent } from './IComponent';
import { ValidProps } from './ISlots';
/**
* Assembles a higher order component based on the following: styles, theme, view, and state.
* Imposes a separation of concern and centralizes styling processing to increase ease of use and robustness
* in how components use and apply styling and theming.
*
* Automatically merges and applies themes and styles with theme / styleprops having the highest priority.
* State component, if provided, is passed in props for processing. Props from state / user are automatically processed
* and styled before finally being passed to view.
*
* State components should contain all stateful behavior and should not generate any JSX, but rather simply call
* the view prop.
*
* Views should simply be stateless pure functions that receive all props needed for rendering their output.
*
* State component is optional. If state is not provided, created component is essentially a functional
* stateless component.
*
* @param options - component Component options. See IComponentOptions for more detail.
*/
export declare function createComponent<TComponentProps extends ValidProps, TTokens, TStyleSet extends IStyleSetBase, TViewProps extends TComponentProps = TComponentProps, TStatics = {}>(view: IViewComponent<TViewProps>, options?: IComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TStatics>): React.FunctionComponent<TComponentProps> & TStatics;
@@ -0,0 +1,108 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createComponent = createComponent;
var tslib_1 = require("tslib");
var React = require("react");
var style_utilities_1 = require("@fluentui/style-utilities");
var utilities_1 = require("@fluentui/utilities");
var slots_1 = require("./slots");
var utilities_2 = require("./utilities");
/**
* Assembles a higher order component based on the following: styles, theme, view, and state.
* Imposes a separation of concern and centralizes styling processing to increase ease of use and robustness
* in how components use and apply styling and theming.
*
* Automatically merges and applies themes and styles with theme / styleprops having the highest priority.
* State component, if provided, is passed in props for processing. Props from state / user are automatically processed
* and styled before finally being passed to view.
*
* State components should contain all stateful behavior and should not generate any JSX, but rather simply call
* the view prop.
*
* Views should simply be stateless pure functions that receive all props needed for rendering their output.
*
* State component is optional. If state is not provided, created component is essentially a functional
* stateless component.
*
* @param options - component Component options. See IComponentOptions for more detail.
*/
function createComponent(view, options) {
if (options === void 0) { options = {}; }
var _a = options.factoryOptions, factoryOptions = _a === void 0 ? {} : _a;
var defaultProp = factoryOptions.defaultProp;
var ResultComponent = function (componentProps) {
var settings = _getCustomizations(options.displayName, React.useContext(utilities_1.CustomizerContext), options.fields);
var stateReducer = options.state;
if (stateReducer) {
// Don't assume state will return all props, so spread useState result over component props.
componentProps = tslib_1.__assign(tslib_1.__assign({}, componentProps), stateReducer(componentProps));
}
var theme = componentProps.theme || settings.theme;
var tokens = _resolveTokens(componentProps, theme, options.tokens, settings.tokens, componentProps.tokens);
var styles = _resolveStyles(componentProps, theme, tokens, options.styles, settings.styles, componentProps.styles);
var viewProps = tslib_1.__assign(tslib_1.__assign({}, componentProps), { styles: styles, tokens: tokens, _defaultStyles: styles, theme: theme });
return view(viewProps);
};
ResultComponent.displayName = options.displayName || view.name;
// If a shorthand prop is defined, create a factory for the component.
// TODO: This shouldn't be a concern of createComponent.. factoryOptions should just be forwarded.
// Need to weigh creating default factories on component creation vs. memoizing them on use in slots.tsx.
if (defaultProp) {
ResultComponent.create = (0, slots_1.createFactory)(ResultComponent, { defaultProp: defaultProp });
}
(0, utilities_2.assign)(ResultComponent, options.statics);
// Later versions of TypeSript should allow us to merge objects in a type safe way and avoid this cast.
return ResultComponent;
}
/**
* Resolve all styles functions with both props and tokens and flatten results along with all styles objects.
*/
function _resolveStyles(props, theme, tokens) {
var allStyles = [];
for (var _i = 3; _i < arguments.length; _i++) {
allStyles[_i - 3] = arguments[_i];
}
return style_utilities_1.concatStyleSets.apply(void 0, allStyles.map(function (styles) {
return typeof styles === 'function' ? styles(props, theme, tokens) : styles;
}));
}
/**
* Resolve all tokens functions with props flatten results along with all tokens objects.
*/
function _resolveTokens(props, theme) {
var allTokens = [];
for (var _i = 2; _i < arguments.length; _i++) {
allTokens[_i - 2] = arguments[_i];
}
var tokens = {};
for (var _a = 0, allTokens_1 = allTokens; _a < allTokens_1.length; _a++) {
var currentTokens = allTokens_1[_a];
if (currentTokens) {
// TODO: why is this cast needed? TS seems to think there is a (TToken | Function) union from somewhere.
currentTokens =
typeof currentTokens === 'function'
? currentTokens(props, theme)
: currentTokens;
if (Array.isArray(currentTokens)) {
currentTokens = _resolveTokens.apply(void 0, tslib_1.__spreadArray([props, theme], currentTokens, false));
}
(0, utilities_2.assign)(tokens, currentTokens);
}
}
return tokens;
}
/**
* Helper function for calling Customizations.getSettings falling back to default fields.
*
* @param displayName Displayable name for component.
* @param context React context passed to component containing contextual settings.
* @param fields Optional list of properties to grab from global store and context.
*/
function _getCustomizations(displayName, context, fields) {
// TODO: do we want field props? should fields be part of IComponent and used here?
// TODO: should we centrally define DefaultFields? (not exported from styling)
// TODO: tie this array to ICustomizationProps, such that each array element is keyof ICustomizationProps
var DefaultFields = ['theme', 'styles', 'tokens'];
return utilities_1.Customizations.getSettings(fields || DefaultFields, displayName, context.customizations);
}
//# sourceMappingURL=createComponent.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,23 @@
import * as React from 'react';
export interface IControlledStateOptions<TProps, TProp extends keyof TProps, TDefaultProp extends keyof TProps> {
defaultPropValue?: TProps[TProp];
defaultPropName?: TDefaultProp;
}
/**
* Controlled state helper that gives priority to props value. Useful for components that have props with both
* controlled and uncontrolled modes. Any props values will override state, but will not update internal state.
* If prop is defined and then later undefined, state will revert to its previous value.
*
* @param props - The props object containing controlled prop values.
* @param propName - The controlled prop name.
* @param options - Options. defaultPropValue is only used if defaultPropName (or its value) is undefined.
*/
export declare function useControlledState<TProps, TProp extends keyof TProps, TDefaultProp extends keyof TProps>(props: Readonly<TProps>, propName: TProp, options?: IControlledStateOptions<TProps, TProp, TDefaultProp>): [TProps[TProp] | undefined, React.Dispatch<React.SetStateAction<TProps[TProp]>>];
/**
* Simple controlled helper that gives priority to props value and falls back to derived value.
*
* @param props - The props object containing controlled prop values.
* @param propName - The controlled prop name.
* @param derivedValue - Derived value. Returned when controlled value is not present.
*/
export declare function getControlledDerivedProps<TProps, TProp extends keyof TProps>(props: Readonly<TProps>, propName: TProp, derivedValue: TProps[TProp]): TProps[TProp];
@@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useControlledState = useControlledState;
exports.getControlledDerivedProps = getControlledDerivedProps;
var React = require("react");
/**
* Controlled state helper that gives priority to props value. Useful for components that have props with both
* controlled and uncontrolled modes. Any props values will override state, but will not update internal state.
* If prop is defined and then later undefined, state will revert to its previous value.
*
* @param props - The props object containing controlled prop values.
* @param propName - The controlled prop name.
* @param options - Options. defaultPropValue is only used if defaultPropName (or its value) is undefined.
*/
function useControlledState(props, propName, options) {
var defaultValue;
if (options) {
if (options.defaultPropName && props[options.defaultPropName] !== undefined) {
// No easy way to coerce TProps[TDefaultProp] to match TProps[TProp] in generic typings, so cast it here.
defaultValue = props[options.defaultPropName];
}
else {
defaultValue = options && options.defaultPropValue;
}
}
var _a = React.useState(defaultValue), state = _a[0], setState = _a[1];
if (props[propName] !== undefined) {
return [props[propName], setState];
}
else {
return [state, setState];
}
}
/**
* Simple controlled helper that gives priority to props value and falls back to derived value.
*
* @param props - The props object containing controlled prop values.
* @param propName - The controlled prop name.
* @param derivedValue - Derived value. Returned when controlled value is not present.
*/
function getControlledDerivedProps(props, propName, derivedValue) {
if (props[propName] !== undefined) {
return props[propName];
}
else {
return derivedValue;
}
}
//# sourceMappingURL=controlled.js.map
@@ -0,0 +1 @@
{"version":3,"file":"controlled.js","sourceRoot":"../src/","sources":["hooks/controlled.ts"],"names":[],"mappings":";;AAgBA,gDAsBC;AASD,8DAUC;AAzDD,6BAA+B;AAO/B;;;;;;;;GAQG;AACH,SAAgB,kBAAkB,CAChC,KAAuB,EACvB,QAAe,EACf,OAA8D;IAE9D,IAAI,YAAuC,CAAC;IAC5C,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,OAAO,CAAC,eAAe,IAAI,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,SAAS,EAAE,CAAC;YAC5E,yGAAyG;YACzG,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,eAAe,CAA6B,CAAC;QAC5E,CAAC;aAAM,CAAC;YACN,YAAY,GAAG,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC;QACrD,CAAC;IACH,CAAC;IAEK,IAAA,KAAoB,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,EAA/C,KAAK,QAAA,EAAE,QAAQ,QAAgC,CAAC;IAEvD,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,yBAAyB,CACvC,KAAuB,EACvB,QAAe,EACf,YAA2B;IAE3B,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;SAAM,CAAC;QACN,OAAO,YAAY,CAAC;IACtB,CAAC;AACH,CAAC","sourcesContent":["import * as React from 'react';\n\nexport interface IControlledStateOptions<TProps, TProp extends keyof TProps, TDefaultProp extends keyof TProps> {\n defaultPropValue?: TProps[TProp];\n defaultPropName?: TDefaultProp;\n}\n\n/**\n * Controlled state helper that gives priority to props value. Useful for components that have props with both\n * controlled and uncontrolled modes. Any props values will override state, but will not update internal state.\n * If prop is defined and then later undefined, state will revert to its previous value.\n *\n * @param props - The props object containing controlled prop values.\n * @param propName - The controlled prop name.\n * @param options - Options. defaultPropValue is only used if defaultPropName (or its value) is undefined.\n */\nexport function useControlledState<TProps, TProp extends keyof TProps, TDefaultProp extends keyof TProps>(\n props: Readonly<TProps>,\n propName: TProp,\n options?: IControlledStateOptions<TProps, TProp, TDefaultProp>,\n): [TProps[TProp] | undefined, React.Dispatch<React.SetStateAction<TProps[TProp]>>] {\n let defaultValue: TProps[TProp] | undefined;\n if (options) {\n if (options.defaultPropName && props[options.defaultPropName] !== undefined) {\n // No easy way to coerce TProps[TDefaultProp] to match TProps[TProp] in generic typings, so cast it here.\n defaultValue = props[options.defaultPropName] as unknown as TProps[TProp];\n } else {\n defaultValue = options && options.defaultPropValue;\n }\n }\n\n const [state, setState] = React.useState(defaultValue);\n\n if (props[propName] !== undefined) {\n return [props[propName], setState];\n } else {\n return [state, setState];\n }\n}\n\n/**\n * Simple controlled helper that gives priority to props value and falls back to derived value.\n *\n * @param props - The props object containing controlled prop values.\n * @param propName - The controlled prop name.\n * @param derivedValue - Derived value. Returned when controlled value is not present.\n */\nexport function getControlledDerivedProps<TProps, TProp extends keyof TProps>(\n props: Readonly<TProps>,\n propName: TProp,\n derivedValue: TProps[TProp],\n): TProps[TProp] {\n if (props[propName] !== undefined) {\n return props[propName];\n } else {\n return derivedValue;\n }\n}\n"]}
@@ -0,0 +1 @@
export * from './controlled';
+5
View File
@@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
tslib_1.__exportStar(require("./controlled"), exports);
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"../src/","sources":["hooks/index.ts"],"names":[],"mappings":";;;AAAA,uDAA6B","sourcesContent":["export * from './controlled';\n"]}
+9
View File
@@ -0,0 +1,9 @@
export * from './createComponent';
export * from './IComponent';
export * from './IHTMLSlots';
export * from './ISlots';
export * from './slots';
export * from './ThemeProvider';
export * from './hooks/index';
export { styled as legacyStyled } from '@fluentui/utilities';
import './version';
+15
View File
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.legacyStyled = void 0;
var tslib_1 = require("tslib");
tslib_1.__exportStar(require("./createComponent"), exports);
tslib_1.__exportStar(require("./IComponent"), exports);
tslib_1.__exportStar(require("./IHTMLSlots"), exports);
tslib_1.__exportStar(require("./ISlots"), exports);
tslib_1.__exportStar(require("./slots"), exports);
tslib_1.__exportStar(require("./ThemeProvider"), exports);
tslib_1.__exportStar(require("./hooks/index"), exports);
var utilities_1 = require("@fluentui/utilities");
Object.defineProperty(exports, "legacyStyled", { enumerable: true, get: function () { return utilities_1.styled; } });
require("./version");
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"../src/","sources":["index.ts"],"names":[],"mappings":";;;;AAAA,4DAAkC;AAClC,uDAA6B;AAC7B,uDAA6B;AAC7B,mDAAyB;AACzB,kDAAwB;AACxB,0DAAgC;AAChC,wDAA8B;AAE9B,iDAA6D;AAApD,yGAAA,MAAM,OAAgB;AAE/B,qBAAmB","sourcesContent":["export * from './createComponent';\nexport * from './IComponent';\nexport * from './IHTMLSlots';\nexport * from './ISlots';\nexport * from './slots';\nexport * from './ThemeProvider';\nexport * from './hooks/index';\n\nexport { styled as legacyStyled } from '@fluentui/utilities';\n\nimport './version';\n"]}
@@ -0,0 +1,51 @@
import * as React from 'react';
import { IStyleSetBase } from '@fluentui/style-utilities';
import { IComponentOptions as IOldComponentOptions } from '../IComponent';
import { ISlots, ISlotDefinition, ISlottableProps } from '../ISlots';
/**
* Defines the contract for view components.
*/
export type IViewComponent<TViewProps, TComponentSlots = {}> = (props: React.PropsWithChildren<TViewProps>, slots: ISlots<Required<TComponentSlots>>) => ReturnType<React.FunctionComponent>;
/**
* Defines the contract for slot components.
*/
export type ISlotComponent<TComponentProps extends ISlottableProps<TComponentSlots>, TComponentSlots> = ISlotDefinition<Required<TComponentSlots>> | ((props: TComponentProps) => ISlotDefinition<Required<TComponentSlots>>);
/**
* Defines the contract for partial slot components used in recomposition.
*/
export type IPartialSlotComponent<TComponentProps extends ISlottableProps<TComponentSlots>, TComponentSlots> = ISlotDefinition<TComponentSlots> | ((props: TComponentProps) => ISlotDefinition<TComponentSlots>);
/**
* Component options used by foundation to tie elements together.
*
* * TComponentProps: A styleable props interface for the created component.
* * TTokens: The type for tokens props.
* * TStyleSet: The type for styles properties.
* * TViewProps: The props specific to the view, including processed properties outputted by optional state component.
* If state component is not provided, TComponentProps is the same as TViewProps.
* * TComponentSlots: The slottable components used to build the HOC.
* * TStatics: Static type for statics applied to created component object.
*/
export interface IComponentOptions<TComponentProps extends ISlottableProps<TComponentSlots>, TTokens, TStyleSet extends IStyleSetBase, TViewProps = TComponentProps, TComponentSlots = {}, TStatics = {}> extends IOldComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TStatics> {
/**
* Slot definition object defining the slot component for each slot.
*/
slots?: ISlotComponent<TComponentProps, TComponentSlots>;
/**
* Stateless pure function that receives props to render the output of the component.
*/
view?: IViewComponent<TViewProps, TComponentSlots>;
}
export interface IRecompositionComponentOptions<TComponentProps extends ISlottableProps<TComponentSlots>, TTokens, TStyleSet extends IStyleSetBase, TViewProps = TComponentProps, TComponentSlots = {}, TStatics = {}> extends IOldComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TStatics> {
/**
* Slot definition object defining the slot component for each slot.
*/
slots?: IPartialSlotComponent<TComponentProps, TComponentSlots>;
/**
* Stateless pure function that receives props to render the output of the component.
*/
view?: IViewComponent<TViewProps, TComponentSlots>;
}
/**
* Component helper that defines options as required for ease of use by component consumers.
*/
export type IComponent<TComponentProps extends ISlottableProps<TComponentSlots>, TTokens, TStyleSet extends IStyleSetBase, TViewProps = TComponentProps, TComponentSlots = {}, TStatics = {}> = Required<IComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TComponentSlots, TStatics>>;
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=IComponent.js.map
@@ -0,0 +1 @@
{"version":3,"file":"IComponent.js","sourceRoot":"../src/","sources":["next/IComponent.ts"],"names":[],"mappings":"","sourcesContent":["import * as React from 'react';\nimport { IStyleSetBase } from '@fluentui/style-utilities';\nimport { IComponentOptions as IOldComponentOptions } from '../IComponent';\nimport { ISlots, ISlotDefinition, ISlottableProps } from '../ISlots';\n\n/**\n * Defines the contract for view components.\n */\nexport type IViewComponent<TViewProps, TComponentSlots = {}> = (\n props: React.PropsWithChildren<TViewProps>,\n slots: ISlots<Required<TComponentSlots>>,\n) => ReturnType<React.FunctionComponent>;\n\n/**\n * Defines the contract for slot components.\n */\nexport type ISlotComponent<TComponentProps extends ISlottableProps<TComponentSlots>, TComponentSlots> =\n | ISlotDefinition<Required<TComponentSlots>>\n | ((props: TComponentProps) => ISlotDefinition<Required<TComponentSlots>>);\n\n/**\n * Defines the contract for partial slot components used in recomposition.\n */\nexport type IPartialSlotComponent<TComponentProps extends ISlottableProps<TComponentSlots>, TComponentSlots> =\n | ISlotDefinition<TComponentSlots>\n | ((props: TComponentProps) => ISlotDefinition<TComponentSlots>);\n\n/**\n * Component options used by foundation to tie elements together.\n *\n * * TComponentProps: A styleable props interface for the created component.\n * * TTokens: The type for tokens props.\n * * TStyleSet: The type for styles properties.\n * * TViewProps: The props specific to the view, including processed properties outputted by optional state component.\n * If state component is not provided, TComponentProps is the same as TViewProps.\n * * TComponentSlots: The slottable components used to build the HOC.\n * * TStatics: Static type for statics applied to created component object.\n */\nexport interface IComponentOptions<\n TComponentProps extends ISlottableProps<TComponentSlots>,\n TTokens,\n TStyleSet extends IStyleSetBase,\n TViewProps = TComponentProps,\n TComponentSlots = {},\n TStatics = {},\n> extends IOldComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TStatics> {\n /**\n * Slot definition object defining the slot component for each slot.\n */\n slots?: ISlotComponent<TComponentProps, TComponentSlots>;\n /**\n * Stateless pure function that receives props to render the output of the component.\n */\n view?: IViewComponent<TViewProps, TComponentSlots>;\n}\n\nexport interface IRecompositionComponentOptions<\n TComponentProps extends ISlottableProps<TComponentSlots>,\n TTokens,\n TStyleSet extends IStyleSetBase,\n TViewProps = TComponentProps,\n TComponentSlots = {},\n TStatics = {},\n> extends IOldComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TStatics> {\n /**\n * Slot definition object defining the slot component for each slot.\n */\n slots?: IPartialSlotComponent<TComponentProps, TComponentSlots>;\n /**\n * Stateless pure function that receives props to render the output of the component.\n */\n view?: IViewComponent<TViewProps, TComponentSlots>;\n}\n\n/**\n * Component helper that defines options as required for ease of use by component consumers.\n */\nexport type IComponent<\n TComponentProps extends ISlottableProps<TComponentSlots>,\n TTokens,\n TStyleSet extends IStyleSetBase,\n TViewProps = TComponentProps,\n TComponentSlots = {},\n TStatics = {},\n> = Required<IComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TComponentSlots, TStatics>>;\n"]}
+10
View File
@@ -0,0 +1,10 @@
import * as React from 'react';
import { IStyleSetBase } from '@fluentui/style-utilities';
import { ISlottableProps, ValidProps } from '../ISlots';
import { IComponentOptions } from './IComponent';
/**
* Signature of components created using composed.
*/
export interface IFoundationComponent<TComponentProps extends ValidProps & ISlottableProps<TComponentSlots>, TTokens, TStyleSet extends IStyleSetBase, TViewProps extends TComponentProps = TComponentProps, TComponentSlots = {}, TStatics = {}> extends React.FunctionComponent {
__options?: IComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TComponentSlots, TStatics>;
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=ISlots.js.map
@@ -0,0 +1 @@
{"version":3,"file":"ISlots.js","sourceRoot":"../src/","sources":["next/ISlots.ts"],"names":[],"mappings":"","sourcesContent":["import * as React from 'react';\nimport { IStyleSetBase } from '@fluentui/style-utilities';\nimport { ISlottableProps, ValidProps } from '../ISlots';\nimport { IComponentOptions } from './IComponent';\n\n/**\n * Signature of components created using composed.\n */\nexport interface IFoundationComponent<\n TComponentProps extends ValidProps & ISlottableProps<TComponentSlots>,\n TTokens,\n TStyleSet extends IStyleSetBase,\n TViewProps extends TComponentProps = TComponentProps,\n TComponentSlots = {},\n TStatics = {},\n> extends React.FunctionComponent {\n __options?: IComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TComponentSlots, TStatics>;\n}\n"]}
@@ -0,0 +1,53 @@
import * as React from 'react';
import { IStyleSetBase } from '@fluentui/style-utilities';
import { IComponentOptions, IPartialSlotComponent, IRecompositionComponentOptions, ISlotComponent } from './IComponent';
import { ValidProps, ISlottableProps, ISlotDefinition } from '../ISlots';
import { IFoundationComponent } from './ISlots';
/**
* Assembles a higher order component based on the following: styles, theme, view, and state.
* Imposes a separation of concern and centralizes styling processing to increase ease of use and robustness
* in how components use and apply styling and theming.
*
* Automatically merges and applies themes and styles with theme / styleprops having the highest priority.
* State component, if provided, is passed in props for processing. Props from state / user are automatically processed
* and styled before finally being passed to view.
*
* State components should contain all stateful behavior and should not generate any JSX, but rather simply call
* the view prop.
*
* Views should simply be stateless pure functions that receive all props needed for rendering their output.
*
* State component is optional. If state is not provided, created component is essentially a functional
* stateless component.
*
* @param options - component Component options. See IComponentOptions for more detail.
*/
export declare function composed<TComponentProps extends ValidProps & ISlottableProps<TComponentSlots>, TTokens, TStyleSet extends IStyleSetBase, TViewProps extends TComponentProps = TComponentProps, TComponentSlots = {}, TStatics = {}>(options: IComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TComponentSlots, TStatics>): IFoundationComponent<TComponentProps, TTokens, TStyleSet, TViewProps, TComponentSlots, TStatics> & TStatics;
/**
* Recomposes a functional component based on a base component and the following set of options: styles, theme, view,
* and state. Imposes a separation of concern and centralizes styling processing to increase ease of use and robustness
* in how components use and apply styling and theming.
*
* Automatically merges and applies themes and styles with theme / styleprops having the highest priority.
* State component, if provided, is passed in props for processing. Props from state / user are automatically processed
* and styled before finally being passed to view.
*
* State components should contain all stateful behavior and should not generate any JSX, but rather simply call
* the view prop.
*
* Views should simply be stateless pure functions that receive all props needed for rendering their output.
*
* State component is optional. If state is not provided, created component is essentially a functional
* stateless component.
*
* @param baseComponent - base component to recompose
* @param options - component Component recomposition options. See IComponentOptions for more detail.
*/
export declare function composed<TComponentProps extends ValidProps & ISlottableProps<TComponentSlots>, TTokens, TStyleSet extends IStyleSetBase, TViewProps extends TComponentProps = TComponentProps, TComponentSlots = {}, TStatics = {}>(baseComponent: React.FunctionComponent, options: IRecompositionComponentOptions<TComponentProps, TTokens, TStyleSet, TViewProps, TComponentSlots, TStatics>): IFoundationComponent<TComponentProps, TTokens, TStyleSet, TViewProps, TComponentSlots, TStatics> & TStatics;
/**
* Resolve the passed slots as a function or an object.
*
* @param slots - Slots that need to be resolved as a function or an object.
* @param data - Data to pass to resolve if the first argument was a function.
*/
export declare function resolveSlots<TComponentProps extends ISlottableProps<TComponentSlots>, TComponentSlots>(slots: IPartialSlotComponent<TComponentProps, TComponentSlots> | ISlotComponent<TComponentProps, TComponentSlots> | undefined, data: TComponentProps): ISlotDefinition<Required<TComponentSlots>>;
+206
View File
@@ -0,0 +1,206 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.composed = composed;
exports.resolveSlots = resolveSlots;
var tslib_1 = require("tslib");
var React = require("react");
var merge_styles_1 = require("@fluentui/merge-styles");
var style_utilities_1 = require("@fluentui/style-utilities");
var utilities_1 = require("@fluentui/utilities");
var slots_1 = require("../slots");
var utilities_2 = require("../utilities");
var memoizedClassNamesMap = {};
/**
* Assembles a higher order component based on a set of options or recomposes a functional component based on a
* base component and the a set of options. This set of options is comprised by: styles, theme, view, and state.
*
* Imposes a separation of concern and centralizes styling processing to increase ease of use and robustness
* in how components use and apply styling and theming.
*
* Automatically merges and applies themes and styles with theme / styleprops having the highest priority.
* State component, if provided, is passed in props for processing. Props from state / user are automatically processed
* and styled before finally being passed to view.
*
* State components should contain all stateful behavior and should not generate any JSX, but rather simply call
* the view prop.
*
* Views should simply be stateless pure functions that receive all props needed for rendering their output.
*
* State component is optional. If state is not provided, created component is essentially a functional
* stateless component.
*
* @param baseComponentOrOptions - base component to recompose or component Component options to compose an HOC.
* See IComponentOptions for more detail.
* @param recompositionOptions - component Component recomposition options. See IComponentOptions for more detail.
*/
function composed(baseComponentOrOptions, recompositionOptions) {
if (baseComponentOrOptions === void 0) { baseComponentOrOptions = {}; }
// Check if we are composing or recomposing.
var options;
if (typeof baseComponentOrOptions === 'function' && baseComponentOrOptions.__options) {
var baseComponentOptions_1 = baseComponentOrOptions.__options;
var recompositionSlots_1 = recompositionOptions ? recompositionOptions.slots : undefined;
options = tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, baseComponentOptions_1), recompositionOptions), { slots: function (props) { return (tslib_1.__assign(tslib_1.__assign({}, resolveSlots(baseComponentOptions_1.slots, props)), resolveSlots(recompositionSlots_1, props))); } });
}
else {
options = baseComponentOrOptions;
}
var _a = options.factoryOptions, factoryOptions = _a === void 0 ? {} : _a, view = options.view;
var defaultProp = factoryOptions.defaultProp;
var ResultComponent = function (componentProps) {
var settings = _getCustomizations(options.displayName, React.useContext(utilities_1.CustomizerContext), options.fields);
var stateReducer = options.state;
if (stateReducer) {
// Don't assume state will return all props, so spread useState result over component props.
componentProps = tslib_1.__assign(tslib_1.__assign({}, componentProps), stateReducer(componentProps));
}
var theme = componentProps.theme || settings.theme;
var tokens = _resolveTokens(componentProps, theme, options.tokens, settings.tokens, componentProps.tokens);
var styles;
var finalStyles = {};
// We get the entry in the memoized classNamesMap for the current component or create one if it doesn't exist.
var displayName = options.displayName;
// If no displayName has been specified, then do not use caching.
if (displayName) {
if (!memoizedClassNamesMap.hasOwnProperty(displayName)) {
memoizedClassNamesMap[displayName] = { map: {} };
}
var current = memoizedClassNamesMap[displayName];
// Memoize based on the tokens definition.
var tokenKeys = Object.keys(tokens).sort();
for (var _i = 0, tokenKeys_1 = tokenKeys; _i < tokenKeys_1.length; _i++) {
var key = tokenKeys_1[_i];
var nextToken = tokens[key];
if (nextToken === undefined) {
nextToken = '__undefined__';
}
if (!current.map.hasOwnProperty(nextToken)) {
current.map[nextToken] = { map: {} };
}
current = current.map[nextToken];
}
// Memoize the slots so we only have to get Object.keys once.
var slots = memoizedClassNamesMap[displayName].slots;
var defaultStyles = void 0;
if (!slots) {
defaultStyles = _resolveStyles(componentProps, theme, tokens, options.styles, settings.styles);
memoizedClassNamesMap[displayName].slots = Object.keys(defaultStyles);
slots = memoizedClassNamesMap[displayName].slots;
}
// Memoize based on the base styling of the component (i.e. without user specified props).
for (var _a = 0, slots_2 = slots; _a < slots_2.length; _a++) {
var key = slots_2[_a];
if (!current.map.hasOwnProperty(key)) {
// Get default styles once if we didn't get them before.
if (!defaultStyles) {
defaultStyles = _resolveStyles(componentProps, theme, tokens, options.styles, settings.styles);
}
current.map[key] = { className: (0, merge_styles_1.mergeStyles)(defaultStyles[key]), map: {} };
}
finalStyles[key] = current.map[key].className;
}
if (componentProps.styles) {
var userStyles = typeof componentProps.styles === 'function'
? componentProps.styles(componentProps, theme, tokens)
: componentProps.styles;
styles = (0, style_utilities_1.concatStyleSets)(styles, userStyles);
if (userStyles) {
var userStyleKeys = Object.keys(userStyles);
for (var _b = 0, userStyleKeys_1 = userStyleKeys; _b < userStyleKeys_1.length; _b++) {
var key = userStyleKeys_1[_b];
if (finalStyles.hasOwnProperty(key)) {
finalStyles[key] = (0, merge_styles_1.mergeStyles)([current.map[key].className], userStyles[key]);
}
else {
finalStyles[key] = (0, merge_styles_1.mergeStyles)(userStyles[key]);
}
}
}
}
}
else {
styles = _resolveStyles(componentProps, theme, tokens, options.styles, settings.styles, componentProps.styles);
}
var viewProps = tslib_1.__assign(tslib_1.__assign({}, componentProps), { styles: styles, tokens: tokens, _defaultStyles: displayName ? finalStyles : styles });
if (!options.slots) {
throw new Error("Component ".concat(options.displayName || (view && view.name) || '', " is missing slot definitions."));
}
var Slots = typeof options.slots === 'function'
? (0, slots_1.getSlots)(viewProps, options.slots(viewProps))
: (0, slots_1.getSlots)(viewProps, options.slots);
return view ? view(viewProps, Slots) : null;
};
ResultComponent.displayName = options.displayName || (view && view.name);
// If a shorthand prop is defined, create a factory for the component.
// TODO: This shouldn't be a concern of createComponent.. factoryOptions should just be forwarded.
// Need to weigh creating default factories on component creation vs. memoizing them on use in slots.tsx.
if (defaultProp) {
ResultComponent.create = (0, slots_1.createFactory)(ResultComponent, { defaultProp: defaultProp });
}
ResultComponent.__options = options;
(0, utilities_2.assign)(ResultComponent, options.statics);
// Later versions of TypeSript should allow us to merge objects in a type safe way and avoid this cast.
return ResultComponent;
}
/**
* Resolve the passed slots as a function or an object.
*
* @param slots - Slots that need to be resolved as a function or an object.
* @param data - Data to pass to resolve if the first argument was a function.
*/
function resolveSlots(slots, data) {
var resolvedSlots = slots ? (typeof slots === 'function' ? slots(data) : slots) : {};
return resolvedSlots;
}
/**
* Resolve all styles functions with both props and tokens and flatten results along with all styles objects.
*/
function _resolveStyles(props, theme, tokens) {
var allStyles = [];
for (var _i = 3; _i < arguments.length; _i++) {
allStyles[_i - 3] = arguments[_i];
}
return style_utilities_1.concatStyleSets.apply(void 0, allStyles.map(function (styles) {
return typeof styles === 'function' ? styles(props, theme, tokens) : styles;
}));
}
/**
* Resolve all tokens functions with props flatten results along with all tokens objects.
*/
function _resolveTokens(props, theme) {
var allTokens = [];
for (var _i = 2; _i < arguments.length; _i++) {
allTokens[_i - 2] = arguments[_i];
}
var tokens = {};
for (var _a = 0, allTokens_1 = allTokens; _a < allTokens_1.length; _a++) {
var currentTokens = allTokens_1[_a];
if (currentTokens) {
// TODO: why is this cast needed? TS seems to think there is a (TToken | Function) union from somewhere.
currentTokens =
typeof currentTokens === 'function'
? currentTokens(props, theme)
: currentTokens;
if (Array.isArray(currentTokens)) {
currentTokens = _resolveTokens.apply(void 0, tslib_1.__spreadArray([props, theme], currentTokens, false));
}
(0, utilities_2.assign)(tokens, currentTokens);
}
}
return tokens;
}
/**
* Helper function for calling Customizations.getSettings falling back to default fields.
*
* @param displayName Displayable name for component.
* @param context React context passed to component containing contextual settings.
* @param fields Optional list of properties to grab from global store and context.
*/
function _getCustomizations(displayName, context, fields) {
// TODO: do we want field props? should fields be part of IComponent and used here?
// TODO: should we centrally define DefaultFields? (not exported from styling)
// TODO: tie this array to ICustomizationProps, such that each array element is keyof ICustomizationProps
var DefaultFields = ['theme', 'styles', 'tokens'];
return utilities_1.Customizations.getSettings(fields || DefaultFields, displayName, context.customizations);
}
//# sourceMappingURL=composed.js.map
File diff suppressed because one or more lines are too long
+30
View File
@@ -0,0 +1,30 @@
import * as React from 'react';
import { IFactoryOptions } from './IComponent';
import { ISlot, ISlots, ISlotDefinition, ISlotFactory, ISlottableProps, ValidProps, ValidShorthand } from './ISlots';
/**
* This function is required for any module that uses slots.
*
* This function is a slot resolver that automatically evaluates slot functions to generate React elements.
* A byproduct of this resolver is that it removes slots from the React hierarchy by bypassing React.createElement.
*
* To use this function on a per-file basis, use the jsx directive targeting withSlots.
* This directive must be the FIRST LINE in the file to work correctly.
* Usage of this pragma also requires withSlots import statement.
*
* See React.createElement
*/
export declare function withSlots<P extends {}>(type: ISlot<P> | React.FunctionComponent<P> | string, props?: (React.Attributes & P) | null, ...children: React.ReactNode[]): ReturnType<React.FunctionComponent<P>>;
/**
* This function creates factories that render ouput depending on the user ISlotProp props passed in.
* @param DefaultComponent - Base component to render when not overridden by user props.
* @param options - Factory options, including defaultProp value for shorthand prop mapping.
* @returns ISlotFactory function used for rendering slots.
*/
export declare function createFactory<TProps extends ValidProps, TShorthandProp extends ValidShorthand = never>(DefaultComponent: React.ComponentType<TProps>, options?: IFactoryOptions<TProps>): ISlotFactory<TProps, TShorthandProp>;
/**
* This function generates slots that can be used in JSX given a definition of slots and their corresponding types.
* @param userProps - Props as pass to component.
* @param slots - Slot definition object defining the default slot component for each slot.
* @returns A set of created slots that components can render in JSX.
*/
export declare function getSlots<TComponentProps extends ISlottableProps<TComponentSlots>, TComponentSlots>(userProps: TComponentProps, slots: ISlotDefinition<Required<TComponentSlots>>): ISlots<Required<TComponentSlots>>;
+190
View File
@@ -0,0 +1,190 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.withSlots = withSlots;
exports.createFactory = createFactory;
exports.getSlots = getSlots;
var tslib_1 = require("tslib");
var React = require("react");
var merge_styles_1 = require("@fluentui/merge-styles");
var utilities_1 = require("@fluentui/utilities");
var utilities_2 = require("./utilities");
/**
* This function is required for any module that uses slots.
*
* This function is a slot resolver that automatically evaluates slot functions to generate React elements.
* A byproduct of this resolver is that it removes slots from the React hierarchy by bypassing React.createElement.
*
* To use this function on a per-file basis, use the jsx directive targeting withSlots.
* This directive must be the FIRST LINE in the file to work correctly.
* Usage of this pragma also requires withSlots import statement.
*
* See React.createElement
*/
// Can't use typeof on React.createElement since it's overloaded. Approximate createElement's signature for now
// and widen as needed.
function withSlots(type, props) {
var children = [];
for (var _i = 2; _i < arguments.length; _i++) {
children[_i - 2] = arguments[_i];
}
var slotType = type;
if (slotType.isSlot) {
// Since we are bypassing createElement, use React.Children.toArray to make sure children are
// properly assigned keys.
// TODO: should this be mutating? does React mutate children subprop with createElement?
// TODO: will toArray clobber existing keys?
// TODO: React generates warnings because it doesn't detect hidden member _store that is set in createElement.
// Even children passed to createElement without keys don't generate this warning.
// Is there a better way to prevent slots from appearing in hierarchy? toArray doesn't address root issue.
children = React.Children.toArray(children);
// TODO: There is something weird going on here with children embedded in props vs. rest args.
// Comment out these lines to see. Make sure this function is doing the right things.
if (children.length === 0) {
return slotType(props);
}
return slotType(tslib_1.__assign(tslib_1.__assign({}, props), { children: children }));
}
else {
// TODO: Are there some cases where children should NOT be spread? Also, spreading reraises perf question.
// Children had to be spread to avoid breaking KeytipData in Toggle.view:
// react-dom.development.js:18931 Uncaught TypeError: children is not a function
// Without spread, function child is a child array of one element
// TODO: is there a reason this can't be:
// return React.createElement.apply(this, arguments);
return React.createElement.apply(React, tslib_1.__spreadArray([type, props], children, false));
}
}
/**
* This function creates factories that render ouput depending on the user ISlotProp props passed in.
* @param DefaultComponent - Base component to render when not overridden by user props.
* @param options - Factory options, including defaultProp value for shorthand prop mapping.
* @returns ISlotFactory function used for rendering slots.
*/
function createFactory(DefaultComponent, options) {
if (options === void 0) { options = {}; }
var _a = options.defaultProp, defaultProp = _a === void 0 ? 'children' : _a;
var result = function (componentProps, userProps, userSlotOptions, defaultStyles, theme) {
// If they passed in raw JSX, just return that.
if (React.isValidElement(userProps)) {
return userProps;
}
var flattenedUserProps = _translateShorthand(defaultProp, userProps);
var finalProps = _constructFinalProps(defaultStyles, theme, componentProps, flattenedUserProps);
if (userSlotOptions) {
if (userSlotOptions.component) {
// TODO: Remove cast if possible. This cast is needed because TS errors on the intrinsic portion of ReactType.
// return <userSlotOptions.component {...finalProps} />;
var UserComponent = userSlotOptions.component;
return React.createElement(UserComponent, tslib_1.__assign({}, finalProps));
}
if (userSlotOptions.render) {
return userSlotOptions.render(finalProps, DefaultComponent);
}
}
return React.createElement(DefaultComponent, tslib_1.__assign({}, finalProps));
};
return result;
}
/**
* Default factory for components without explicit factories.
*/
var defaultFactory = (0, utilities_1.memoizeFunction)(function (type) { return createFactory(type); });
/**
* This function generates slots that can be used in JSX given a definition of slots and their corresponding types.
* @param userProps - Props as pass to component.
* @param slots - Slot definition object defining the default slot component for each slot.
* @returns A set of created slots that components can render in JSX.
*/
function getSlots(userProps, slots) {
var result = {};
// userProps already has default props mixed in by createComponent. Recast here to gain typing for this function.
var mixedProps = userProps;
var _loop_1 = function (name_1) {
if (slots.hasOwnProperty(name_1)) {
// This closure method requires the use of withSlots to prevent unnecessary rerenders. This is because React
// detects each closure as a different component (since it is a new instance) from the previous one and then
// forces a rerender of the entire slot subtree. For now, the only way to avoid this is to use withSlots, which
// bypasses the call to React.createElement.
var slot = function (componentProps) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
if (args.length > 0) {
// If React.createElement is being incorrectly used with slots, there will be additional arguments.
// We can detect these additional arguments and error on their presence.
throw new Error('Any module using getSlots must use withSlots. Please see withSlots javadoc for more info.');
}
// TODO: having TS infer types here seems to cause infinite loop.
// use explicit types or casting to preserve typing if possible.
// TODO: this should be a lookup on TProps property instead of being TProps directly, which is probably
// causing the infinite loop
return _renderSlot(slots[name_1],
// TODO: this cast to any is hiding a relationship issue between the first two args
componentProps, mixedProps[name_1], mixedProps.slots && mixedProps.slots[name_1],
// _defaultStyles should always be present, but a check for existence is added to make view tests
// easier to use.
mixedProps._defaultStyles && mixedProps._defaultStyles[name_1], mixedProps.theme);
};
slot.isSlot = true;
result[name_1] = slot;
}
};
for (var name_1 in slots) {
_loop_1(name_1);
}
return result;
}
/**
* Helper function that translates shorthand as needed.
* @param defaultProp
* @param slotProps
*/
function _translateShorthand(defaultProp, slotProps) {
var _a;
var transformedProps;
if (typeof slotProps === 'string' || typeof slotProps === 'number' || typeof slotProps === 'boolean') {
transformedProps = (_a = {},
_a[defaultProp] = slotProps,
_a);
}
else {
transformedProps = slotProps;
}
return transformedProps;
}
/**
* Helper function that constructs final styles and props given a series of props ordered by increasing priority.
*/
function _constructFinalProps(defaultStyles, theme) {
var allProps = [];
for (var _i = 2; _i < arguments.length; _i++) {
allProps[_i - 2] = arguments[_i];
}
var finalProps = {};
var classNames = [];
for (var _a = 0, allProps_1 = allProps; _a < allProps_1.length; _a++) {
var props = allProps_1[_a];
classNames.push(props && props.className);
(0, utilities_2.assign)(finalProps, props);
}
finalProps.className = (0, merge_styles_1.mergeCss)([defaultStyles, classNames], { rtl: (0, utilities_1.getRTL)(theme) });
return finalProps;
}
/**
* Render a slot given component and user props. Uses component factory if available, otherwise falls back
* to default factory.
* @param ComponentType Factory component type.
* @param componentProps The properties passed into slot from within the component.
* @param userProps The user properties passed in from outside of the component.
*/
function _renderSlot(ComponentType, componentProps, userProps, slotOptions, defaultStyles, theme) {
if (ComponentType.create !== undefined) {
return ComponentType.create(componentProps, userProps, slotOptions, defaultStyles);
}
else {
// TODO: need to resolve typing / generic issues passing through memoizeFunction. for now, cast to 'unknown'
return defaultFactory(ComponentType)(componentProps, userProps, slotOptions, defaultStyles, theme);
}
}
//# sourceMappingURL=slots.js.map
File diff suppressed because one or more lines are too long
+2
View File
@@ -0,0 +1,2 @@
import { __assign } from 'tslib';
export declare const assign: typeof __assign;
+6
View File
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.assign = void 0;
var tslib_1 = require("tslib");
exports.assign = tslib_1.__assign;
//# sourceMappingURL=utilities.js.map
@@ -0,0 +1 @@
{"version":3,"file":"utilities.js","sourceRoot":"../src/","sources":["utilities.ts"],"names":[],"mappings":";;;AAAA,+BAAiC;AACpB,QAAA,MAAM,GAAG,gBAAQ,CAAC","sourcesContent":["import { __assign } from 'tslib';\nexport const assign = __assign;\n"]}
+1
View File
@@ -0,0 +1 @@
export {};
+7
View File
@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// Do not modify this file; it is generated as part of publish.
// The checked in version is a placeholder only and will not be updated.
var set_version_1 = require("@fluentui/set-version");
(0, set_version_1.setVersion)('@fluentui/foundation-legacy', '8.6.5');
//# sourceMappingURL=version.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"version.js","sourceRoot":"../src/","sources":["version.ts"],"names":[],"mappings":";;AAAA,+DAA+D;AAC/D,wEAAwE;AACxE,qDAAmD;AACnD,IAAA,wBAAU,EAAC,6BAA6B,EAAE,OAAO,CAAC,CAAC","sourcesContent":["// Do not modify this file; it is generated as part of publish.\n// The checked in version is a placeholder only and will not be updated.\nimport { setVersion } from '@fluentui/set-version';\nsetVersion('@fluentui/foundation-legacy', '8.6.5');"]}