@flamingo-stack/openframe-frontend-core 0.0.499 → 0.0.500
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/dist/{chunk-XV22URNM.cjs → chunk-4NDGD2YH.cjs} +19 -19
- package/dist/{chunk-XV22URNM.cjs.map → chunk-4NDGD2YH.cjs.map} +1 -1
- package/dist/{chunk-YDNIQLAP.js → chunk-5CY6YKWY.js} +6 -6
- package/dist/{chunk-Q66TP2LY.js → chunk-6TJJFQ74.js} +6 -6
- package/dist/{chunk-47LHA4QI.cjs → chunk-C5R2OX7A.cjs} +7 -2
- package/dist/chunk-C5R2OX7A.cjs.map +1 -0
- package/dist/{chunk-NSDDV4F6.cjs → chunk-ETU6VFOL.cjs} +40 -40
- package/dist/{chunk-NSDDV4F6.cjs.map → chunk-ETU6VFOL.cjs.map} +1 -1
- package/dist/{chunk-WJ2S6I34.cjs → chunk-GDUWGCPP.cjs} +12 -12
- package/dist/{chunk-WJ2S6I34.cjs.map → chunk-GDUWGCPP.cjs.map} +1 -1
- package/dist/{chunk-44YXQBNM.cjs → chunk-I64ZGPA6.cjs} +3 -3
- package/dist/{chunk-44YXQBNM.cjs.map → chunk-I64ZGPA6.cjs.map} +1 -1
- package/dist/{chunk-7DUMNMED.cjs → chunk-IDRKW6MS.cjs} +12 -12
- package/dist/{chunk-7DUMNMED.cjs.map → chunk-IDRKW6MS.cjs.map} +1 -1
- package/dist/{chunk-SGL6URIJ.cjs → chunk-L5CI57RM.cjs} +9 -5
- package/dist/chunk-L5CI57RM.cjs.map +1 -0
- package/dist/{chunk-Q6B7VAHN.cjs → chunk-LN2X4XAB.cjs} +18 -18
- package/dist/{chunk-Q6B7VAHN.cjs.map → chunk-LN2X4XAB.cjs.map} +1 -1
- package/dist/{chunk-RAL274JM.js → chunk-P3B65FBX.js} +4 -4
- package/dist/{chunk-QWCW4Z75.js → chunk-P5UMIPKR.js} +5 -5
- package/dist/{chunk-QL5YB4F7.js → chunk-P7IOCYGD.js} +52 -47
- package/dist/chunk-P7IOCYGD.js.map +1 -0
- package/dist/{chunk-V2APV4E4.cjs → chunk-PAO45LBQ.cjs} +1113 -916
- package/dist/chunk-PAO45LBQ.cjs.map +1 -0
- package/dist/{chunk-3AXJESKA.js → chunk-QQAKDJPE.js} +3 -3
- package/dist/{chunk-O7JY7LRP.js → chunk-R2IGOYHU.js} +3 -3
- package/dist/{chunk-RBZOUGCL.cjs → chunk-S3COVC7H.cjs} +73 -73
- package/dist/{chunk-RBZOUGCL.cjs.map → chunk-S3COVC7H.cjs.map} +1 -1
- package/dist/{chunk-QUFB5SDZ.js → chunk-SOX7CGFX.js} +303 -106
- package/dist/{chunk-QUFB5SDZ.js.map → chunk-SOX7CGFX.js.map} +1 -1
- package/dist/{chunk-W42256FC.cjs → chunk-TJCUGL7S.cjs} +33 -33
- package/dist/{chunk-W42256FC.cjs.map → chunk-TJCUGL7S.cjs.map} +1 -1
- package/dist/{chunk-SSYE7BQC.js → chunk-UM2YFCPE.js} +3 -3
- package/dist/{chunk-2CEDCSYD.cjs → chunk-V5ALIJZ6.cjs} +32 -32
- package/dist/{chunk-2CEDCSYD.cjs.map → chunk-V5ALIJZ6.cjs.map} +1 -1
- package/dist/{chunk-EP7ELZTU.cjs → chunk-VLI6ESJN.cjs} +93 -93
- package/dist/{chunk-EP7ELZTU.cjs.map → chunk-VLI6ESJN.cjs.map} +1 -1
- package/dist/{chunk-BAMTV6GL.js → chunk-VMDQDD5Y.js} +2 -2
- package/dist/{chunk-IUP26OXG.js → chunk-VPQBQJ4S.js} +2 -2
- package/dist/{chunk-TTJSLIXA.js → chunk-W6Y66G4K.js} +3 -3
- package/dist/{chunk-QKWOBV55.js → chunk-WHJGRRK2.js} +9 -5
- package/dist/chunk-WHJGRRK2.js.map +1 -0
- package/dist/{chunk-AEZ5BXLJ.js → chunk-XBLRT3MX.js} +4 -4
- package/dist/{chunk-FLZTUE2T.cjs → chunk-YSN2AZJR.cjs} +5 -5
- package/dist/{chunk-FLZTUE2T.cjs.map → chunk-YSN2AZJR.cjs.map} +1 -1
- package/dist/{chunk-6QVV3OLL.cjs → chunk-ZLJCE75C.cjs} +40 -40
- package/dist/{chunk-6QVV3OLL.cjs.map → chunk-ZLJCE75C.cjs.map} +1 -1
- package/dist/{chunk-UD4IT3GY.js → chunk-ZU27I5NZ.js} +6 -6
- package/dist/components/case-studies/index.cjs +10 -10
- package/dist/components/case-studies/index.js +4 -4
- package/dist/components/chat/index.cjs +4 -4
- package/dist/components/chat/index.js +3 -3
- package/dist/components/contact/index.cjs +5 -5
- package/dist/components/contact/index.js +4 -4
- package/dist/components/docs/index.cjs +7 -7
- package/dist/components/docs/index.js +6 -6
- package/dist/components/embeds/index.cjs +5 -5
- package/dist/components/embeds/index.js +4 -4
- package/dist/components/faq/index.cjs +6 -6
- package/dist/components/faq/index.js +5 -5
- package/dist/components/features/filters-dropdown.d.ts.map +1 -1
- package/dist/components/features/index.cjs +4 -4
- package/dist/components/features/index.js +3 -3
- package/dist/components/help-center-pages/index.cjs +23 -23
- package/dist/components/help-center-pages/index.js +14 -14
- package/dist/components/index.cjs +165 -161
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +16 -12
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/app-header.d.ts +48 -0
- package/dist/components/navigation/app-header.d.ts.map +1 -1
- package/dist/components/navigation/header-mingo-button.d.ts.map +1 -1
- package/dist/components/navigation/index.cjs +6 -4
- package/dist/components/navigation/index.cjs.map +1 -1
- package/dist/components/navigation/index.d.ts +2 -2
- package/dist/components/navigation/index.d.ts.map +1 -1
- package/dist/components/navigation/index.js +5 -3
- package/dist/components/navigation/navigation-sidebar-item.d.ts +14 -0
- package/dist/components/navigation/navigation-sidebar-item.d.ts.map +1 -1
- package/dist/components/navigation/navigation-sidebar-toggle.d.ts.map +1 -1
- package/dist/components/navigation/navigation-sidebar.d.ts +18 -0
- package/dist/components/navigation/navigation-sidebar.d.ts.map +1 -1
- package/dist/components/onboarding-guides/index.cjs +8 -8
- package/dist/components/onboarding-guides/index.js +7 -7
- package/dist/components/related-content/index.cjs +6 -6
- package/dist/components/related-content/index.js +5 -5
- package/dist/components/tickets/index.cjs +7 -7
- package/dist/components/tickets/index.js +6 -6
- package/dist/components/ui/button/button-styles.d.ts +1 -0
- package/dist/components/ui/button/button-styles.d.ts.map +1 -1
- package/dist/components/ui/button/button.d.ts.map +1 -1
- package/dist/components/ui/data-table/data-table-body.d.ts.map +1 -1
- package/dist/components/ui/data-table/data-table-column-filter.d.ts.map +1 -1
- package/dist/components/ui/data-table/data-table-header.d.ts.map +1 -1
- package/dist/components/ui/data-table/data-table-row.d.ts.map +1 -1
- package/dist/components/ui/data-table/data-table-skeleton.d.ts +12 -0
- package/dist/components/ui/data-table/data-table-skeleton.d.ts.map +1 -1
- package/dist/components/ui/data-table/index.d.ts +1 -1
- package/dist/components/ui/data-table/index.d.ts.map +1 -1
- package/dist/components/ui/data-table/utils.d.ts +18 -0
- package/dist/components/ui/data-table/utils.d.ts.map +1 -1
- package/dist/components/ui/file-manager/index.cjs +50 -50
- package/dist/components/ui/file-manager/index.js +1 -1
- package/dist/components/ui/index.cjs +6 -4
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +5 -3
- package/dist/hooks/index.cjs +4 -2
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.js +3 -1
- package/dist/hooks/ui/index.d.ts +1 -0
- package/dist/hooks/ui/index.d.ts.map +1 -1
- package/dist/hooks/ui/use-isomorphic-layout-effect.d.ts +17 -0
- package/dist/hooks/ui/use-isomorphic-layout-effect.d.ts.map +1 -0
- package/dist/index.cjs +10 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +9 -3
- package/dist/types/navigation.d.ts +24 -0
- package/dist/types/navigation.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/features/filters-dropdown.tsx +17 -5
- package/src/components/navigation/app-header.tsx +178 -0
- package/src/components/navigation/header-mingo-button.tsx +5 -0
- package/src/components/navigation/index.ts +2 -2
- package/src/components/navigation/navigation-sidebar-item.tsx +22 -0
- package/src/components/navigation/navigation-sidebar-toggle.tsx +10 -6
- package/src/components/navigation/navigation-sidebar.tsx +187 -44
- package/src/components/ui/button/button-styles.ts +11 -0
- package/src/components/ui/button/button.tsx +6 -3
- package/src/components/ui/button/split-button.tsx +2 -2
- package/src/components/ui/data-table/data-table-body.tsx +5 -2
- package/src/components/ui/data-table/data-table-column-filter.tsx +54 -25
- package/src/components/ui/data-table/data-table-header.tsx +134 -45
- package/src/components/ui/data-table/data-table-row.tsx +3 -2
- package/src/components/ui/data-table/data-table-skeleton.tsx +17 -2
- package/src/components/ui/data-table/index.ts +1 -1
- package/src/components/ui/data-table/utils.ts +49 -3
- package/src/hooks/ui/index.ts +1 -0
- package/src/hooks/ui/use-isomorphic-layout-effect.ts +20 -0
- package/src/types/navigation.ts +21 -0
- package/dist/chunk-47LHA4QI.cjs.map +0 -1
- package/dist/chunk-QKWOBV55.js.map +0 -1
- package/dist/chunk-QL5YB4F7.js.map +0 -1
- package/dist/chunk-SGL6URIJ.cjs.map +0 -1
- package/dist/chunk-V2APV4E4.cjs.map +0 -1
- /package/dist/{chunk-YDNIQLAP.js.map → chunk-5CY6YKWY.js.map} +0 -0
- /package/dist/{chunk-Q66TP2LY.js.map → chunk-6TJJFQ74.js.map} +0 -0
- /package/dist/{chunk-RAL274JM.js.map → chunk-P3B65FBX.js.map} +0 -0
- /package/dist/{chunk-QWCW4Z75.js.map → chunk-P5UMIPKR.js.map} +0 -0
- /package/dist/{chunk-3AXJESKA.js.map → chunk-QQAKDJPE.js.map} +0 -0
- /package/dist/{chunk-O7JY7LRP.js.map → chunk-R2IGOYHU.js.map} +0 -0
- /package/dist/{chunk-SSYE7BQC.js.map → chunk-UM2YFCPE.js.map} +0 -0
- /package/dist/{chunk-BAMTV6GL.js.map → chunk-VMDQDD5Y.js.map} +0 -0
- /package/dist/{chunk-IUP26OXG.js.map → chunk-VPQBQJ4S.js.map} +0 -0
- /package/dist/{chunk-TTJSLIXA.js.map → chunk-W6Y66G4K.js.map} +0 -0
- /package/dist/{chunk-AEZ5BXLJ.js.map → chunk-XBLRT3MX.js.map} +0 -0
- /package/dist/{chunk-UD4IT3GY.js.map → chunk-ZU27I5NZ.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -394,6 +394,7 @@ import {
|
|
|
394
394
|
MspOrganizationCard,
|
|
395
395
|
MspOrganizationCardSkeleton,
|
|
396
396
|
MultiLevelNavigation,
|
|
397
|
+
NAVIGATION_SIDEBAR_WIDTH_VAR,
|
|
397
398
|
NETWORK_CONFIG,
|
|
398
399
|
NEW_TAB_FEATURES,
|
|
399
400
|
NavLinkAnchorViaRuntime,
|
|
@@ -475,6 +476,7 @@ import {
|
|
|
475
476
|
ROADMAP_STATUS_OPTIONS,
|
|
476
477
|
ROW_HEIGHT_DESKTOP,
|
|
477
478
|
ROW_HEIGHT_MOBILE,
|
|
479
|
+
ROW_SHELL_CLASSES,
|
|
478
480
|
RadioGroup,
|
|
479
481
|
RadioGroupBlock,
|
|
480
482
|
RadioGroupItem,
|
|
@@ -989,7 +991,7 @@ import {
|
|
|
989
991
|
walkthroughDismissCookieName,
|
|
990
992
|
withFirstTouchAttribution,
|
|
991
993
|
writeDismissCookie
|
|
992
|
-
} from "./chunk-
|
|
994
|
+
} from "./chunk-SOX7CGFX.js";
|
|
993
995
|
import {
|
|
994
996
|
CommandApprovalToast,
|
|
995
997
|
DEFAULT_MIN_FILL_MS,
|
|
@@ -1079,6 +1081,7 @@ import {
|
|
|
1079
1081
|
useHumanitySignals,
|
|
1080
1082
|
useImageEdgeColor,
|
|
1081
1083
|
useIsTruncated,
|
|
1084
|
+
useIsomorphicLayoutEffect,
|
|
1082
1085
|
useLgUp,
|
|
1083
1086
|
useLocalStorage,
|
|
1084
1087
|
useMarqueeEngine,
|
|
@@ -1109,7 +1112,7 @@ import {
|
|
|
1109
1112
|
validateSchema,
|
|
1110
1113
|
validateVariables,
|
|
1111
1114
|
variablesToUrlParams
|
|
1112
|
-
} from "./chunk-
|
|
1115
|
+
} from "./chunk-P7IOCYGD.js";
|
|
1113
1116
|
import {
|
|
1114
1117
|
PLAY_ICON_PATH
|
|
1115
1118
|
} from "./chunk-OYGFWWLQ.js";
|
|
@@ -1148,7 +1151,7 @@ import {
|
|
|
1148
1151
|
SkeletonText,
|
|
1149
1152
|
SplitButton,
|
|
1150
1153
|
buttonVariants
|
|
1151
|
-
} from "./chunk-
|
|
1154
|
+
} from "./chunk-WHJGRRK2.js";
|
|
1152
1155
|
import "./chunk-6U3IUD57.js";
|
|
1153
1156
|
import "./chunk-OHPI2HRK.js";
|
|
1154
1157
|
import {
|
|
@@ -1823,6 +1826,7 @@ export {
|
|
|
1823
1826
|
MspOrganizationCard,
|
|
1824
1827
|
MspOrganizationCardSkeleton,
|
|
1825
1828
|
MultiLevelNavigation,
|
|
1829
|
+
NAVIGATION_SIDEBAR_WIDTH_VAR,
|
|
1826
1830
|
NEAR_VIEWPORT_ROOT_MARGIN,
|
|
1827
1831
|
NETWORK_CONFIG,
|
|
1828
1832
|
NEW_TAB_FEATURES,
|
|
@@ -1927,6 +1931,7 @@ export {
|
|
|
1927
1931
|
ROADMAP_STATUS_OPTIONS,
|
|
1928
1932
|
ROW_HEIGHT_DESKTOP,
|
|
1929
1933
|
ROW_HEIGHT_MOBILE,
|
|
1934
|
+
ROW_SHELL_CLASSES,
|
|
1930
1935
|
RadioGroup,
|
|
1931
1936
|
RadioGroupBlock,
|
|
1932
1937
|
RadioGroupItem,
|
|
@@ -2550,6 +2555,7 @@ export {
|
|
|
2550
2555
|
useHumanitySignals,
|
|
2551
2556
|
useImageEdgeColor,
|
|
2552
2557
|
useIsTruncated,
|
|
2558
|
+
useIsomorphicLayoutEffect,
|
|
2553
2559
|
useJetStreamDialogSubscription,
|
|
2554
2560
|
useLgUp,
|
|
2555
2561
|
useLoading,
|
|
@@ -87,6 +87,30 @@ export interface SlidingSidebarConfig {
|
|
|
87
87
|
*/
|
|
88
88
|
export interface NavigationSidebarConfig {
|
|
89
89
|
items: NavigationSidebarItem[];
|
|
90
|
+
/**
|
|
91
|
+
* Draw placeholder rows instead of `items`.
|
|
92
|
+
*
|
|
93
|
+
* For hosts whose navigation is not knowable at first paint — entries gated by
|
|
94
|
+
* server-loaded feature flags, permissions, or tenant config. Such a host has no
|
|
95
|
+
* good option without this: rendering the items it has yet means a nav that grows
|
|
96
|
+
* and shifts as answers arrive, and guessing the gated ones wrong shows entries
|
|
97
|
+
* that don't belong to the user (a flag that HIDES a legacy entry when enabled
|
|
98
|
+
* makes "not answered yet" indistinguishable from "off").
|
|
99
|
+
*
|
|
100
|
+
* The rows reuse the real entry's geometry and the sidebar's own minimized state,
|
|
101
|
+
* so the placeholder is correct in both the expanded and the minimized rail with
|
|
102
|
+
* nothing to pass in — and the handoff to the real nav moves nothing.
|
|
103
|
+
*/
|
|
104
|
+
loading?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* How many placeholder rows `loading` draws, per section. Defaults to 7 primary
|
|
107
|
+
* and 2 secondary — the shape of a typical console nav. Pass the counts the host
|
|
108
|
+
* expects so the placeholder and the loaded nav are the same height.
|
|
109
|
+
*/
|
|
110
|
+
loadingRows?: {
|
|
111
|
+
primary?: number;
|
|
112
|
+
secondary?: number;
|
|
113
|
+
};
|
|
90
114
|
minimized?: boolean;
|
|
91
115
|
onNavigate?: (path: string) => void;
|
|
92
116
|
onToggleMinimized?: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/types/navigation.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/types/navigation.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -212,6 +212,19 @@ export const FiltersDropdown: React.FC<FiltersDropdownProps> = ({
|
|
|
212
212
|
}
|
|
213
213
|
}, [currentFiltersStr])
|
|
214
214
|
|
|
215
|
+
// Closing must NOT reset `actualPlacement`.
|
|
216
|
+
//
|
|
217
|
+
// The panel stays mounted through its exit transition (see `shouldRender`), so
|
|
218
|
+
// a reset here lands on something still on screen: a dropdown that had flipped
|
|
219
|
+
// to the opposite side snaps back the moment it starts fading, sliding roughly
|
|
220
|
+
// its own width sideways on the way out. It showed up on whichever filter sits
|
|
221
|
+
// nearest an edge — the last column on tablet, and the same column on desktop
|
|
222
|
+
// once the window is narrow enough to force the flip.
|
|
223
|
+
//
|
|
224
|
+
// Nothing is lost by dropping it: opening recomputes the placement from the
|
|
225
|
+
// trigger's current rect (see the effect above), so the value left behind is
|
|
226
|
+
// never read again.
|
|
227
|
+
|
|
215
228
|
// Close dropdown when clicking outside
|
|
216
229
|
useEffect(() => {
|
|
217
230
|
const handleClickOutside = (event: MouseEvent) => {
|
|
@@ -221,7 +234,6 @@ export const FiltersDropdown: React.FC<FiltersDropdownProps> = ({
|
|
|
221
234
|
!containerRef.current.contains(event.target as Node)
|
|
222
235
|
) {
|
|
223
236
|
setIsOpen(false)
|
|
224
|
-
setActualPlacement(placement)
|
|
225
237
|
}
|
|
226
238
|
}
|
|
227
239
|
|
|
@@ -236,19 +248,18 @@ export const FiltersDropdown: React.FC<FiltersDropdownProps> = ({
|
|
|
236
248
|
document.removeEventListener('mousedown', handleClickOutside)
|
|
237
249
|
}
|
|
238
250
|
}
|
|
239
|
-
}, [isOpen
|
|
251
|
+
}, [isOpen])
|
|
240
252
|
|
|
241
253
|
// Handle escape key
|
|
242
254
|
useEffect(() => {
|
|
243
255
|
const handleEscape = (e: KeyboardEvent) => {
|
|
244
256
|
if (e.key === 'Escape' && isOpen) {
|
|
245
257
|
setIsOpen(false)
|
|
246
|
-
setActualPlacement(placement)
|
|
247
258
|
}
|
|
248
259
|
}
|
|
249
260
|
document.addEventListener('keydown', handleEscape)
|
|
250
261
|
return () => document.removeEventListener('keydown', handleEscape)
|
|
251
|
-
}, [isOpen
|
|
262
|
+
}, [isOpen])
|
|
252
263
|
|
|
253
264
|
const handleToggleOption = (sectionId: string, optionId: string, sectionType: string) => {
|
|
254
265
|
setSelectedFilters(prev => {
|
|
@@ -298,8 +309,9 @@ export const FiltersDropdown: React.FC<FiltersDropdownProps> = ({
|
|
|
298
309
|
|
|
299
310
|
const handleApply = () => {
|
|
300
311
|
onApply(selectedFilters)
|
|
312
|
+
// No placement reset — see the note above the outside-click effect. `Reset`
|
|
313
|
+
// never did one, which is why only Apply and the dismiss paths slid.
|
|
301
314
|
setIsOpen(false)
|
|
302
|
-
setActualPlacement(placement)
|
|
303
315
|
}
|
|
304
316
|
|
|
305
317
|
const getActiveFiltersCount = () => {
|
|
@@ -50,8 +50,57 @@ export interface AppHeaderProps {
|
|
|
50
50
|
* EXCEPT the mobile burger menu toggle, which remains interactive.
|
|
51
51
|
*/
|
|
52
52
|
disabled?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Draw placeholder cells instead of the live controls.
|
|
55
|
+
*
|
|
56
|
+
* Solves a problem this header cannot solve on its own: its mobile/desktop split
|
|
57
|
+
* is decided by `useMdUp()`, which answers `undefined` until an effect has run —
|
|
58
|
+
* and `?? false` turns that into "mobile". The first render is therefore always
|
|
59
|
+
* the phone header (burger + wordmark, no side actions), which on a desktop load
|
|
60
|
+
* is a visible flash before the real layout appears. It is also what a host has
|
|
61
|
+
* to show while the user and the action flags are still loading.
|
|
62
|
+
*
|
|
63
|
+
* The placeholder decides mobile vs desktop in CSS instead, so it is correct at
|
|
64
|
+
* every width on the very first paint, server-rendered included.
|
|
65
|
+
*/
|
|
66
|
+
loading?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Shape of the trailing action cells `loading` reserves.
|
|
69
|
+
*
|
|
70
|
+
* Needed because the `show*` props are usually the very thing the host is still
|
|
71
|
+
* waiting on — they are typically driven by feature flags or permissions, so during
|
|
72
|
+
* `loading` they all read `false` and the placeholder collapses to whatever is
|
|
73
|
+
* hardcoded on (often just the avatar), which looks nothing like the loaded header.
|
|
74
|
+
*
|
|
75
|
+
* Pass the cells the header settles on, in order — see `HeaderLoadingCell` for the
|
|
76
|
+
* footprints. A bare number is accepted as shorthand for all-`'icon'`.
|
|
77
|
+
*
|
|
78
|
+
* Unlike the sidebar's rows, a cell that turns out not to exist is cheap here: the
|
|
79
|
+
* cells are a right-aligned cluster in otherwise empty space, so one disappearing
|
|
80
|
+
* shifts nothing else on the page.
|
|
81
|
+
*
|
|
82
|
+
* Defaults to the shape implied by the `show*` props, which is right for a host whose
|
|
83
|
+
* header composition is known up front.
|
|
84
|
+
*/
|
|
85
|
+
loadingActionCells?: number | ReadonlyArray<HeaderLoadingCell>;
|
|
53
86
|
}
|
|
54
87
|
|
|
88
|
+
/**
|
|
89
|
+
* A trailing header cell's footprint while loading — see `loadingActionCells`.
|
|
90
|
+
*
|
|
91
|
+
* The breakpoint-scoped members exist because several live cells are themselves
|
|
92
|
+
* responsive, and a placeholder that ignores that is wider than the header it hands
|
|
93
|
+
* off to on exactly the viewports where the cluster is tightest:
|
|
94
|
+
*
|
|
95
|
+
* - `'icon'` — a fixed 48/56px cell at every width (time tracker, notifications).
|
|
96
|
+
* - `'icon-md'` — the same cell, from md only (the avatar: `isMdUp && showUser`).
|
|
97
|
+
* - `'icon-lg'` — the same cell, from lg only (the organization filter, which the
|
|
98
|
+
* live header renders `hidden lg:flex`).
|
|
99
|
+
* - `'wide'` — the Mingo launcher: a 48px square below md, where the live button is
|
|
100
|
+
* `iconOnly`, and the fixed 140px labelled cell from md.
|
|
101
|
+
*/
|
|
102
|
+
export type HeaderLoadingCell = 'icon' | 'icon-md' | 'icon-lg' | 'wide';
|
|
103
|
+
|
|
55
104
|
export const AppHeader = React.memo(function AppHeader({
|
|
56
105
|
showSearch,
|
|
57
106
|
onSearch,
|
|
@@ -75,9 +124,36 @@ export const AppHeader = React.memo(function AppHeader({
|
|
|
75
124
|
isMobileMenuOpen,
|
|
76
125
|
onToggleMobileMenu,
|
|
77
126
|
disabled = false,
|
|
127
|
+
loading = false,
|
|
128
|
+
loadingActionCells,
|
|
78
129
|
}: AppHeaderProps) {
|
|
79
130
|
const isMdUp = useMdUp() ?? false;
|
|
80
131
|
|
|
132
|
+
// After the only hook above, so the hook order is identical in both branches.
|
|
133
|
+
if (loading) {
|
|
134
|
+
return (
|
|
135
|
+
<AppHeaderSkeleton
|
|
136
|
+
showSearch={showSearch}
|
|
137
|
+
actionCells={
|
|
138
|
+
loadingActionCells ??
|
|
139
|
+
// Fallback: what the `show*` props imply, in the order the live cells are
|
|
140
|
+
// mounted below. Only correct for a host that knows its header composition
|
|
141
|
+
// before it starts loading. The cell types carry each control's own
|
|
142
|
+
// breakpoint — the organization filter is `hidden lg:flex`, the avatar is
|
|
143
|
+
// gated on `isMdUp`, and Mingo is `iconOnly` below md.
|
|
144
|
+
([
|
|
145
|
+
showOrganizations && 'icon-lg',
|
|
146
|
+
showTimeTracker && 'icon',
|
|
147
|
+
showNotifications && 'icon',
|
|
148
|
+
showUser && 'icon-md',
|
|
149
|
+
showMingoAI && 'wide',
|
|
150
|
+
].filter(Boolean) as HeaderLoadingCell[])
|
|
151
|
+
}
|
|
152
|
+
className={className}
|
|
153
|
+
/>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
81
157
|
const dimmedClass = disabled ? 'pointer-events-none opacity-50' : '';
|
|
82
158
|
// Cells carry their own dividers in the unified TopNavigation model
|
|
83
159
|
// (the shell no longer applies divide-x).
|
|
@@ -268,3 +344,105 @@ function NotificationsHeaderButton({ fallbackUnreadCount, disabled, dimmedClass
|
|
|
268
344
|
}
|
|
269
345
|
|
|
270
346
|
export default AppHeader;
|
|
347
|
+
|
|
348
|
+
// Literal class strings — Tailwind's scanner needs to see them spelled out.
|
|
349
|
+
const CELL_VISIBILITY: Record<Exclude<HeaderLoadingCell, 'wide'>, string | undefined> = {
|
|
350
|
+
icon: undefined,
|
|
351
|
+
'icon-md': 'hidden md:flex',
|
|
352
|
+
'icon-lg': 'hidden lg:flex',
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
/** One trailing action cell placeholder — mirrors the live cells' 48/56px box. */
|
|
356
|
+
function HeaderCellSkeleton({ className }: { className?: string }) {
|
|
357
|
+
return (
|
|
358
|
+
<div
|
|
359
|
+
className={cn(
|
|
360
|
+
'flex h-full w-12 shrink-0 items-center justify-center border-l border-ods-border md:w-14',
|
|
361
|
+
className,
|
|
362
|
+
)}
|
|
363
|
+
>
|
|
364
|
+
<div className="h-4 w-4 animate-pulse rounded bg-ods-border md:h-6 md:w-6" />
|
|
365
|
+
</div>
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Wide cell placeholder — mirrors `HeaderMingoButton` at both widths, which are
|
|
371
|
+
* two different shapes: the live button gets `iconOnly={!isMdUp}`, so below md it
|
|
372
|
+
* drops its wordmark and collapses to the same 48px square as any other cell, and
|
|
373
|
+
* from md it is the fixed 140px labelled cell. Reserving 140px-worth of icon,
|
|
374
|
+
* label, gap and padding on a phone would make the placeholder cluster ~70px
|
|
375
|
+
* wider than the header it hands off to.
|
|
376
|
+
*/
|
|
377
|
+
function HeaderWideCellSkeleton() {
|
|
378
|
+
return (
|
|
379
|
+
<div className="flex h-full w-12 shrink-0 items-center justify-center gap-2 border-l border-ods-border md:w-[140px] md:px-4">
|
|
380
|
+
<div className="h-4 w-4 shrink-0 animate-pulse rounded bg-ods-border md:h-6 md:w-6" />
|
|
381
|
+
<div className="hidden h-5 animate-pulse rounded bg-ods-border md:block md:w-[72px]" />
|
|
382
|
+
</div>
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* `AppHeader`'s loading state — see `AppHeaderProps.loading`.
|
|
388
|
+
*
|
|
389
|
+
* Keep in sync with `AppHeader` above; a diverging placeholder makes the handoff
|
|
390
|
+
* jump. Every breakpoint decision here is a Tailwind variant on purpose: this is the
|
|
391
|
+
* one thing the live header cannot do (its split runs through `useMdUp()`), and it
|
|
392
|
+
* is the whole reason this branch exists.
|
|
393
|
+
*/
|
|
394
|
+
function AppHeaderSkeleton({
|
|
395
|
+
showSearch,
|
|
396
|
+
actionCells,
|
|
397
|
+
className,
|
|
398
|
+
}: {
|
|
399
|
+
showSearch?: boolean;
|
|
400
|
+
actionCells: number | ReadonlyArray<HeaderLoadingCell>;
|
|
401
|
+
className?: string;
|
|
402
|
+
}) {
|
|
403
|
+
const cells: ReadonlyArray<HeaderLoadingCell> =
|
|
404
|
+
typeof actionCells === 'number'
|
|
405
|
+
? Array.from({ length: Math.max(0, actionCells) }, () => 'icon' as const)
|
|
406
|
+
: actionCells;
|
|
407
|
+
return (
|
|
408
|
+
<TopNavigation
|
|
409
|
+
className={cn('sticky top-0 z-40', className)}
|
|
410
|
+
centerBreakpoint="md"
|
|
411
|
+
aria-busy="true"
|
|
412
|
+
leading={
|
|
413
|
+
// Burger cell: mobile only, in CSS.
|
|
414
|
+
<div className="flex h-full w-12 shrink-0 items-center justify-center border-r border-ods-border md:hidden">
|
|
415
|
+
<div className="h-4 w-4 animate-pulse rounded bg-ods-border" />
|
|
416
|
+
</div>
|
|
417
|
+
}
|
|
418
|
+
logo={
|
|
419
|
+
<>
|
|
420
|
+
<div className="h-6 w-6 shrink-0 animate-pulse rounded bg-ods-border" />
|
|
421
|
+
<div className="h-4 w-24 animate-pulse rounded bg-ods-border" />
|
|
422
|
+
</>
|
|
423
|
+
}
|
|
424
|
+
// `md:hidden` belongs on the WRAPPER, not the placeholder inside it:
|
|
425
|
+
// `TopNavigation` builds its padded logo zone whenever `logo` is truthy, and
|
|
426
|
+
// that padding runs to 24px at md and 80px at lg. The live header passes
|
|
427
|
+
// `false` here from md up, so the zone does not exist at all — leaving the
|
|
428
|
+
// wrapper visible would inset the search field by 80px on desktop and shift
|
|
429
|
+
// it back on handoff, which is the exact jump this branch removes.
|
|
430
|
+
logoClassName="gap-2 md:hidden"
|
|
431
|
+
// `TopNavigation` already hides the center zone below `centerBreakpoint`.
|
|
432
|
+
center={showSearch ? <div className="h-10 w-full animate-pulse rounded-md bg-ods-border" /> : undefined}
|
|
433
|
+
sideActions={
|
|
434
|
+
<>
|
|
435
|
+
{/* Mobile-only search trigger; from md the search lives in the center zone. */}
|
|
436
|
+
{showSearch && <HeaderCellSkeleton className="md:hidden" />}
|
|
437
|
+
{cells.map((cell, i) =>
|
|
438
|
+
cell === 'wide' ? (
|
|
439
|
+
<HeaderWideCellSkeleton key={i} />
|
|
440
|
+
) : (
|
|
441
|
+
<HeaderCellSkeleton key={i} className={CELL_VISIBILITY[cell]} />
|
|
442
|
+
),
|
|
443
|
+
)}
|
|
444
|
+
</>
|
|
445
|
+
}
|
|
446
|
+
/>
|
|
447
|
+
);
|
|
448
|
+
}
|
|
@@ -39,6 +39,11 @@ export function HeaderMingoButton({
|
|
|
39
39
|
aria-pressed={isActive}
|
|
40
40
|
className={cn(
|
|
41
41
|
'flex items-center shrink-0 h-full gap-2 px-4',
|
|
42
|
+
// Fixed 140px cell from md, so the header's right-hand cluster has a
|
|
43
|
+
// known width and a loading placeholder can reserve it exactly
|
|
44
|
+
// (`AppHeaderProps.loadingActionCells` → `'wide'`). Content-width below
|
|
45
|
+
// md, and in `iconOnly` mode, where the control is a square affordance.
|
|
46
|
+
!iconOnly && 'md:w-[140px] md:justify-center',
|
|
42
47
|
'transition-colors duration-200',
|
|
43
48
|
'focus:outline-none focus-visible:ring-2 focus-visible:ring-ods-accent',
|
|
44
49
|
// Transparent at rest so the cell inherits the bar's background
|
|
@@ -22,11 +22,11 @@ export type { SlidingSidebarProps } from './sliding-sidebar'
|
|
|
22
22
|
export { StickySectionNav, useSectionNavigation } from './sticky-section-nav'
|
|
23
23
|
export type { StickyNavSection } from './sticky-section-nav'
|
|
24
24
|
|
|
25
|
-
export { NavigationSidebar } from './navigation-sidebar'
|
|
25
|
+
export { NAVIGATION_SIDEBAR_WIDTH_VAR, NavigationSidebar } from './navigation-sidebar'
|
|
26
26
|
export type { NavigationSidebarProps } from './navigation-sidebar'
|
|
27
27
|
|
|
28
28
|
export { AppHeader } from './app-header'
|
|
29
|
-
export type { AppHeaderProps } from './app-header'
|
|
29
|
+
export type { AppHeaderProps, HeaderLoadingCell } from './app-header'
|
|
30
30
|
|
|
31
31
|
export { AppLayout, useAppLayoutDrawerContainer } from './app-layout'
|
|
32
32
|
export type { AppLayoutProps } from './app-layout'
|
|
@@ -130,3 +130,25 @@ export const NavigationSidebarItemButton = memo(function NavigationSidebarItemBu
|
|
|
130
130
|
</Link>
|
|
131
131
|
)
|
|
132
132
|
})
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* One placeholder entry, for `NavigationSidebarConfig.loading`.
|
|
136
|
+
*
|
|
137
|
+
* Deliberately in this file, beside `NavigationSidebarItemButton`: the two must
|
|
138
|
+
* agree on `h-14`, the `p-[var(--spacing-system-m)]` inset, the 24px icon box and
|
|
139
|
+
* the label column, or the nav resizes on the handoff. Same reason
|
|
140
|
+
* `header-skeleton.tsx` sits beside `header.tsx`.
|
|
141
|
+
*
|
|
142
|
+
* `showLabel` is the sidebar's own minimized state, so the caller passes what it
|
|
143
|
+
* already passes the real row — no separate width handling.
|
|
144
|
+
*/
|
|
145
|
+
export function NavigationSidebarItemSkeleton({ showLabel }: { showLabel: boolean }) {
|
|
146
|
+
return (
|
|
147
|
+
<div className="w-full flex items-center justify-start h-14 p-[var(--spacing-system-m)]" aria-hidden="true">
|
|
148
|
+
<div className="relative flex items-center justify-center flex-shrink-0">
|
|
149
|
+
<div className="h-6 w-6 animate-pulse rounded bg-ods-border" />
|
|
150
|
+
</div>
|
|
151
|
+
{showLabel && <div className="h-4 flex-1 ml-[var(--spacing-system-xs)] animate-pulse rounded bg-ods-border" />}
|
|
152
|
+
</div>
|
|
153
|
+
)
|
|
154
|
+
}
|
|
@@ -30,12 +30,16 @@ export function NavigationSidebarToggle({
|
|
|
30
30
|
aria-label={"Hide Menu"}
|
|
31
31
|
>
|
|
32
32
|
<div className="flex items-center justify-center flex-shrink-0">
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
{/* Direction follows the rail's measured width (the `of-nav-sidebar`
|
|
34
|
+
container declared in `navigation-sidebar.tsx`), not `minimized`:
|
|
35
|
+
before hydration that prop can only carry the server's answer, and
|
|
36
|
+
a chevron pointing the wrong way in a 56px rail is the one piece of
|
|
37
|
+
sidebar state a user actually notices arriving late.
|
|
38
|
+
|
|
39
|
+
Collapsed is the default because container queries are min-width —
|
|
40
|
+
the rail is narrower than every threshold, so it needs no query of
|
|
41
|
+
its own. */}
|
|
42
|
+
<Chevrons03LeftIcon className="rotate-180 @[140px]/of-nav-sidebar:rotate-0 text-ods-text-secondary w-6 h-6 transition-transform duration-300" />
|
|
39
43
|
</div>
|
|
40
44
|
|
|
41
45
|
<span
|