@spfx-fast/sharepoint-ui 0.0.0-stage → 0.4.0
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/AGENTS.md +211 -0
- package/LICENSE +21 -0
- package/README.md +897 -2
- package/components.json +5810 -0
- package/dist/appearance.d.ts +6 -0
- package/dist/appearance.js +217 -0
- package/dist/elements/accordion.d.ts +9 -0
- package/dist/elements/accordion.js +338 -0
- package/dist/elements/alert.d.ts +2 -0
- package/dist/elements/alert.js +62 -0
- package/dist/elements/avatar-group-primitives.d.ts +3 -0
- package/dist/elements/avatar-group-primitives.js +189 -0
- package/dist/elements/avatar-group.d.ts +2 -0
- package/dist/elements/avatar-group.js +110 -0
- package/dist/elements/avatar.d.ts +4 -0
- package/dist/elements/avatar.js +251 -0
- package/dist/elements/badge.d.ts +8 -0
- package/dist/elements/badge.js +182 -0
- package/dist/elements/breadcrumb.d.ts +4 -0
- package/dist/elements/breadcrumb.js +233 -0
- package/dist/elements/button-group.d.ts +1 -0
- package/dist/elements/button-group.js +20 -0
- package/dist/elements/button-variants.d.ts +6 -0
- package/dist/elements/button-variants.js +339 -0
- package/dist/elements/button.d.ts +5 -0
- package/dist/elements/button.js +233 -0
- package/dist/elements/card-primitives.d.ts +3 -0
- package/dist/elements/card-primitives.js +83 -0
- package/dist/elements/card.d.ts +5 -0
- package/dist/elements/card.js +213 -0
- package/dist/elements/carousel.d.ts +92 -0
- package/dist/elements/carousel.js +1112 -0
- package/dist/elements/color-picker.d.ts +24 -0
- package/dist/elements/color-picker.js +1004 -0
- package/dist/elements/combobox.d.ts +1 -0
- package/dist/elements/combobox.js +1012 -0
- package/dist/elements/data-grid-model.d.ts +117 -0
- package/dist/elements/data-grid-model.js +294 -0
- package/dist/elements/data-grid.d.ts +29 -0
- package/dist/elements/data-grid.js +1567 -0
- package/dist/elements/date-picker.d.ts +1 -0
- package/dist/elements/date-picker.js +486 -0
- package/dist/elements/dialog.d.ts +23 -0
- package/dist/elements/dialog.js +409 -0
- package/dist/elements/divider.d.ts +2 -0
- package/dist/elements/divider.js +66 -0
- package/dist/elements/drawer.d.ts +3 -0
- package/dist/elements/drawer.js +308 -0
- package/dist/elements/field-composition.d.ts +26 -0
- package/dist/elements/field-composition.js +133 -0
- package/dist/elements/field.d.ts +1 -0
- package/dist/elements/field.js +67 -0
- package/dist/elements/file-upload.d.ts +6 -0
- package/dist/elements/file-upload.js +211 -0
- package/dist/elements/floating-position.d.ts +26 -0
- package/dist/elements/floating-position.js +39 -0
- package/dist/elements/image.d.ts +28 -0
- package/dist/elements/image.js +38 -0
- package/dist/elements/info.d.ts +9 -0
- package/dist/elements/info.js +102 -0
- package/dist/elements/input.d.ts +5 -0
- package/dist/elements/input.js +255 -0
- package/dist/elements/label.d.ts +15 -0
- package/dist/elements/label.js +56 -0
- package/dist/elements/link.d.ts +1 -0
- package/dist/elements/link.js +92 -0
- package/dist/elements/list.d.ts +19 -0
- package/dist/elements/list.js +297 -0
- package/dist/elements/menu.d.ts +33 -0
- package/dist/elements/menu.js +1103 -0
- package/dist/elements/message-bar.d.ts +10 -0
- package/dist/elements/message-bar.js +299 -0
- package/dist/elements/nav.d.ts +32 -0
- package/dist/elements/nav.js +791 -0
- package/dist/elements/overflow.d.ts +9 -0
- package/dist/elements/overflow.js +218 -0
- package/dist/elements/persona.d.ts +3 -0
- package/dist/elements/persona.js +124 -0
- package/dist/elements/popover.d.ts +77 -0
- package/dist/elements/popover.js +840 -0
- package/dist/elements/progress-bar.d.ts +4 -0
- package/dist/elements/progress-bar.js +82 -0
- package/dist/elements/radio-group.d.ts +1 -0
- package/dist/elements/radio-group.js +303 -0
- package/dist/elements/rating-display.d.ts +2 -0
- package/dist/elements/rating-display.js +125 -0
- package/dist/elements/rating.d.ts +2 -0
- package/dist/elements/rating.js +206 -0
- package/dist/elements/rich-text-editor.d.ts +18 -0
- package/dist/elements/rich-text-editor.js +508 -0
- package/dist/elements/search.d.ts +3 -0
- package/dist/elements/search.js +207 -0
- package/dist/elements/select.d.ts +6 -0
- package/dist/elements/select.js +291 -0
- package/dist/elements/shared.d.ts +19 -0
- package/dist/elements/shared.js +396 -0
- package/dist/elements/skeleton.d.ts +6 -0
- package/dist/elements/skeleton.js +91 -0
- package/dist/elements/slider.d.ts +1 -0
- package/dist/elements/slider.js +248 -0
- package/dist/elements/spin-button.d.ts +7 -0
- package/dist/elements/spin-button.js +499 -0
- package/dist/elements/spinner.d.ts +4 -0
- package/dist/elements/spinner.js +124 -0
- package/dist/elements/swatch-picker.d.ts +5 -0
- package/dist/elements/swatch-picker.js +363 -0
- package/dist/elements/table.d.ts +21 -0
- package/dist/elements/table.js +261 -0
- package/dist/elements/tabs.d.ts +1 -0
- package/dist/elements/tabs.js +276 -0
- package/dist/elements/tag-picker.d.ts +29 -0
- package/dist/elements/tag-picker.js +697 -0
- package/dist/elements/tags.d.ts +21 -0
- package/dist/elements/tags.js +421 -0
- package/dist/elements/teaching-popover.d.ts +32 -0
- package/dist/elements/teaching-popover.js +412 -0
- package/dist/elements/text.d.ts +5 -0
- package/dist/elements/text.js +69 -0
- package/dist/elements/textarea.d.ts +1 -0
- package/dist/elements/textarea.js +182 -0
- package/dist/elements/toast.d.ts +25 -0
- package/dist/elements/toast.js +337 -0
- package/dist/elements/toaster.d.ts +6 -0
- package/dist/elements/toaster.js +356 -0
- package/dist/elements/toggle.d.ts +2 -0
- package/dist/elements/toggle.js +246 -0
- package/dist/elements/toolbar.d.ts +12 -0
- package/dist/elements/toolbar.js +381 -0
- package/dist/elements/tooltip.d.ts +76 -0
- package/dist/elements/tooltip.js +510 -0
- package/dist/elements/tree-model.d.ts +19 -0
- package/dist/elements/tree-model.js +34 -0
- package/dist/elements/tree.d.ts +5 -0
- package/dist/elements/tree.js +273 -0
- package/dist/elements/view-card.d.ts +2 -0
- package/dist/elements/view-card.js +78 -0
- package/dist/elements/virtual-list.d.ts +41 -0
- package/dist/elements/virtual-list.js +369 -0
- package/dist/elements.d.ts +72 -0
- package/dist/elements.js +207 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.js +66 -0
- package/dist/react-theme-styles.d.ts +2 -0
- package/dist/react-theme-styles.js +75 -0
- package/dist/react.d.ts +4540 -0
- package/dist/react.js +6799 -0
- package/dist/theme.d.ts +169 -0
- package/dist/theme.js +167 -0
- package/dist/virtualizer-hooks.d.ts +80 -0
- package/dist/virtualizer-hooks.js +253 -0
- package/package.json +87 -4
- package/scripts/generate-token-index.mjs +43 -0
- package/scripts/sync-component-catalog-signatures.mjs +55 -0
- package/scripts/validate-component-catalog.mjs +44 -0
- package/skills/sharepoint-ui/SKILL.md +12 -0
- package/skills/sharepoint-ui/references/choosing-components.md +20 -0
- package/skills/sharepoint-ui/references/sharepoint-patterns.md +17 -0
- package/tokens.json +3777 -0
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { type SharePointUIAppearance, type SharePointUIBaseAppearance, type SharePointUIDensity, type SharePointUIStyleTokens } from "./appearance.js";
|
|
2
|
+
/** SPFx theme data is copied through without a lossy, hand-maintained token allowlist. */
|
|
3
|
+
export type SharePointTheme = {
|
|
4
|
+
palette?: Record<string, string | undefined>;
|
|
5
|
+
semanticColors?: Record<string, string | undefined>;
|
|
6
|
+
/** Raw Fluent v8 theme tokens exposed as `--spui-effects-*`, `--spui-spacing-*`, and `--spui-fonts-*-*` variables. */
|
|
7
|
+
effects?: Record<string, string | undefined>;
|
|
8
|
+
spacing?: Record<string, string | undefined>;
|
|
9
|
+
fonts?: Record<string, Record<string, string | number | undefined> | undefined>;
|
|
10
|
+
defaultFontStyle?: Record<string, string | number | undefined>;
|
|
11
|
+
isInverted?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type FluentThemeTokens = Record<string, string | number | undefined>;
|
|
14
|
+
/** Semantic theme values are translated to the library's shared design tokens. */
|
|
15
|
+
export type SharePointUIDesignTheme = {
|
|
16
|
+
/** Raw named SharePoint palette values, exposed as `--spui-palette-*` CSS variables. `themePrimary` also seeds the accent when no explicit accent is set. */
|
|
17
|
+
palette?: Record<string, string>;
|
|
18
|
+
/** Any Fluent v9 theme values, exposed under their native CSS variable names and composable with the other design-pack groups. */
|
|
19
|
+
fluentTokens?: FluentThemeTokens;
|
|
20
|
+
/** Brand input for an automatically tinted accent scale. Hex values also get an AA-aware on-accent foreground; other CSS colors can set colors.accentForeground explicitly. */
|
|
21
|
+
brandColor?: string;
|
|
22
|
+
/** App- or component-specific CSS custom properties, merged after semantic roles and before direct provider tokens. */
|
|
23
|
+
customProperties?: Record<`--${string}`, string | number>;
|
|
24
|
+
colors?: {
|
|
25
|
+
accent?: string;
|
|
26
|
+
accentHover?: string;
|
|
27
|
+
accentPressed?: string;
|
|
28
|
+
accentSubtle?: string;
|
|
29
|
+
accentSubtleHover?: string;
|
|
30
|
+
accentSubtlePressed?: string;
|
|
31
|
+
accentForeground?: string;
|
|
32
|
+
secondaryHover?: string;
|
|
33
|
+
foreground?: string;
|
|
34
|
+
foregroundMuted?: string;
|
|
35
|
+
foregroundTertiary?: string;
|
|
36
|
+
foregroundSubtle?: string;
|
|
37
|
+
foregroundDisabled?: string;
|
|
38
|
+
canvas?: string;
|
|
39
|
+
surface?: string;
|
|
40
|
+
surfaceHover?: string;
|
|
41
|
+
surfaceAlt?: string;
|
|
42
|
+
surfaceSecondary?: string;
|
|
43
|
+
surfaceSubtle?: string;
|
|
44
|
+
surfaceRaised?: string;
|
|
45
|
+
surfaceSunken?: string;
|
|
46
|
+
border?: string;
|
|
47
|
+
borderSubtle?: string;
|
|
48
|
+
borderStrong?: string;
|
|
49
|
+
borderFocus?: string;
|
|
50
|
+
borderDisabled?: string;
|
|
51
|
+
selectedBackground?: string;
|
|
52
|
+
selectedBackgroundHover?: string;
|
|
53
|
+
selectedForeground?: string;
|
|
54
|
+
selectedBorder?: string;
|
|
55
|
+
link?: string;
|
|
56
|
+
linkVisited?: string;
|
|
57
|
+
overlay?: string;
|
|
58
|
+
info?: string;
|
|
59
|
+
infoSurface?: string;
|
|
60
|
+
success?: string;
|
|
61
|
+
successSurface?: string;
|
|
62
|
+
warning?: string;
|
|
63
|
+
warningSurface?: string;
|
|
64
|
+
danger?: string;
|
|
65
|
+
dangerSurface?: string;
|
|
66
|
+
focus?: string;
|
|
67
|
+
focusRing?: string;
|
|
68
|
+
};
|
|
69
|
+
typography?: {
|
|
70
|
+
fontFamily?: string;
|
|
71
|
+
fontFamilyMono?: string;
|
|
72
|
+
fontSize?: string;
|
|
73
|
+
fontSizeSmall?: string;
|
|
74
|
+
fontSizeLarge?: string;
|
|
75
|
+
fontSizeHeading?: string;
|
|
76
|
+
fontWeight?: string | number;
|
|
77
|
+
fontWeightStrong?: string | number;
|
|
78
|
+
lineHeight?: string;
|
|
79
|
+
lineHeightHeading?: string;
|
|
80
|
+
/** Fluent-compatible type ramp; values flow to the same CSS variables used by the component styles. */
|
|
81
|
+
fontSize100?: string;
|
|
82
|
+
fontSize200?: string;
|
|
83
|
+
fontSize300?: string;
|
|
84
|
+
fontSize400?: string;
|
|
85
|
+
fontSize500?: string;
|
|
86
|
+
fontSize600?: string;
|
|
87
|
+
fontSize700?: string;
|
|
88
|
+
fontSize800?: string;
|
|
89
|
+
fontSize900?: string;
|
|
90
|
+
fontSize1000?: string;
|
|
91
|
+
fontSize1100?: string;
|
|
92
|
+
fontSize1200?: string;
|
|
93
|
+
lineHeight100?: string;
|
|
94
|
+
lineHeight200?: string;
|
|
95
|
+
lineHeight300?: string;
|
|
96
|
+
lineHeight400?: string;
|
|
97
|
+
lineHeight500?: string;
|
|
98
|
+
lineHeight600?: string;
|
|
99
|
+
lineHeight700?: string;
|
|
100
|
+
lineHeight800?: string;
|
|
101
|
+
lineHeight900?: string;
|
|
102
|
+
lineHeight1000?: string;
|
|
103
|
+
lineHeight1100?: string;
|
|
104
|
+
lineHeight1200?: string;
|
|
105
|
+
fontWeightRegular?: string | number;
|
|
106
|
+
fontWeightMedium?: string | number;
|
|
107
|
+
fontWeightSemibold?: string | number;
|
|
108
|
+
fontWeightBold?: string | number;
|
|
109
|
+
letterSpacing?: string;
|
|
110
|
+
};
|
|
111
|
+
spacing?: {
|
|
112
|
+
controlHeight?: string;
|
|
113
|
+
controlGap?: string;
|
|
114
|
+
controlPaddingInline?: string;
|
|
115
|
+
controlPaddingBlock?: string;
|
|
116
|
+
cardPadding?: string;
|
|
117
|
+
fieldGap?: string;
|
|
118
|
+
sectionGap?: string;
|
|
119
|
+
listGap?: string;
|
|
120
|
+
touchTargetMin?: string;
|
|
121
|
+
};
|
|
122
|
+
shape?: {
|
|
123
|
+
controlRadius?: string;
|
|
124
|
+
inputRadius?: string;
|
|
125
|
+
cardRadius?: string;
|
|
126
|
+
surfaceRadius?: string;
|
|
127
|
+
pillRadius?: string;
|
|
128
|
+
focusRingWidth?: string;
|
|
129
|
+
};
|
|
130
|
+
elevation?: {
|
|
131
|
+
cardShadow?: string;
|
|
132
|
+
controlShadow?: string;
|
|
133
|
+
popoverShadow?: string;
|
|
134
|
+
overlayShadow?: string;
|
|
135
|
+
focusShadow?: string;
|
|
136
|
+
};
|
|
137
|
+
/** Material controls tune theme-derived translucent surfaces without replacing their brand or neutral colors. */
|
|
138
|
+
materials?: {
|
|
139
|
+
glassBlur?: string;
|
|
140
|
+
glassSaturation?: string;
|
|
141
|
+
glassSurfaceOpacity?: string;
|
|
142
|
+
glassCanvasOpacity?: string;
|
|
143
|
+
glassBorderOpacity?: string;
|
|
144
|
+
};
|
|
145
|
+
motion?: {
|
|
146
|
+
durationFast?: string;
|
|
147
|
+
durationNormal?: string;
|
|
148
|
+
durationSlow?: string;
|
|
149
|
+
easingStandard?: string;
|
|
150
|
+
easingEmphasized?: string;
|
|
151
|
+
};
|
|
152
|
+
/** Shared stacking order for menus, floating pickers, and notifications. Browser top-layer surfaces remain above these layers. */
|
|
153
|
+
layers?: {
|
|
154
|
+
dropdown?: string | number;
|
|
155
|
+
popover?: string | number;
|
|
156
|
+
toast?: string | number;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
/** Compose reusable theme packs left-to-right; later packs override earlier values within each group. */
|
|
160
|
+
export declare function composeSharePointUIDesignThemes(...themes: Array<SharePointUIDesignTheme | undefined>): SharePointUIDesignTheme;
|
|
161
|
+
export declare function getSharePointUIDesignTokens(theme?: SharePointUIDesignTheme): Record<string, string>;
|
|
162
|
+
export type SharePointUIThemeOptions = {
|
|
163
|
+
appearance?: SharePointUIAppearance;
|
|
164
|
+
baseAppearance?: SharePointUIBaseAppearance;
|
|
165
|
+
density?: SharePointUIDensity;
|
|
166
|
+
theme?: SharePointUIDesignTheme;
|
|
167
|
+
tokens?: Partial<SharePointUIStyleTokens>;
|
|
168
|
+
};
|
|
169
|
+
export declare function applySharePointTheme(target: HTMLElement, theme?: SharePointTheme, fluentTokens?: FluentThemeTokens, options?: SharePointUIThemeOptions): void;
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { getSharePointUIStyleTokens } from "./appearance.js";
|
|
2
|
+
/** Compose reusable theme packs left-to-right; later packs override earlier values within each group. */
|
|
3
|
+
export function composeSharePointUIDesignThemes(...themes) {
|
|
4
|
+
return themes.reduce((merged, theme) => ({
|
|
5
|
+
...merged,
|
|
6
|
+
...theme,
|
|
7
|
+
palette: { ...merged.palette, ...theme?.palette },
|
|
8
|
+
fluentTokens: { ...merged.fluentTokens, ...theme?.fluentTokens },
|
|
9
|
+
colors: { ...merged.colors, ...theme?.colors },
|
|
10
|
+
typography: { ...merged.typography, ...theme?.typography },
|
|
11
|
+
spacing: { ...merged.spacing, ...theme?.spacing },
|
|
12
|
+
shape: { ...merged.shape, ...theme?.shape },
|
|
13
|
+
elevation: { ...merged.elevation, ...theme?.elevation },
|
|
14
|
+
materials: { ...merged.materials, ...theme?.materials },
|
|
15
|
+
motion: { ...merged.motion, ...theme?.motion },
|
|
16
|
+
layers: { ...merged.layers, ...theme?.layers },
|
|
17
|
+
customProperties: { ...merged.customProperties, ...theme?.customProperties }
|
|
18
|
+
}), {});
|
|
19
|
+
}
|
|
20
|
+
const designTokenMap = {
|
|
21
|
+
"colors.accent": "--spui-ui-accent", "colors.accentHover": "--spui-ui-accent-hover", "colors.accentPressed": "--spui-ui-accent-pressed",
|
|
22
|
+
"colors.accentSubtle": "--spui-ui-accent-subtle", "colors.accentSubtleHover": "--spui-ui-accent-subtle-hover", "colors.accentSubtlePressed": "--spui-ui-accent-subtle-pressed", "colors.accentForeground": "--spui-ui-accent-text", "colors.secondaryHover": "--spui-button-secondary-hover",
|
|
23
|
+
"colors.foreground": "--spui-ui-text", "colors.foregroundMuted": "--spui-ui-muted", "colors.foregroundTertiary": "--spui-ui-text-muted", "colors.foregroundSubtle": "--spui-ui-foreground-subtle",
|
|
24
|
+
"colors.foregroundDisabled": "--spui-ui-foreground-disabled", "colors.canvas": "--spui-ui-canvas",
|
|
25
|
+
"colors.surface": "--spui-ui-surface", "colors.surfaceHover": "--spui-ui-surface-hover", "colors.surfaceAlt": "--spui-ui-surface-alt", "colors.surfaceSecondary": "--spui-ui-surface-secondary", "colors.surfaceSubtle": "--spui-ui-surface-subtle", "colors.surfaceRaised": "--spui-ui-surface-raised",
|
|
26
|
+
"colors.surfaceSunken": "--spui-ui-surface-sunken", "colors.border": "--spui-ui-stroke", "colors.borderSubtle": "--spui-ui-border-subtle",
|
|
27
|
+
"colors.borderStrong": "--spui-ui-border-strong", "colors.borderFocus": "--spui-ui-border-focus", "colors.borderDisabled": "--spui-ui-border-disabled",
|
|
28
|
+
"colors.selectedBackground": "--spui-selection-background", "colors.selectedBackgroundHover": "--spui-selection-background-hover", "colors.selectedForeground": "--spui-selection-foreground",
|
|
29
|
+
"colors.selectedBorder": "--spui-selection-border", "colors.link": "--spui-link-color", "colors.linkVisited": "--spui-link-visited", "colors.overlay": "--spui-overlay-scrim",
|
|
30
|
+
"colors.info": "--spui-ui-info", "colors.infoSurface": "--spui-ui-info-surface",
|
|
31
|
+
"colors.success": "--spui-ui-success", "colors.successSurface": "--spui-ui-success-surface", "colors.warning": "--spui-ui-warning",
|
|
32
|
+
"colors.warningSurface": "--spui-ui-warning-surface", "colors.danger": "--spui-ui-danger", "colors.dangerSurface": "--spui-ui-danger-surface", "colors.focus": "--spui-ui-focus", "colors.focusRing": "--spui-focus-ring",
|
|
33
|
+
"typography.fontFamily": "--spui-font-family", "typography.fontFamilyMono": "--spui-font-family-mono",
|
|
34
|
+
"typography.fontSize": "--spui-text-font-size", "typography.fontSizeSmall": "--spui-text-font-size-small",
|
|
35
|
+
"typography.fontSizeLarge": "--spui-text-font-size-large", "typography.fontSizeHeading": "--spui-text-font-size-heading",
|
|
36
|
+
"typography.fontWeight": "--spui-text-font-weight", "typography.fontWeightStrong": "--spui-text-font-weight-strong",
|
|
37
|
+
"typography.lineHeight": "--spui-text-line-height", "typography.lineHeightHeading": "--spui-text-line-height-heading",
|
|
38
|
+
"typography.fontSize100": "--fontSizeBase100", "typography.fontSize200": "--fontSizeBase200", "typography.fontSize300": "--fontSizeBase300",
|
|
39
|
+
"typography.fontSize400": "--fontSizeBase400", "typography.fontSize500": "--fontSizeBase500", "typography.fontSize600": "--fontSizeBase600",
|
|
40
|
+
"typography.fontSize700": "--fontSizeHero700", "typography.fontSize800": "--fontSizeHero800", "typography.fontSize900": "--fontSizeHero900", "typography.fontSize1000": "--fontSizeHero1000",
|
|
41
|
+
"typography.fontSize1100": "--spui-text-font-size-1100", "typography.fontSize1200": "--spui-text-font-size-1200",
|
|
42
|
+
"typography.lineHeight100": "--lineHeightBase100", "typography.lineHeight200": "--lineHeightBase200", "typography.lineHeight300": "--lineHeightBase300",
|
|
43
|
+
"typography.lineHeight400": "--lineHeightBase400", "typography.lineHeight500": "--lineHeightBase500", "typography.lineHeight600": "--lineHeightBase600",
|
|
44
|
+
"typography.lineHeight700": "--lineHeightHero700", "typography.lineHeight800": "--lineHeightHero800", "typography.lineHeight900": "--lineHeightHero900", "typography.lineHeight1000": "--lineHeightHero1000",
|
|
45
|
+
"typography.lineHeight1100": "--spui-text-line-height-1100", "typography.lineHeight1200": "--spui-text-line-height-1200",
|
|
46
|
+
"typography.fontWeightRegular": "--fontWeightRegular", "typography.fontWeightMedium": "--fontWeightMedium",
|
|
47
|
+
"typography.fontWeightSemibold": "--fontWeightSemibold", "typography.fontWeightBold": "--fontWeightBold",
|
|
48
|
+
"typography.letterSpacing": "--spui-text-letter-spacing",
|
|
49
|
+
"spacing.controlHeight": "--spui-control-height", "spacing.controlGap": "--spui-control-gap", "spacing.controlPaddingInline": "--spui-control-padding-inline",
|
|
50
|
+
"spacing.controlPaddingBlock": "--spui-control-padding-block", "spacing.cardPadding": "--spui-card-padding", "spacing.fieldGap": "--spui-field-gap",
|
|
51
|
+
"spacing.sectionGap": "--spui-section-gap", "spacing.listGap": "--spui-list-gap", "spacing.touchTargetMin": "--spui-touch-target-min",
|
|
52
|
+
"shape.controlRadius": "--spui-control-radius", "shape.inputRadius": "--spui-input-radius", "shape.cardRadius": "--spui-card-radius",
|
|
53
|
+
"shape.surfaceRadius": "--spui-surface-radius", "shape.pillRadius": "--spui-pill-radius", "shape.focusRingWidth": "--spui-focus-ring-width",
|
|
54
|
+
"elevation.cardShadow": "--spui-card-shadow", "elevation.controlShadow": "--spui-control-shadow", "elevation.popoverShadow": "--spui-popover-shadow",
|
|
55
|
+
"elevation.overlayShadow": "--spui-overlay-shadow", "elevation.focusShadow": "--spui-focus-shadow",
|
|
56
|
+
"materials.glassBlur": "--spui-glass-blur", "materials.glassSaturation": "--spui-glass-saturation",
|
|
57
|
+
"materials.glassSurfaceOpacity": "--spui-glass-surface-opacity", "materials.glassCanvasOpacity": "--spui-glass-canvas-opacity", "materials.glassBorderOpacity": "--spui-glass-border-opacity",
|
|
58
|
+
"motion.durationFast": "--spui-motion-duration-fast", "motion.durationNormal": "--spui-motion-duration-normal", "motion.durationSlow": "--spui-motion-duration-slow",
|
|
59
|
+
"motion.easingStandard": "--spui-motion-easing-standard", "motion.easingEmphasized": "--spui-motion-easing-emphasized",
|
|
60
|
+
"layers.dropdown": "--spui-layer-dropdown", "layers.popover": "--spui-layer-popover", "layers.toast": "--spui-layer-toast"
|
|
61
|
+
};
|
|
62
|
+
export function getSharePointUIDesignTokens(theme) {
|
|
63
|
+
const accent = theme?.colors?.accent ?? theme?.brandColor ?? theme?.palette?.themePrimary;
|
|
64
|
+
const result = {};
|
|
65
|
+
for (const [name, value] of Object.entries(theme?.palette ?? {})) {
|
|
66
|
+
if (value !== undefined)
|
|
67
|
+
result[`--spui-palette-${toKebab(name)}`] = String(value);
|
|
68
|
+
}
|
|
69
|
+
for (const [name, value] of Object.entries(theme?.fluentTokens ?? {})) {
|
|
70
|
+
if (value !== undefined && (typeof value === "string" || typeof value === "number")) {
|
|
71
|
+
result[name.startsWith("--") ? name : `--${name}`] = String(value);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (accent)
|
|
75
|
+
Object.assign(result, {
|
|
76
|
+
"--spui-ui-accent": accent,
|
|
77
|
+
"--spui-ui-accent-hover": `color-mix(in srgb, ${accent} 84%, black)`,
|
|
78
|
+
"--spui-selection-background": `color-mix(in srgb, ${accent} 14%, var(--spui-ui-surface))`,
|
|
79
|
+
"--spui-selection-border": accent,
|
|
80
|
+
"--spui-link-color": `var(--spui-semantic-link, color-mix(in srgb, ${accent} 55%, var(--spui-ui-text) 45%))`,
|
|
81
|
+
"--spui-focus-ring": "var(--spui-ui-border-focus)",
|
|
82
|
+
"--spui-ui-info": accent,
|
|
83
|
+
"--spui-ui-info-surface": `color-mix(in srgb, ${accent} 12%, var(--spui-ui-surface))`,
|
|
84
|
+
"--spui-primary-background": accent,
|
|
85
|
+
"--spui-primary-hover": `color-mix(in srgb, ${accent} 84%, black)`
|
|
86
|
+
});
|
|
87
|
+
if (accent && !theme?.colors?.accentForeground) {
|
|
88
|
+
const hex = /^#([\da-f]{3}|[\da-f]{6})$/i.exec(accent)?.[1];
|
|
89
|
+
if (hex) {
|
|
90
|
+
const normalized = hex.length === 3 ? [...hex].map(value => value + value).join("") : hex;
|
|
91
|
+
const channels = normalized.match(/[\da-f]{2}/gi).map(value => Number.parseInt(value, 16) / 255).map(value => value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4);
|
|
92
|
+
const luminance = channels[0] * 0.2126 + channels[1] * 0.7152 + channels[2] * 0.0722;
|
|
93
|
+
result["--spui-ui-accent-text"] = luminance > 0.179 ? "#000000" : "#ffffff";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
for (const [group, values] of Object.entries(theme ?? {})) {
|
|
97
|
+
if (group === "brandColor" || group === "palette" || group === "customProperties")
|
|
98
|
+
continue;
|
|
99
|
+
for (const [name, value] of Object.entries(values ?? {})) {
|
|
100
|
+
if (value !== undefined) {
|
|
101
|
+
const token = designTokenMap[`${group}.${name}`];
|
|
102
|
+
if (token)
|
|
103
|
+
result[token] = String(value);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// App-specific properties are the final design-pack layer; direct provider tokens still win later.
|
|
108
|
+
for (const [name, value] of Object.entries(theme?.customProperties ?? {})) {
|
|
109
|
+
if (name.startsWith("--") && name.length > 2)
|
|
110
|
+
result[name] = String(value);
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
const appliedProperties = new WeakMap();
|
|
115
|
+
const toKebab = (key) => key.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);
|
|
116
|
+
export function applySharePointTheme(target, theme, fluentTokens, options = {}) {
|
|
117
|
+
const style = target.style;
|
|
118
|
+
for (const name of appliedProperties.get(target) ?? [])
|
|
119
|
+
style.removeProperty(name);
|
|
120
|
+
const names = new Set();
|
|
121
|
+
if (theme) {
|
|
122
|
+
for (const [group, values] of Object.entries({ palette: theme.palette, semantic: theme.semanticColors })) {
|
|
123
|
+
for (const [name, value] of Object.entries(values ?? {})) {
|
|
124
|
+
if (!value)
|
|
125
|
+
continue;
|
|
126
|
+
const property = `--spui-${group}-${toKebab(name)}`;
|
|
127
|
+
style.setProperty(property, value);
|
|
128
|
+
names.add(property);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (const [group, values] of Object.entries({ effects: theme.effects, spacing: theme.spacing, "default-font-style": theme.defaultFontStyle })) {
|
|
132
|
+
for (const [name, value] of Object.entries(values ?? {})) {
|
|
133
|
+
if (typeof value !== "string" && typeof value !== "number")
|
|
134
|
+
continue;
|
|
135
|
+
const property = `--spui-${group}-${toKebab(name)}`;
|
|
136
|
+
style.setProperty(property, String(value));
|
|
137
|
+
names.add(property);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
for (const [name, values] of Object.entries(theme.fonts ?? {})) {
|
|
141
|
+
for (const [propertyName, value] of Object.entries(values ?? {})) {
|
|
142
|
+
if (typeof value !== "string" && typeof value !== "number")
|
|
143
|
+
continue;
|
|
144
|
+
const property = `--spui-fonts-${toKebab(name)}-${toKebab(propertyName)}`;
|
|
145
|
+
style.setProperty(property, String(value));
|
|
146
|
+
names.add(property);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
style.setProperty("--spui-is-inverted", theme.isInverted ? "1" : "0");
|
|
150
|
+
names.add("--spui-is-inverted");
|
|
151
|
+
}
|
|
152
|
+
for (const [name, value] of Object.entries(fluentTokens ?? {})) {
|
|
153
|
+
if (typeof value !== "string" && typeof value !== "number")
|
|
154
|
+
continue;
|
|
155
|
+
const property = name.startsWith("--") ? name : `--${name}`;
|
|
156
|
+
style.setProperty(property, String(value));
|
|
157
|
+
names.add(property);
|
|
158
|
+
}
|
|
159
|
+
target.dataset.spuiAppearance = options.appearance ?? "fluent";
|
|
160
|
+
const styleTokens = getSharePointUIStyleTokens(options.appearance, { ...getSharePointUIDesignTokens(options.theme), ...options.tokens }, options.baseAppearance, options.density);
|
|
161
|
+
for (const [property, value] of Object.entries(styleTokens)) {
|
|
162
|
+
style.setProperty(property, String(value));
|
|
163
|
+
names.add(property);
|
|
164
|
+
}
|
|
165
|
+
style.colorScheme = String(styleTokens["--spui-color-scheme"] ?? "light");
|
|
166
|
+
appliedProperties.set(target, names);
|
|
167
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type VirtualizerMeasureProps = {
|
|
3
|
+
defaultItemSize: number;
|
|
4
|
+
direction?: "vertical" | "horizontal";
|
|
5
|
+
bufferItems?: number;
|
|
6
|
+
bufferSize?: number;
|
|
7
|
+
};
|
|
8
|
+
export type VirtualizerContextMeasureProps = {
|
|
9
|
+
contextIndex: number;
|
|
10
|
+
setContextIndex: (index: number) => void;
|
|
11
|
+
childProgressiveSizes: React.MutableRefObject<number[]>;
|
|
12
|
+
};
|
|
13
|
+
export type VirtualizerMeasureDynamicProps = VirtualizerMeasureProps & {
|
|
14
|
+
virtualizerContext: VirtualizerContextMeasureProps;
|
|
15
|
+
numItems: number;
|
|
16
|
+
getItemSize: (index: number) => number;
|
|
17
|
+
};
|
|
18
|
+
export interface IndexedResizeCallbackElement {
|
|
19
|
+
handleResize: () => void;
|
|
20
|
+
}
|
|
21
|
+
/** Measure a fixed-size viewport and calculate a bounded item window. */
|
|
22
|
+
export declare function useStaticVirtualizerMeasure<TElement extends HTMLElement = HTMLElement>(props: VirtualizerMeasureProps): {
|
|
23
|
+
virtualizerLength: number;
|
|
24
|
+
bufferItems: number;
|
|
25
|
+
bufferSize: number;
|
|
26
|
+
scrollRef: (element: TElement | null) => void;
|
|
27
|
+
containerSizeRef: React.MutableRefObject<number>;
|
|
28
|
+
};
|
|
29
|
+
/** Measure only enough variable-size rows to cover the current scroll viewport. */
|
|
30
|
+
export declare function useDynamicVirtualizerMeasure<TElement extends HTMLElement = HTMLElement>(props: VirtualizerMeasureDynamicProps): {
|
|
31
|
+
virtualizerLength: number;
|
|
32
|
+
bufferItems: number;
|
|
33
|
+
bufferSize: number;
|
|
34
|
+
scrollRef: (element: TElement | null) => void;
|
|
35
|
+
containerSizeRef: React.RefObject<number>;
|
|
36
|
+
updateScrollPosition: (position: number) => void;
|
|
37
|
+
};
|
|
38
|
+
/** Track measured widths/heights by item index for legacy dynamic virtualizer composition. */
|
|
39
|
+
export declare function useMeasureList<TElement extends HTMLElement & IndexedResizeCallbackElement = HTMLElement & IndexedResizeCallbackElement>(currentIndex: number, _refLength: number, totalLength: number, defaultItemSize: number): {
|
|
40
|
+
widthArray: React.MutableRefObject<number[]>;
|
|
41
|
+
heightArray: React.MutableRefObject<number[]>;
|
|
42
|
+
createIndexedRef: (index: number) => (element: TElement | null) => void;
|
|
43
|
+
refArray: React.MutableRefObject<Array<TElement | undefined | null>>;
|
|
44
|
+
sizeUpdateCount: number;
|
|
45
|
+
};
|
|
46
|
+
export type ResizeCallbackWithRef = (entries: ResizeObserverEntry[], observer: ResizeObserver, scrollRef?: React.MutableRefObject<HTMLElement | null>) => void;
|
|
47
|
+
export type ScrollToItemStaticParams = {
|
|
48
|
+
index: number;
|
|
49
|
+
itemSize: number;
|
|
50
|
+
totalItems: number;
|
|
51
|
+
scrollViewRef: React.RefObject<HTMLElement | null>;
|
|
52
|
+
axis?: "horizontal" | "vertical";
|
|
53
|
+
reversed?: boolean;
|
|
54
|
+
behavior?: ScrollBehavior;
|
|
55
|
+
};
|
|
56
|
+
export type ScrollToItemDynamicParams = {
|
|
57
|
+
index: number;
|
|
58
|
+
itemSizes: React.RefObject<number[] | null>;
|
|
59
|
+
totalSize: number;
|
|
60
|
+
scrollViewRef: React.RefObject<HTMLElement | null>;
|
|
61
|
+
axis?: "horizontal" | "vertical";
|
|
62
|
+
reversed?: boolean;
|
|
63
|
+
behavior?: ScrollBehavior;
|
|
64
|
+
};
|
|
65
|
+
/** Create an observer from the document's own window, including when an SPFx part is rendered in an iframe. */
|
|
66
|
+
export declare function createResizeObserverFromDocument(targetDocument: Document | null | undefined, callback: ResizeObserverCallback): ResizeObserver | null;
|
|
67
|
+
/** Mirror a four-sided LTR observer margin for an RTL root. */
|
|
68
|
+
export declare function getRTLRootMargin(ltrRootMargin: string, target?: Element | Document | null, win?: Window | null): string;
|
|
69
|
+
/** Observe a changing element list with native IntersectionObserver and direction-aware margins. */
|
|
70
|
+
export declare function useIntersectionObserver(callback: IntersectionObserverCallback, options?: IntersectionObserverInit): {
|
|
71
|
+
setObserverList: React.Dispatch<React.SetStateAction<Element[] | undefined>>;
|
|
72
|
+
setObserverInit: (next: IntersectionObserverInit | undefined) => void;
|
|
73
|
+
observer: React.MutableRefObject<IntersectionObserver | undefined>;
|
|
74
|
+
};
|
|
75
|
+
/** Attach a resize observer callback ref; it is safe when ResizeObserver is unavailable. */
|
|
76
|
+
export declare function useResizeObserverRef_unstable(resizeCallback: ResizeCallbackWithRef): (instance: HTMLElement | null) => void;
|
|
77
|
+
/** Scroll an element to a fixed-size virtual item. */
|
|
78
|
+
export declare function scrollToItemStatic({ index, itemSize, totalItems, scrollViewRef, axis, reversed, behavior }: ScrollToItemStaticParams): void;
|
|
79
|
+
/** Scroll an element to a measured item; summing the prefix is O(index), so keep the measured list modest. */
|
|
80
|
+
export declare function scrollToItemDynamic({ index, itemSizes, totalSize, scrollViewRef, axis, reversed, behavior }: ScrollToItemDynamicParams): void;
|