Private
Public Access
1
0

feat: Fluent UI Outlook Lite + connections mockup

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

View File

@@ -0,0 +1,30 @@
import * as React from 'react';
import { isFluentTrigger } from './isFluentTrigger';
/**
* @internal
* resolve the trigger props to the children, either by calling the render function, or cloning with the new props.
*/ export function applyTriggerPropsToChildren(children, triggerChildProps) {
if (typeof children === 'function') {
return children(triggerChildProps);
} else if (children) {
return cloneTriggerTree(children, triggerChildProps);
}
// Components in React should return either JSX elements or "null", otherwise React will throw:
// Nothing was returned from render.
// This usually means a return statement is missing. Or, to render nothing, return null.
return children || null;
}
/**
* Clones a React element tree, and applies the given props to the first grandchild that is not
* a FluentTriggerComponent or React Fragment (the same element returned by {@link getTriggerChild}).
*/ function cloneTriggerTree(child, triggerProps) {
if (!React.isValidElement(child) || child.type === React.Fragment) {
throw new Error('A trigger element must be a single element for this component. ' + "Please ensure that you're not using React Fragments.");
}
if (isFluentTrigger(child)) {
const grandchild = cloneTriggerTree(child.props.children, triggerProps);
return React.cloneElement(child, undefined, grandchild);
} else {
return React.cloneElement(child, triggerProps);
}
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/trigger/applyTriggerPropsToChildren.ts"],"sourcesContent":["import * as React from 'react';\nimport { isFluentTrigger } from './isFluentTrigger';\nimport type { TriggerProps } from './types';\n\n/**\n * @internal\n * resolve the trigger props to the children, either by calling the render function, or cloning with the new props.\n */\nexport function applyTriggerPropsToChildren<TriggerChildProps>(\n children: TriggerProps<TriggerChildProps>['children'],\n triggerChildProps: TriggerChildProps,\n): React.ReactElement | null {\n if (typeof children === 'function') {\n return children(triggerChildProps);\n } else if (children) {\n return cloneTriggerTree(children, triggerChildProps);\n }\n\n // Components in React should return either JSX elements or \"null\", otherwise React will throw:\n // Nothing was returned from render.\n // This usually means a return statement is missing. Or, to render nothing, return null.\n return children || null;\n}\n\n/**\n * Clones a React element tree, and applies the given props to the first grandchild that is not\n * a FluentTriggerComponent or React Fragment (the same element returned by {@link getTriggerChild}).\n */\nfunction cloneTriggerTree<TriggerChildProps>(\n child: TriggerProps['children'],\n triggerProps: TriggerChildProps,\n): React.ReactElement {\n if (!React.isValidElement(child) || child.type === React.Fragment) {\n throw new Error(\n 'A trigger element must be a single element for this component. ' +\n \"Please ensure that you're not using React Fragments.\",\n );\n }\n\n if (isFluentTrigger(child)) {\n const grandchild = cloneTriggerTree(child.props.children, triggerProps);\n return React.cloneElement(child, undefined, grandchild);\n } else {\n return React.cloneElement(child, triggerProps as TriggerChildProps & React.Attributes);\n }\n}\n"],"names":["React","isFluentTrigger","applyTriggerPropsToChildren","children","triggerChildProps","cloneTriggerTree","child","triggerProps","isValidElement","type","Fragment","Error","grandchild","props","cloneElement","undefined"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,eAAe,QAAQ,oBAAoB;AAGpD;;;CAGC,GACD,OAAO,SAASC,4BACdC,QAAqD,EACrDC,iBAAoC;IAEpC,IAAI,OAAOD,aAAa,YAAY;QAClC,OAAOA,SAASC;IAClB,OAAO,IAAID,UAAU;QACnB,OAAOE,iBAAiBF,UAAUC;IACpC;IAEA,+FAA+F;IAC/F,sCAAsC;IACtC,0FAA0F;IAC1F,OAAOD,YAAY;AACrB;AAEA;;;CAGC,GACD,SAASE,iBACPC,KAA+B,EAC/BC,YAA+B;IAE/B,IAAI,CAACP,MAAMQ,cAAc,CAACF,UAAUA,MAAMG,IAAI,KAAKT,MAAMU,QAAQ,EAAE;QACjE,MAAM,IAAIC,MACR,oEACE;IAEN;IAEA,IAAIV,gBAAgBK,QAAQ;QAC1B,MAAMM,aAAaP,iBAAiBC,MAAMO,KAAK,CAACV,QAAQ,EAAEI;QAC1D,OAAOP,MAAMc,YAAY,CAACR,OAAOS,WAAWH;IAC9C,OAAO;QACL,OAAOZ,MAAMc,YAAY,CAACR,OAAOC;IACnC;AACF"}

View File

@@ -0,0 +1,31 @@
import * as React from 'react';
import { isFluentTrigger } from './isFluentTrigger';
/**
* @internal
* Gets the trigger element of a FluentTriggerComponent (such as Tooltip or MenuTrigger).
*
* In the case where the immediate child is itself a FluentTriggerComponent and/or React Fragment,
* it returns the first descendant that is _not_ a FluentTriggerComponent or Fragment.
* This allows multiple triggers to be stacked, and still apply their props to the actual trigger element.
*
* For example, the following returns `<div id="child" />`:
* ```jsx
* getTriggerChild(
* <Tooltip>
* <MenuTrigger>
* <div id="child" />
* </MenuTrigger>
* </Tooltip>
* );
* ```
*
* In the case where the immediate child is not a valid element,
* null is returned
*/ export function getTriggerChild(children) {
if (!React.isValidElement(children)) {
return null;
}
return isFluentTrigger(children) ? getTriggerChild(// FIXME: This casting should be unnecessary as isFluentTrigger is a guard type method,
// but for some reason it's failing on build
children.props.children) : children;
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/trigger/getTriggerChild.ts"],"sourcesContent":["import * as React from 'react';\nimport { isFluentTrigger } from './isFluentTrigger';\nimport type { TriggerProps } from './types';\n\n/**\n * @internal\n * Gets the trigger element of a FluentTriggerComponent (such as Tooltip or MenuTrigger).\n *\n * In the case where the immediate child is itself a FluentTriggerComponent and/or React Fragment,\n * it returns the first descendant that is _not_ a FluentTriggerComponent or Fragment.\n * This allows multiple triggers to be stacked, and still apply their props to the actual trigger element.\n *\n * For example, the following returns `<div id=\"child\" />`:\n * ```jsx\n * getTriggerChild(\n * <Tooltip>\n * <MenuTrigger>\n * <div id=\"child\" />\n * </MenuTrigger>\n * </Tooltip>\n * );\n * ```\n *\n * In the case where the immediate child is not a valid element,\n * null is returned\n */\nexport function getTriggerChild<TriggerChildProps>(\n children: TriggerProps<TriggerChildProps>['children'],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): (React.ReactElement<Partial<TriggerChildProps>> & { ref?: React.Ref<any> }) | null {\n if (!React.isValidElement<TriggerChildProps>(children)) {\n return null;\n }\n return isFluentTrigger(children)\n ? getTriggerChild(\n // FIXME: This casting should be unnecessary as isFluentTrigger is a guard type method,\n // but for some reason it's failing on build\n (children.props as TriggerProps).children,\n )\n : children;\n}\n"],"names":["React","isFluentTrigger","getTriggerChild","children","isValidElement","props"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,eAAe,QAAQ,oBAAoB;AAGpD;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,OAAO,SAASC,gBACdC,QAAqD;IAGrD,IAAI,CAACH,MAAMI,cAAc,CAAoBD,WAAW;QACtD,OAAO;IACT;IACA,OAAOF,gBAAgBE,YACnBD,gBAGE,AAFA,uFAAuF;IACvF,4CAA4C;IAC3CC,SAASE,KAAK,CAAkBF,QAAQ,IAE3CA;AACN"}

View File

@@ -0,0 +1,3 @@
export { applyTriggerPropsToChildren } from './applyTriggerPropsToChildren';
export { getTriggerChild } from './getTriggerChild';
export { isFluentTrigger } from './isFluentTrigger';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/trigger/index.ts"],"sourcesContent":["export { applyTriggerPropsToChildren } from './applyTriggerPropsToChildren';\nexport { getTriggerChild } from './getTriggerChild';\nexport { isFluentTrigger } from './isFluentTrigger';\nexport type { FluentTriggerComponent, TriggerProps } from './types';\n"],"names":["applyTriggerPropsToChildren","getTriggerChild","isFluentTrigger"],"mappings":"AAAA,SAASA,2BAA2B,QAAQ,gCAAgC;AAC5E,SAASC,eAAe,QAAQ,oBAAoB;AACpD,SAASC,eAAe,QAAQ,oBAAoB"}

View File

@@ -0,0 +1,8 @@
import * as React from 'react';
/**
* @internal
* Checks if a given element is a FluentUI trigger (e.g. `MenuTrigger` or `Tooltip`).
* See the {@link FluentTriggerComponent} type for more info.
*/ export function isFluentTrigger(element) {
return Boolean(element.type.isFluentTriggerComponent);
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/trigger/isFluentTrigger.ts"],"sourcesContent":["import * as React from 'react';\nimport type { FluentTriggerComponent, TriggerProps } from './types';\n\n/**\n * @internal\n * Checks if a given element is a FluentUI trigger (e.g. `MenuTrigger` or `Tooltip`).\n * See the {@link FluentTriggerComponent} type for more info.\n */\nexport function isFluentTrigger(element: React.ReactElement): element is React.ReactElement<TriggerProps> {\n return Boolean((element.type as FluentTriggerComponent).isFluentTriggerComponent);\n}\n"],"names":["React","isFluentTrigger","element","Boolean","type","isFluentTriggerComponent"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAG/B;;;;CAIC,GACD,OAAO,SAASC,gBAAgBC,OAA2B;IACzD,OAAOC,QAAQ,AAACD,QAAQE,IAAI,CAA4BC,wBAAwB;AAClF"}

View File

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

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/trigger/types.ts"],"sourcesContent":["import * as React from 'react';\n\n/**\n * @internal\n * Allows a component to be tagged as a FluentUI trigger component.\n *\n * Triggers are special-case components: they attach event listeners and other props on their child,\n * and use them to trigger another component to show. Examples include `MenuTrigger` and `Tooltip`.\n *\n * A component can be tagged as a trigger as follows:\n * ```ts\n * const MyComponent: React.FC<MyComponentProps> & FluentTriggerComponent = ...;\n *\n * MyComponent.isFluentTriggerComponent = true; // MUST also set this to true\n * ```\n */\nexport type FluentTriggerComponent = {\n isFluentTriggerComponent?: boolean;\n};\n\n/**\n * A trigger may have a children that could be either:\n * 1. A single element\n * 2. A render function that will receive properties and must return a valid element or null\n * 3. null or undefined\n */\nexport type TriggerProps<TriggerChildProps = unknown> = {\n children?: React.ReactElement | ((props: TriggerChildProps) => React.ReactElement | null) | null;\n};\n"],"names":["React"],"mappings":"AAAA,YAAYA,WAAW,QAAQ"}