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
@@ -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