fluentui-extended 2026.8.54 → 2026.8.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/README.md +50 -0
- package/dist/index.d.mts +36 -1
- package/dist/index.d.ts +36 -1
- package/dist/index.js +575 -415
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +575 -416
- package/dist/index.mjs.map +1 -1
- package/package.json +89 -89
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
- ✨ **[ParentPortal](README.md#parentportal)** — new component that renders Fluent UI content in the
|
|
8
|
+
parent document, escaping iframe boundaries with full Griffel styling and theme token sync. Designed
|
|
9
|
+
for Dynamics 365 web resources where dialogs must float above the D365 page without causing iframe
|
|
10
|
+
resize or scrollbars.
|
|
7
11
|
- ✨ **[CommandBar tooltips](README.md#tooltips)** — commands take Fluent tooltips in three forms:
|
|
8
12
|
`title` for a plain line, `title` + `description` for the Fluent 2 rich tooltip, and `tooltip` for
|
|
9
13
|
a fully custom element. `description` accepts markup, so it can carry its own emphasis.
|
package/README.md
CHANGED
|
@@ -123,6 +123,56 @@ selections render as the usual Lookup badges and multi-select comes for free.
|
|
|
123
123
|
|
|
124
124
|

|
|
125
125
|
|
|
126
|
+
### ParentPortal
|
|
127
|
+
|
|
128
|
+
Renders Fluent UI content in the **parent document**, escaping an iframe boundary with full styling. Designed for Dynamics 365 web resources where dialogs must float above the entire D365 page rather than being trapped inside the iframe.
|
|
129
|
+
|
|
130
|
+
**Problem:** Fluent UI v9 has no built-in cross-frame portal. `mountNode` targets a DOM node but Griffel injects styles into the iframe's `<head>`. D365's auto-height mechanism detects `scrollHeight` changes and adds scrollbars.
|
|
131
|
+
|
|
132
|
+
**Solution:** `ParentPortal` creates a container in `window.parent.document`, syncs all Griffel CSSOM rules to the parent, and copies Fluent theme tokens — so components render fully styled in the parent page.
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
import { Dialog, DialogSurface, DialogBody, DialogTitle, DialogContent } from '@fluentui/react-components';
|
|
136
|
+
import { ParentPortal } from 'fluentui-extended';
|
|
137
|
+
|
|
138
|
+
function MyDialog({ open, onClose }) {
|
|
139
|
+
return (
|
|
140
|
+
<Dialog open={open} onOpenChange={(_, d) => !d.open && onClose()}>
|
|
141
|
+
<ParentPortal>
|
|
142
|
+
<DialogSurface backdrop={{ appearance: 'dimmed' }}>
|
|
143
|
+
<DialogBody>
|
|
144
|
+
<DialogTitle>Escaped the iframe</DialogTitle>
|
|
145
|
+
<DialogContent>
|
|
146
|
+
This dialog renders in the parent D365 document with full
|
|
147
|
+
Fluent styling — no scrollbars, no forced iframe resize.
|
|
148
|
+
</DialogContent>
|
|
149
|
+
</DialogBody>
|
|
150
|
+
</DialogSurface>
|
|
151
|
+
</ParentPortal>
|
|
152
|
+
</Dialog>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
| Prop | Type | Default | Description |
|
|
158
|
+
|------|------|---------|-------------|
|
|
159
|
+
| `children` | `ReactNode` | — | Content to render in the parent document |
|
|
160
|
+
| `containerId` | `string` | `'fluentui-extended-parent-portal-root'` | ID for the container element in the parent |
|
|
161
|
+
| `syncStyles` | `boolean` | `true` | Sync Griffel stylesheets to the parent |
|
|
162
|
+
| `syncTokens` | `boolean` | `true` | Copy Fluent CSS custom properties (theme tokens) |
|
|
163
|
+
| `syncInterval` | `number` | `300` | Interval (ms) for CSSOM rule re-sync |
|
|
164
|
+
| `containerStyles` | `string` | *(built-in)* | Custom CSS for the parent container |
|
|
165
|
+
|
|
166
|
+
**How it works:**
|
|
167
|
+
1. Creates a `position: fixed` container in `window.parent.document.body`
|
|
168
|
+
2. Uses `React.createPortal` to render a `FluentProvider` + children into that container
|
|
169
|
+
3. Serializes all `CSSStyleSheet.cssRules` from iframe `<style>` elements (Griffel uses `insertRule()`, so `textContent` is empty) and mirrors them to the parent `<head>`
|
|
170
|
+
4. Copies CSS custom properties (`--colorNeutralBackground1`, etc.) from the iframe's `FluentProvider` to the parent container
|
|
171
|
+
5. A `MutationObserver` + interval catches lazily-inserted Griffel rules
|
|
172
|
+
6. Falls back to in-place rendering if not inside an iframe
|
|
173
|
+
|
|
174
|
+
> **Requires same-origin:** The iframe and parent must be on the same domain (standard for D365 web resources).
|
|
175
|
+
|
|
126
176
|
## Quick Start
|
|
127
177
|
|
|
128
178
|
```tsx
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import React__default, { ReactNode } from 'react';
|
|
2
3
|
import { InputProps, PresenceBadgeStatus } from '@fluentui/react-components';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -37,6 +38,34 @@ declare const toTextareaAppearance: (appearance?: FieldAppearance) => TextareaAp
|
|
|
37
38
|
*/
|
|
38
39
|
declare const toListboxAppearance: (appearance?: FieldAppearance) => ListboxAppearance;
|
|
39
40
|
|
|
41
|
+
interface ParentPortalProps {
|
|
42
|
+
children: ReactNode;
|
|
43
|
+
containerId?: string;
|
|
44
|
+
syncStyles?: boolean;
|
|
45
|
+
syncTokens?: boolean;
|
|
46
|
+
syncInterval?: number;
|
|
47
|
+
containerStyles?: string;
|
|
48
|
+
}
|
|
49
|
+
interface UseParentPortalMountOptions {
|
|
50
|
+
containerId?: string;
|
|
51
|
+
syncStyles?: boolean;
|
|
52
|
+
syncTokens?: boolean;
|
|
53
|
+
syncInterval?: number;
|
|
54
|
+
containerStyles?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Hook that returns the parent-document mount node for use with Fluent's
|
|
59
|
+
* `mountNode` prop (e.g. on DialogSurface). Also handles style sync.
|
|
60
|
+
*/
|
|
61
|
+
declare function useParentPortalMount(options?: UseParentPortalMountOptions): HTMLElement | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Renders children into the parent document via createPortal.
|
|
64
|
+
* Use for non-portal Fluent components. For DialogSurface, use
|
|
65
|
+
* useParentPortalMount() with the mountNode prop instead.
|
|
66
|
+
*/
|
|
67
|
+
declare function ParentPortal({ children, containerId, syncStyles, syncTokens, syncInterval, containerStyles, }: ParentPortalProps): React__default.JSX.Element;
|
|
68
|
+
|
|
40
69
|
/** Size variants matching FluentUI Input component */
|
|
41
70
|
type LookupSize = 'small' | 'medium';
|
|
42
71
|
interface LookupOptionDetail {
|
|
@@ -207,6 +236,12 @@ interface LookupProps extends Omit<InputProps, 'onChange' | 'value'> {
|
|
|
207
236
|
hoverCardDelayMs?: number;
|
|
208
237
|
/** Content rendered at the bottom of the card, e.g. an "Open record" link */
|
|
209
238
|
hoverCardActions?: React.ReactNode;
|
|
239
|
+
/**
|
|
240
|
+
* Mount node for the dropdown Portal. Use when the Lookup is inside a
|
|
241
|
+
* dialog rendered in a parent document (via mountNode) so the listbox
|
|
242
|
+
* appears in the same document as the dialog.
|
|
243
|
+
*/
|
|
244
|
+
mountNode?: HTMLElement;
|
|
210
245
|
}
|
|
211
246
|
|
|
212
247
|
declare const Lookup: React.FC<LookupProps>;
|
|
@@ -1468,4 +1503,4 @@ declare const validateQueryBuilderState: (state: QueryBuilderState, fields: Quer
|
|
|
1468
1503
|
|
|
1469
1504
|
declare const QueryBuilder: React.FC<QueryBuilderProps>;
|
|
1470
1505
|
|
|
1471
|
-
export { type AttributeMetadata, CommandBar, type CommandBarItem, type CommandBarItemAppearance, type CommandBarProps, DEFAULT_FIELD_APPEARANCE, type DateTimeBehavior, DateTimeField, type DateTimeFieldProps, DateTimeRangeField, type DateTimeRangeFieldChange, type DateTimeRangeFieldProps, type DateTimeRangeValue, type EntityDefinition, EntityGrid, type EntityGridColumn, type EntityGridProps, type EntityGridSort, type EntityGridSortDirection, type FieldAppearance, type ListboxAppearance, Lookup, type LookupOption, type LookupOptionDetail, type LookupProps, OptionSetField, type OptionSetFieldProps, type OptionSetOption, type OptionSetValue, OwnerLookup, type OwnerLookupProps, type OwnerRecord, type OwnerType, QueryBuilder, type QueryBuilderApplyResult, type QueryBuilderCondition, type QueryBuilderDataType, type QueryBuilderField, type QueryBuilderGroup, type QueryBuilderOperator, type QueryBuilderOption, type QueryBuilderProps, type QueryBuilderQueryOptions, type QueryBuilderRelatedEntity, type QueryBuilderState, RecordHoverCard, type RecordHoverCardDetail, type RecordHoverCardProps, type RecordHoverCardRecord, type SearchOwnersOptions, type SearchSystemUsersOptions, SystemUserCard, type SystemUserCardProps, type SystemUserContactItem, SystemUserPersona, type SystemUserPersonaProps, type SystemUserPersonaSize, type SystemUserRecord, type TextareaAppearance, type WebApiCollection, WebApiError, clearMetadataCache, formatMultiSelectValue, formatStoredValue, getAttributeOptions, getEntityAttributes, getEntityDefinition, getEntityOptionSets, getOwner, getSystemUser, getWebApiBaseUrl, initialsOf, ownerFromUser, parseFetchXmlToState, parseSelectedValues, parseStoredValue, searchOwners, searchSystemUsers, searchTeams, serializeQueryBuilderState, setWebApiBaseUrl, setWebApiFetch, systemUserImageUrl, toListboxAppearance, toTextareaAppearance, validateFetchXmlSyntax, validateQueryBuilderState, webApiGet };
|
|
1506
|
+
export { type AttributeMetadata, CommandBar, type CommandBarItem, type CommandBarItemAppearance, type CommandBarProps, DEFAULT_FIELD_APPEARANCE, type DateTimeBehavior, DateTimeField, type DateTimeFieldProps, DateTimeRangeField, type DateTimeRangeFieldChange, type DateTimeRangeFieldProps, type DateTimeRangeValue, type EntityDefinition, EntityGrid, type EntityGridColumn, type EntityGridProps, type EntityGridSort, type EntityGridSortDirection, type FieldAppearance, type ListboxAppearance, Lookup, type LookupOption, type LookupOptionDetail, type LookupProps, OptionSetField, type OptionSetFieldProps, type OptionSetOption, type OptionSetValue, OwnerLookup, type OwnerLookupProps, type OwnerRecord, type OwnerType, ParentPortal, type ParentPortalProps, QueryBuilder, type QueryBuilderApplyResult, type QueryBuilderCondition, type QueryBuilderDataType, type QueryBuilderField, type QueryBuilderGroup, type QueryBuilderOperator, type QueryBuilderOption, type QueryBuilderProps, type QueryBuilderQueryOptions, type QueryBuilderRelatedEntity, type QueryBuilderState, RecordHoverCard, type RecordHoverCardDetail, type RecordHoverCardProps, type RecordHoverCardRecord, type SearchOwnersOptions, type SearchSystemUsersOptions, SystemUserCard, type SystemUserCardProps, type SystemUserContactItem, SystemUserPersona, type SystemUserPersonaProps, type SystemUserPersonaSize, type SystemUserRecord, type TextareaAppearance, type UseParentPortalMountOptions, type WebApiCollection, WebApiError, clearMetadataCache, formatMultiSelectValue, formatStoredValue, getAttributeOptions, getEntityAttributes, getEntityDefinition, getEntityOptionSets, getOwner, getSystemUser, getWebApiBaseUrl, initialsOf, ownerFromUser, parseFetchXmlToState, parseSelectedValues, parseStoredValue, searchOwners, searchSystemUsers, searchTeams, serializeQueryBuilderState, setWebApiBaseUrl, setWebApiFetch, systemUserImageUrl, toListboxAppearance, toTextareaAppearance, useParentPortalMount, validateFetchXmlSyntax, validateQueryBuilderState, webApiGet };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import React__default, { ReactNode } from 'react';
|
|
2
3
|
import { InputProps, PresenceBadgeStatus } from '@fluentui/react-components';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -37,6 +38,34 @@ declare const toTextareaAppearance: (appearance?: FieldAppearance) => TextareaAp
|
|
|
37
38
|
*/
|
|
38
39
|
declare const toListboxAppearance: (appearance?: FieldAppearance) => ListboxAppearance;
|
|
39
40
|
|
|
41
|
+
interface ParentPortalProps {
|
|
42
|
+
children: ReactNode;
|
|
43
|
+
containerId?: string;
|
|
44
|
+
syncStyles?: boolean;
|
|
45
|
+
syncTokens?: boolean;
|
|
46
|
+
syncInterval?: number;
|
|
47
|
+
containerStyles?: string;
|
|
48
|
+
}
|
|
49
|
+
interface UseParentPortalMountOptions {
|
|
50
|
+
containerId?: string;
|
|
51
|
+
syncStyles?: boolean;
|
|
52
|
+
syncTokens?: boolean;
|
|
53
|
+
syncInterval?: number;
|
|
54
|
+
containerStyles?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Hook that returns the parent-document mount node for use with Fluent's
|
|
59
|
+
* `mountNode` prop (e.g. on DialogSurface). Also handles style sync.
|
|
60
|
+
*/
|
|
61
|
+
declare function useParentPortalMount(options?: UseParentPortalMountOptions): HTMLElement | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Renders children into the parent document via createPortal.
|
|
64
|
+
* Use for non-portal Fluent components. For DialogSurface, use
|
|
65
|
+
* useParentPortalMount() with the mountNode prop instead.
|
|
66
|
+
*/
|
|
67
|
+
declare function ParentPortal({ children, containerId, syncStyles, syncTokens, syncInterval, containerStyles, }: ParentPortalProps): React__default.JSX.Element;
|
|
68
|
+
|
|
40
69
|
/** Size variants matching FluentUI Input component */
|
|
41
70
|
type LookupSize = 'small' | 'medium';
|
|
42
71
|
interface LookupOptionDetail {
|
|
@@ -207,6 +236,12 @@ interface LookupProps extends Omit<InputProps, 'onChange' | 'value'> {
|
|
|
207
236
|
hoverCardDelayMs?: number;
|
|
208
237
|
/** Content rendered at the bottom of the card, e.g. an "Open record" link */
|
|
209
238
|
hoverCardActions?: React.ReactNode;
|
|
239
|
+
/**
|
|
240
|
+
* Mount node for the dropdown Portal. Use when the Lookup is inside a
|
|
241
|
+
* dialog rendered in a parent document (via mountNode) so the listbox
|
|
242
|
+
* appears in the same document as the dialog.
|
|
243
|
+
*/
|
|
244
|
+
mountNode?: HTMLElement;
|
|
210
245
|
}
|
|
211
246
|
|
|
212
247
|
declare const Lookup: React.FC<LookupProps>;
|
|
@@ -1468,4 +1503,4 @@ declare const validateQueryBuilderState: (state: QueryBuilderState, fields: Quer
|
|
|
1468
1503
|
|
|
1469
1504
|
declare const QueryBuilder: React.FC<QueryBuilderProps>;
|
|
1470
1505
|
|
|
1471
|
-
export { type AttributeMetadata, CommandBar, type CommandBarItem, type CommandBarItemAppearance, type CommandBarProps, DEFAULT_FIELD_APPEARANCE, type DateTimeBehavior, DateTimeField, type DateTimeFieldProps, DateTimeRangeField, type DateTimeRangeFieldChange, type DateTimeRangeFieldProps, type DateTimeRangeValue, type EntityDefinition, EntityGrid, type EntityGridColumn, type EntityGridProps, type EntityGridSort, type EntityGridSortDirection, type FieldAppearance, type ListboxAppearance, Lookup, type LookupOption, type LookupOptionDetail, type LookupProps, OptionSetField, type OptionSetFieldProps, type OptionSetOption, type OptionSetValue, OwnerLookup, type OwnerLookupProps, type OwnerRecord, type OwnerType, QueryBuilder, type QueryBuilderApplyResult, type QueryBuilderCondition, type QueryBuilderDataType, type QueryBuilderField, type QueryBuilderGroup, type QueryBuilderOperator, type QueryBuilderOption, type QueryBuilderProps, type QueryBuilderQueryOptions, type QueryBuilderRelatedEntity, type QueryBuilderState, RecordHoverCard, type RecordHoverCardDetail, type RecordHoverCardProps, type RecordHoverCardRecord, type SearchOwnersOptions, type SearchSystemUsersOptions, SystemUserCard, type SystemUserCardProps, type SystemUserContactItem, SystemUserPersona, type SystemUserPersonaProps, type SystemUserPersonaSize, type SystemUserRecord, type TextareaAppearance, type WebApiCollection, WebApiError, clearMetadataCache, formatMultiSelectValue, formatStoredValue, getAttributeOptions, getEntityAttributes, getEntityDefinition, getEntityOptionSets, getOwner, getSystemUser, getWebApiBaseUrl, initialsOf, ownerFromUser, parseFetchXmlToState, parseSelectedValues, parseStoredValue, searchOwners, searchSystemUsers, searchTeams, serializeQueryBuilderState, setWebApiBaseUrl, setWebApiFetch, systemUserImageUrl, toListboxAppearance, toTextareaAppearance, validateFetchXmlSyntax, validateQueryBuilderState, webApiGet };
|
|
1506
|
+
export { type AttributeMetadata, CommandBar, type CommandBarItem, type CommandBarItemAppearance, type CommandBarProps, DEFAULT_FIELD_APPEARANCE, type DateTimeBehavior, DateTimeField, type DateTimeFieldProps, DateTimeRangeField, type DateTimeRangeFieldChange, type DateTimeRangeFieldProps, type DateTimeRangeValue, type EntityDefinition, EntityGrid, type EntityGridColumn, type EntityGridProps, type EntityGridSort, type EntityGridSortDirection, type FieldAppearance, type ListboxAppearance, Lookup, type LookupOption, type LookupOptionDetail, type LookupProps, OptionSetField, type OptionSetFieldProps, type OptionSetOption, type OptionSetValue, OwnerLookup, type OwnerLookupProps, type OwnerRecord, type OwnerType, ParentPortal, type ParentPortalProps, QueryBuilder, type QueryBuilderApplyResult, type QueryBuilderCondition, type QueryBuilderDataType, type QueryBuilderField, type QueryBuilderGroup, type QueryBuilderOperator, type QueryBuilderOption, type QueryBuilderProps, type QueryBuilderQueryOptions, type QueryBuilderRelatedEntity, type QueryBuilderState, RecordHoverCard, type RecordHoverCardDetail, type RecordHoverCardProps, type RecordHoverCardRecord, type SearchOwnersOptions, type SearchSystemUsersOptions, SystemUserCard, type SystemUserCardProps, type SystemUserContactItem, SystemUserPersona, type SystemUserPersonaProps, type SystemUserPersonaSize, type SystemUserRecord, type TextareaAppearance, type UseParentPortalMountOptions, type WebApiCollection, WebApiError, clearMetadataCache, formatMultiSelectValue, formatStoredValue, getAttributeOptions, getEntityAttributes, getEntityDefinition, getEntityOptionSets, getOwner, getSystemUser, getWebApiBaseUrl, initialsOf, ownerFromUser, parseFetchXmlToState, parseSelectedValues, parseStoredValue, searchOwners, searchSystemUsers, searchTeams, serializeQueryBuilderState, setWebApiBaseUrl, setWebApiFetch, systemUserImageUrl, toListboxAppearance, toTextareaAppearance, useParentPortalMount, validateFetchXmlSyntax, validateQueryBuilderState, webApiGet };
|