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,137 @@
import * as React from 'react';
import { createPriorityQueue } from '@fluentui/react-utilities';
function assignDefined(a, b) {
// This cast is required, as Object.entries will return string as key which is not indexable
for (const [key, prop] of Object.entries(b)){
// eslint-disable-next-line eqeqeq
if (prop != undefined) {
a[key] = prop;
}
}
}
const defaulToastOptions = {
onStatusChange: undefined,
priority: 0,
pauseOnHover: false,
pauseOnWindowBlur: false,
position: 'bottom-end',
timeout: 3000
};
// Multiple toasts can be dispatched in a single tick, use counter to prevent collisions
let counter = 0;
/**
* Toast are managed outside of the react lifecycle because they can be
* dispatched imperatively. Therefore the state of toast visibility can't
* really be managed properly by a declarative lifecycle.
*/ export function createToaster(options) {
const { limit = Number.POSITIVE_INFINITY } = options;
const visibleToasts = new Set();
const toasts = new Map();
const queue = createPriorityQueue((ta, tb)=>{
const a = toasts.get(ta);
const b = toasts.get(tb);
if (!a || !b) {
return 0;
}
if (a.priority === b.priority) {
return a.order - b.order;
}
return a.priority - b.priority;
});
const isToastVisible = (toastId)=>{
return visibleToasts.has(toastId);
};
/**
* Updates an existing toast with any available option
*/ const updateToast = (toastOptions)=>{
const { toastId } = toastOptions;
const toastToUpdate = toasts.get(toastId);
if (!toastToUpdate) {
return;
}
Object.assign(toastToUpdate, toastOptions);
toastToUpdate.updateId++;
};
/**
* Dismisses a toast with a specific id
*/ const dismissToast = (toastId)=>{
visibleToasts.delete(toastId);
};
/**
* Dismisses all toasts and clears the queue
*/ const dismissAllToasts = ()=>{
visibleToasts.clear();
queue.clear();
};
/**
* @param toastOptions user configured options
* @param onUpdate Some toast methods can result in UI changes (i.e. close) use this to dispatch callbacks
*/ const buildToast = (toastOptions, onUpdate)=>{
var _toast_onStatusChange;
const { toastId, content, toasterId } = toastOptions;
if (toasts.has(toastId)) {
return;
}
const close = ()=>{
var _toast_onStatusChange;
const toast = toasts.get(toastId);
if (!toast) {
return;
}
visibleToasts.delete(toastId);
onUpdate();
(_toast_onStatusChange = toast.onStatusChange) === null || _toast_onStatusChange === void 0 ? void 0 : _toast_onStatusChange.call(toast, null, {
status: 'dismissed',
...toast
});
};
const remove = ()=>{
const toast = toasts.get(toastId);
if (!toast) {
return;
}
toasts.delete(toastId);
if (visibleToasts.size < limit && queue.peek()) {
const nextToast = toasts.get(queue.dequeue());
if (!nextToast) {
return;
}
visibleToasts.add(nextToast.toastId);
}
onUpdate();
};
const toast = {
...defaulToastOptions,
close,
remove,
toastId,
content,
updateId: 0,
toasterId,
order: counter++,
data: {},
imperativeRef: React.createRef()
};
assignDefined(toast, options);
assignDefined(toast, toastOptions);
toasts.set(toastId, toast);
(_toast_onStatusChange = toast.onStatusChange) === null || _toast_onStatusChange === void 0 ? void 0 : _toast_onStatusChange.call(toast, null, {
status: 'queued',
...toast
});
if (visibleToasts.size >= limit) {
queue.enqueue(toastId);
} else {
visibleToasts.add(toastId);
}
};
return {
buildToast,
dismissAllToasts,
dismissToast,
isToastVisible,
updateToast,
visibleToasts,
toasts
};
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
import { EVENTS } from '../constants';
export function dismissAllToasts(toasterId = undefined, targetDocument) {
const event = new CustomEvent(EVENTS.dismissAll, {
bubbles: false,
cancelable: false,
detail: {
toasterId
}
});
targetDocument.dispatchEvent(event);
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/state/vanilla/dismissAllToasts.ts"],"sourcesContent":["import { EVENTS } from '../constants';\nimport { DismissAllToastsEventDetail, ToasterId } from '../types';\n\nexport function dismissAllToasts(toasterId: ToasterId | undefined = undefined, targetDocument: Document): void {\n const event = new CustomEvent<DismissAllToastsEventDetail>(EVENTS.dismissAll, {\n bubbles: false,\n cancelable: false,\n detail: { toasterId },\n });\n targetDocument.dispatchEvent(event);\n}\n"],"names":["EVENTS","dismissAllToasts","toasterId","undefined","targetDocument","event","CustomEvent","dismissAll","bubbles","cancelable","detail","dispatchEvent"],"mappings":"AAAA,SAASA,MAAM,QAAQ,eAAe;AAGtC,OAAO,SAASC,iBAAiBC,YAAmCC,SAAS,EAAEC,cAAwB;IACrG,MAAMC,QAAQ,IAAIC,YAAyCN,OAAOO,UAAU,EAAE;QAC5EC,SAAS;QACTC,YAAY;QACZC,QAAQ;YAAER;QAAU;IACtB;IACAE,eAAeO,aAAa,CAACN;AAC/B"}

View File

@@ -0,0 +1,12 @@
import { EVENTS } from '../constants';
export function dismissToast(toastId, toasterId = undefined, targetDocument) {
const event = new CustomEvent(EVENTS.dismiss, {
bubbles: false,
cancelable: false,
detail: {
toastId,
toasterId
}
});
targetDocument.dispatchEvent(event);
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/state/vanilla/dismissToast.ts"],"sourcesContent":["import { EVENTS } from '../constants';\nimport { DismissToastEventDetail, ToastId, ToasterId } from '../types';\n\nexport function dismissToast(\n toastId: ToastId,\n toasterId: ToasterId | undefined = undefined,\n targetDocument: Document,\n): void {\n const event = new CustomEvent<DismissToastEventDetail>(EVENTS.dismiss, {\n bubbles: false,\n cancelable: false,\n detail: { toastId, toasterId },\n });\n targetDocument.dispatchEvent(event);\n}\n"],"names":["EVENTS","dismissToast","toastId","toasterId","undefined","targetDocument","event","CustomEvent","dismiss","bubbles","cancelable","detail","dispatchEvent"],"mappings":"AAAA,SAASA,MAAM,QAAQ,eAAe;AAGtC,OAAO,SAASC,aACdC,OAAgB,EAChBC,YAAmCC,SAAS,EAC5CC,cAAwB;IAExB,MAAMC,QAAQ,IAAIC,YAAqCP,OAAOQ,OAAO,EAAE;QACrEC,SAAS;QACTC,YAAY;QACZC,QAAQ;YAAET;YAASC;QAAU;IAC/B;IACAE,eAAeO,aAAa,CAACN;AAC/B"}

View File

@@ -0,0 +1,16 @@
import { EVENTS } from '../constants';
let counter = 0;
export function dispatchToast(content, options = {}, targetDocument) {
var _options_toastId;
const detail = {
...options,
content,
toastId: (_options_toastId = options.toastId) !== null && _options_toastId !== void 0 ? _options_toastId : (counter++).toString()
};
const event = new CustomEvent(EVENTS.show, {
bubbles: false,
cancelable: false,
detail
});
targetDocument.dispatchEvent(event);
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/state/vanilla/dispatchToast.ts"],"sourcesContent":["import { ShowToastEventDetail, ToastOptions } from '../types';\nimport { EVENTS } from '../constants';\n\nlet counter = 0;\n\nexport function dispatchToast(content: unknown, options: Partial<ToastOptions> = {}, targetDocument: Document): void {\n const detail: ShowToastEventDetail = {\n ...options,\n content,\n toastId: options.toastId ?? (counter++).toString(),\n };\n const event = new CustomEvent<ShowToastEventDetail>(EVENTS.show, {\n bubbles: false,\n cancelable: false,\n detail,\n });\n targetDocument.dispatchEvent(event);\n}\n"],"names":["EVENTS","counter","dispatchToast","content","options","targetDocument","detail","toastId","toString","event","CustomEvent","show","bubbles","cancelable","dispatchEvent"],"mappings":"AACA,SAASA,MAAM,QAAQ,eAAe;AAEtC,IAAIC,UAAU;AAEd,OAAO,SAASC,cAAcC,OAAgB,EAAEC,UAAiC,CAAC,CAAC,EAAEC,cAAwB;QAIhGD;IAHX,MAAME,SAA+B;QACnC,GAAGF,OAAO;QACVD;QACAI,SAASH,CAAAA,mBAAAA,QAAQG,OAAO,cAAfH,8BAAAA,mBAAmB,AAACH,CAAAA,SAAQ,EAAGO,QAAQ;IAClD;IACA,MAAMC,QAAQ,IAAIC,YAAkCV,OAAOW,IAAI,EAAE;QAC/DC,SAAS;QACTC,YAAY;QACZP;IACF;IACAD,eAAeS,aAAa,CAACL;AAC/B"}

View File

@@ -0,0 +1,53 @@
export const getPositionStyles = (position, dir, offset)=>{
const positionStyles = {};
var _offset_position;
const offsetStyles = offset ? isShorthandOffset(offset) ? offset : (_offset_position = offset[position]) !== null && _offset_position !== void 0 ? _offset_position : {} : {};
const centered = position === 'top' || position === 'bottom';
const { horizontal = centered ? 0 : 20, vertical = 16 } = offsetStyles;
const start = dir === 'ltr' ? 'left' : 'right';
const end = dir === 'ltr' ? 'right' : 'left';
switch(position){
case 'top':
Object.assign(positionStyles, {
top: vertical,
left: `calc(50% + ${horizontal}px)`,
transform: 'translateX(-50%)'
});
break;
case 'bottom':
Object.assign(positionStyles, {
bottom: vertical,
left: `calc(50% + ${horizontal}px)`,
transform: 'translateX(-50%)'
});
break;
case 'top-start':
Object.assign(positionStyles, {
top: vertical,
[start]: horizontal
});
break;
case 'top-end':
Object.assign(positionStyles, {
top: vertical,
[end]: horizontal
});
break;
case 'bottom-start':
Object.assign(positionStyles, {
bottom: vertical,
[start]: horizontal
});
break;
case 'bottom-end':
Object.assign(positionStyles, {
bottom: vertical,
[end]: horizontal
});
break;
}
return positionStyles;
};
function isShorthandOffset(offset) {
return 'horizontal' in offset || 'vertical' in offset;
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/state/vanilla/getPositionStyles.ts"],"sourcesContent":["import { ToastOffsetObject, ToastOffset, ToastPosition } from '../types';\n\ninterface PositionStyles {\n top?: number;\n left?: number;\n right?: number;\n bottom?: number;\n}\n\nexport const getPositionStyles = (\n position: ToastPosition,\n dir: 'rtl' | 'ltr',\n offset?: ToastOffset,\n): PositionStyles => {\n const positionStyles: PositionStyles = {};\n\n const offsetStyles: ToastOffsetObject = offset ? (isShorthandOffset(offset) ? offset : offset[position] ?? {}) : {};\n\n const centered = position === 'top' || position === 'bottom';\n\n const { horizontal = centered ? 0 : 20, vertical = 16 } = offsetStyles;\n const start = dir === 'ltr' ? 'left' : 'right';\n const end = dir === 'ltr' ? 'right' : 'left';\n\n switch (position) {\n case 'top':\n Object.assign(positionStyles, {\n top: vertical,\n left: `calc(50% + ${horizontal}px)`,\n transform: 'translateX(-50%)',\n });\n break;\n\n case 'bottom':\n Object.assign(positionStyles, {\n bottom: vertical,\n left: `calc(50% + ${horizontal}px)`,\n transform: 'translateX(-50%)',\n });\n break;\n\n case 'top-start':\n Object.assign(positionStyles, {\n top: vertical,\n [start]: horizontal,\n });\n break;\n case 'top-end':\n Object.assign(positionStyles, {\n top: vertical,\n [end]: horizontal,\n });\n break;\n case 'bottom-start':\n Object.assign(positionStyles, {\n bottom: vertical,\n [start]: horizontal,\n });\n break;\n case 'bottom-end':\n Object.assign(positionStyles, {\n bottom: vertical,\n [end]: horizontal,\n });\n break;\n }\n\n return positionStyles;\n};\n\nfunction isShorthandOffset(offset: ToastOffset): offset is ToastOffsetObject {\n return 'horizontal' in offset || 'vertical' in offset;\n}\n"],"names":["getPositionStyles","position","dir","offset","positionStyles","offsetStyles","isShorthandOffset","centered","horizontal","vertical","start","end","Object","assign","top","left","transform","bottom"],"mappings":"AASA,OAAO,MAAMA,oBAAoB,CAC/BC,UACAC,KACAC;IAEA,MAAMC,iBAAiC,CAAC;QAE+CD;IAAvF,MAAME,eAAkCF,SAAUG,kBAAkBH,UAAUA,SAASA,CAAAA,mBAAAA,MAAM,CAACF,SAAS,cAAhBE,8BAAAA,mBAAoB,CAAC,IAAK,CAAC;IAElH,MAAMI,WAAWN,aAAa,SAASA,aAAa;IAEpD,MAAM,EAAEO,aAAaD,WAAW,IAAI,EAAE,EAAEE,WAAW,EAAE,EAAE,GAAGJ;IAC1D,MAAMK,QAAQR,QAAQ,QAAQ,SAAS;IACvC,MAAMS,MAAMT,QAAQ,QAAQ,UAAU;IAEtC,OAAQD;QACN,KAAK;YACHW,OAAOC,MAAM,CAACT,gBAAgB;gBAC5BU,KAAKL;gBACLM,MAAM,CAAC,WAAW,EAAEP,WAAW,GAAG,CAAC;gBACnCQ,WAAW;YACb;YACA;QAEF,KAAK;YACHJ,OAAOC,MAAM,CAACT,gBAAgB;gBAC5Ba,QAAQR;gBACRM,MAAM,CAAC,WAAW,EAAEP,WAAW,GAAG,CAAC;gBACnCQ,WAAW;YACb;YACA;QAEF,KAAK;YACHJ,OAAOC,MAAM,CAACT,gBAAgB;gBAC5BU,KAAKL;gBACL,CAACC,MAAM,EAAEF;YACX;YACA;QACF,KAAK;YACHI,OAAOC,MAAM,CAACT,gBAAgB;gBAC5BU,KAAKL;gBACL,CAACE,IAAI,EAAEH;YACT;YACA;QACF,KAAK;YACHI,OAAOC,MAAM,CAACT,gBAAgB;gBAC5Ba,QAAQR;gBACR,CAACC,MAAM,EAAEF;YACX;YACA;QACF,KAAK;YACHI,OAAOC,MAAM,CAACT,gBAAgB;gBAC5Ba,QAAQR;gBACR,CAACE,IAAI,EAAEH;YACT;YACA;IACJ;IAEA,OAAOJ;AACT,EAAE;AAEF,SAASE,kBAAkBH,MAAmB;IAC5C,OAAO,gBAAgBA,UAAU,cAAcA;AACjD"}

View File

@@ -0,0 +1,8 @@
export { dispatchToast } from './dispatchToast';
export { dismissToast } from './dismissToast';
export { dismissAllToasts } from './dismissAllToasts';
export { updateToast } from './updateToast';
export { pauseToast } from './pauseToast';
export { playToast } from './playToast';
export { createToaster } from './createToaster';
export { getPositionStyles } from './getPositionStyles';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/state/vanilla/index.ts"],"sourcesContent":["export { dispatchToast } from './dispatchToast';\nexport { dismissToast } from './dismissToast';\nexport { dismissAllToasts } from './dismissAllToasts';\nexport { updateToast } from './updateToast';\nexport { pauseToast } from './pauseToast';\nexport { playToast } from './playToast';\nexport { createToaster } from './createToaster';\nexport { getPositionStyles } from './getPositionStyles';\n"],"names":["dispatchToast","dismissToast","dismissAllToasts","updateToast","pauseToast","playToast","createToaster","getPositionStyles"],"mappings":"AAAA,SAASA,aAAa,QAAQ,kBAAkB;AAChD,SAASC,YAAY,QAAQ,iBAAiB;AAC9C,SAASC,gBAAgB,QAAQ,qBAAqB;AACtD,SAASC,WAAW,QAAQ,gBAAgB;AAC5C,SAASC,UAAU,QAAQ,eAAe;AAC1C,SAASC,SAAS,QAAQ,cAAc;AACxC,SAASC,aAAa,QAAQ,kBAAkB;AAChD,SAASC,iBAAiB,QAAQ,sBAAsB"}

View File

@@ -0,0 +1,12 @@
import { EVENTS } from '../constants';
export function pauseToast(toastId, toasterId = undefined, targetDocument) {
const event = new CustomEvent(EVENTS.pause, {
bubbles: false,
cancelable: false,
detail: {
toastId,
toasterId
}
});
targetDocument.dispatchEvent(event);
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/state/vanilla/pauseToast.ts"],"sourcesContent":["import { EVENTS } from '../constants';\nimport { PauseToastEventDetail, ToastId, ToasterId } from '../types';\n\nexport function pauseToast(\n toastId: ToastId,\n toasterId: ToasterId | undefined = undefined,\n targetDocument: Document,\n): void {\n const event = new CustomEvent<PauseToastEventDetail>(EVENTS.pause, {\n bubbles: false,\n cancelable: false,\n detail: { toastId, toasterId },\n });\n targetDocument.dispatchEvent(event);\n}\n"],"names":["EVENTS","pauseToast","toastId","toasterId","undefined","targetDocument","event","CustomEvent","pause","bubbles","cancelable","detail","dispatchEvent"],"mappings":"AAAA,SAASA,MAAM,QAAQ,eAAe;AAGtC,OAAO,SAASC,WACdC,OAAgB,EAChBC,YAAmCC,SAAS,EAC5CC,cAAwB;IAExB,MAAMC,QAAQ,IAAIC,YAAmCP,OAAOQ,KAAK,EAAE;QACjEC,SAAS;QACTC,YAAY;QACZC,QAAQ;YAAET;YAASC;QAAU;IAC/B;IACAE,eAAeO,aAAa,CAACN;AAC/B"}

View File

@@ -0,0 +1,12 @@
import { EVENTS } from '../constants';
export function playToast(toastId, toasterId = undefined, targetDocument) {
const event = new CustomEvent(EVENTS.play, {
bubbles: false,
cancelable: false,
detail: {
toastId,
toasterId
}
});
targetDocument.dispatchEvent(event);
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/state/vanilla/playToast.ts"],"sourcesContent":["import { EVENTS } from '../constants';\nimport { PlayToastEventDetail, ToastId, ToasterId } from '../types';\n\nexport function playToast(\n toastId: ToastId,\n toasterId: ToasterId | undefined = undefined,\n targetDocument: Document,\n): void {\n const event = new CustomEvent<PlayToastEventDetail>(EVENTS.play, {\n bubbles: false,\n cancelable: false,\n detail: { toastId, toasterId },\n });\n targetDocument.dispatchEvent(event);\n}\n"],"names":["EVENTS","playToast","toastId","toasterId","undefined","targetDocument","event","CustomEvent","play","bubbles","cancelable","detail","dispatchEvent"],"mappings":"AAAA,SAASA,MAAM,QAAQ,eAAe;AAGtC,OAAO,SAASC,UACdC,OAAgB,EAChBC,YAAmCC,SAAS,EAC5CC,cAAwB;IAExB,MAAMC,QAAQ,IAAIC,YAAkCP,OAAOQ,IAAI,EAAE;QAC/DC,SAAS;QACTC,YAAY;QACZC,QAAQ;YAAET;YAASC;QAAU;IAC/B;IACAE,eAAeO,aAAa,CAACN;AAC/B"}

View File

@@ -0,0 +1,9 @@
import { EVENTS } from '../constants';
export function updateToast(options, targetDocument) {
const event = new CustomEvent(EVENTS.update, {
bubbles: false,
cancelable: false,
detail: options
});
targetDocument.dispatchEvent(event);
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/state/vanilla/updateToast.ts"],"sourcesContent":["import { UpdateToastEventDetail } from '../types';\nimport { EVENTS } from '../constants';\n\nexport function updateToast(options: UpdateToastEventDetail, targetDocument: Document): void {\n const event = new CustomEvent<UpdateToastEventDetail>(EVENTS.update, {\n bubbles: false,\n cancelable: false,\n detail: options,\n });\n\n targetDocument.dispatchEvent(event);\n}\n"],"names":["EVENTS","updateToast","options","targetDocument","event","CustomEvent","update","bubbles","cancelable","detail","dispatchEvent"],"mappings":"AACA,SAASA,MAAM,QAAQ,eAAe;AAEtC,OAAO,SAASC,YAAYC,OAA+B,EAAEC,cAAwB;IACnF,MAAMC,QAAQ,IAAIC,YAAoCL,OAAOM,MAAM,EAAE;QACnEC,SAAS;QACTC,YAAY;QACZC,QAAQP;IACV;IAEAC,eAAeO,aAAa,CAACN;AAC/B"}