68 lines
3.9 KiB
JavaScript
68 lines
3.9 KiB
JavaScript
import * as React from 'react';
|
|
import { SLOT_ELEMENT_TYPE_SYMBOL, SLOT_RENDER_FUNCTION_SYMBOL } from './constants';
|
|
/**
|
|
* Creates a slot from a slot shorthand or properties (`props.SLOT_NAME` or `props` itself)
|
|
* @param value - the value of the slot, it can be a slot shorthand, a slot component or a slot properties
|
|
* @param options - values you can pass to alter the signature of a slot, those values are:
|
|
*
|
|
* * `elementType` - the base element type of a slot, defaults to `'div'`
|
|
* * `defaultProps` - similar to a React component declaration, you can provide a slot default properties to be merged with the shorthand/properties provided.
|
|
*/ export function always(value, options) {
|
|
const { defaultProps, elementType } = options;
|
|
const props = resolveShorthand(value);
|
|
/**
|
|
* Casting is required here as SlotComponentType is a function, not an object.
|
|
* Although SlotComponentType has a function signature, it is still just an object.
|
|
* This is required to make a slot callable (JSX compatible), this is the exact same approach
|
|
* that is used on `@types/react` components
|
|
*/ const propsWithMetadata = {
|
|
...defaultProps,
|
|
...props,
|
|
[SLOT_ELEMENT_TYPE_SYMBOL]: elementType
|
|
};
|
|
if (props && typeof props.children === 'function') {
|
|
propsWithMetadata[SLOT_RENDER_FUNCTION_SYMBOL] = props.children;
|
|
propsWithMetadata.children = defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.children;
|
|
}
|
|
return propsWithMetadata;
|
|
}
|
|
/**
|
|
* Creates a slot from a slot shorthand or properties (`props.SLOT_NAME` or `props` itself)
|
|
* @param value - the value of the slot, it can be a slot shorthand, a slot component or a slot properties
|
|
* @param options - values you can pass to alter the signature of a slot, those values are:
|
|
*
|
|
* * `elementType` - the base element type of a slot, defaults to `'div'`
|
|
* * `defaultProps` - similar to a React component declaration, you can provide a slot default properties to be merged with the shorthand/properties provided
|
|
* * `renderByDefault` - a boolean that indicates if a slot will be rendered even if it's base value is `undefined`.
|
|
* By default if `props.SLOT_NAME` is `undefined` then `state.SLOT_NAME` becomes `undefined`
|
|
* and nothing will be rendered, but if `renderByDefault = true` then `state.SLOT_NAME` becomes an object
|
|
* with the values provided by `options.defaultProps` (or `{}`). This is useful for cases such as providing a default content
|
|
* in case no shorthand is provided, like the case of the `expandIcon` slot for the `AccordionHeader`
|
|
*/ export function optional(value, options) {
|
|
if (value === null || value === undefined && !options.renderByDefault) {
|
|
return undefined;
|
|
}
|
|
return always(value, options);
|
|
}
|
|
/**
|
|
* Helper function that converts a slot shorthand or properties to a slot properties object
|
|
* The main difference between this function and `slot` is that this function does not return the metadata required for a slot to be considered a properly renderable slot, it only converts the value to a slot properties object
|
|
* @param value - the value of the slot, it can be a slot shorthand or a slot properties object
|
|
*/ export function resolveShorthand(value) {
|
|
if (typeof value === 'string' || typeof value === 'number' || Array.isArray(value) || // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
React.isValidElement(value)) {
|
|
return {
|
|
children: value
|
|
};
|
|
}
|
|
if (value && typeof value !== 'object' && process.env.NODE_ENV !== 'production') {
|
|
// TODO: would be nice to have a link to slot documentation in this error message
|
|
// eslint-disable-next-line no-console
|
|
console.error(`@fluentui/react-utilities [slot.${resolveShorthand.name}]:
|
|
A slot got an invalid value "${value}" (${typeof value}).
|
|
A valid value for a slot is a slot shorthand or slot properties object.
|
|
Slot shorthands can be strings, numbers, arrays or JSX elements`);
|
|
}
|
|
return value;
|
|
}
|