@wordpress/boot 0.1.1-next.2f1c7c01b.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.
Files changed (130) hide show
  1. package/LICENSE.md +788 -0
  2. package/build-module/components/app/index.js +32 -0
  3. package/build-module/components/app/index.js.map +7 -0
  4. package/build-module/components/app/router.js +119 -0
  5. package/build-module/components/app/router.js.map +7 -0
  6. package/build-module/components/navigation/drilldown-item/index.js +49 -0
  7. package/build-module/components/navigation/drilldown-item/index.js.map +7 -0
  8. package/build-module/components/navigation/dropdown-item/index.js +162 -0
  9. package/build-module/components/navigation/dropdown-item/index.js.map +7 -0
  10. package/build-module/components/navigation/index.js +101 -0
  11. package/build-module/components/navigation/index.js.map +7 -0
  12. package/build-module/components/navigation/items.js +60 -0
  13. package/build-module/components/navigation/items.js.map +7 -0
  14. package/build-module/components/navigation/navigation-item/index.js +180 -0
  15. package/build-module/components/navigation/navigation-item/index.js.map +7 -0
  16. package/build-module/components/navigation/navigation-screen/index.js +196 -0
  17. package/build-module/components/navigation/navigation-screen/index.js.map +7 -0
  18. package/build-module/components/navigation/path-matching.js +78 -0
  19. package/build-module/components/navigation/path-matching.js.map +7 -0
  20. package/build-module/components/navigation/router-link-item.js +14 -0
  21. package/build-module/components/navigation/router-link-item.js.map +7 -0
  22. package/build-module/components/navigation/use-sidebar-parent.js +52 -0
  23. package/build-module/components/navigation/use-sidebar-parent.js.map +7 -0
  24. package/build-module/components/root/index.js +115 -0
  25. package/build-module/components/root/index.js.map +7 -0
  26. package/build-module/components/sidebar/index.js +78 -0
  27. package/build-module/components/sidebar/index.js.map +7 -0
  28. package/build-module/components/site-hub/index.js +153 -0
  29. package/build-module/components/site-hub/index.js.map +7 -0
  30. package/build-module/components/site-icon/index.js +115 -0
  31. package/build-module/components/site-icon/index.js.map +7 -0
  32. package/build-module/components/site-icon-link/index.js +101 -0
  33. package/build-module/components/site-icon-link/index.js.map +7 -0
  34. package/build-module/index.js +622 -0
  35. package/build-module/index.js.map +7 -0
  36. package/build-module/lock-unlock.js +11 -0
  37. package/build-module/lock-unlock.js.map +7 -0
  38. package/build-module/store/actions.js +19 -0
  39. package/build-module/store/actions.js.map +7 -0
  40. package/build-module/store/index.js +17 -0
  41. package/build-module/store/index.js.map +7 -0
  42. package/build-module/store/reducer.js +27 -0
  43. package/build-module/store/reducer.js.map +7 -0
  44. package/build-module/store/selectors.js +12 -0
  45. package/build-module/store/selectors.js.map +7 -0
  46. package/build-module/store/types.js +1 -0
  47. package/build-module/store/types.js.map +7 -0
  48. package/build-style/style-rtl.css +612 -0
  49. package/build-style/style.css +612 -0
  50. package/build-types/components/app/index.d.ts +6 -0
  51. package/build-types/components/app/index.d.ts.map +1 -0
  52. package/build-types/components/app/router.d.ts +7 -0
  53. package/build-types/components/app/router.d.ts.map +1 -0
  54. package/build-types/components/navigation/drilldown-item/index.d.ts +34 -0
  55. package/build-types/components/navigation/drilldown-item/index.d.ts.map +1 -0
  56. package/build-types/components/navigation/dropdown-item/index.d.ts +36 -0
  57. package/build-types/components/navigation/dropdown-item/index.d.ts.map +1 -0
  58. package/build-types/components/navigation/index.d.ts +3 -0
  59. package/build-types/components/navigation/index.d.ts.map +1 -0
  60. package/build-types/components/navigation/items.d.ts +16 -0
  61. package/build-types/components/navigation/items.d.ts.map +1 -0
  62. package/build-types/components/navigation/navigation-item/index.d.ts +28 -0
  63. package/build-types/components/navigation/navigation-item/index.d.ts.map +1 -0
  64. package/build-types/components/navigation/navigation-screen/index.d.ts +24 -0
  65. package/build-types/components/navigation/navigation-screen/index.d.ts.map +1 -0
  66. package/build-types/components/navigation/path-matching.d.ts +30 -0
  67. package/build-types/components/navigation/path-matching.d.ts.map +1 -0
  68. package/build-types/components/navigation/router-link-item.d.ts +5 -0
  69. package/build-types/components/navigation/router-link-item.d.ts.map +1 -0
  70. package/build-types/components/navigation/use-sidebar-parent.d.ts +12 -0
  71. package/build-types/components/navigation/use-sidebar-parent.d.ts.map +1 -0
  72. package/build-types/components/root/index.d.ts +3 -0
  73. package/build-types/components/root/index.d.ts.map +1 -0
  74. package/build-types/components/sidebar/index.d.ts +3 -0
  75. package/build-types/components/sidebar/index.d.ts.map +1 -0
  76. package/build-types/components/site-hub/index.d.ts +4 -0
  77. package/build-types/components/site-hub/index.d.ts.map +1 -0
  78. package/build-types/components/site-icon/index.d.ts +9 -0
  79. package/build-types/components/site-icon/index.d.ts.map +1 -0
  80. package/build-types/components/site-icon-link/index.d.ts +8 -0
  81. package/build-types/components/site-icon-link/index.d.ts.map +1 -0
  82. package/build-types/index.d.ts +6 -0
  83. package/build-types/index.d.ts.map +1 -0
  84. package/build-types/lock-unlock.d.ts +2 -0
  85. package/build-types/lock-unlock.d.ts.map +1 -0
  86. package/build-types/store/actions.d.ts +15 -0
  87. package/build-types/store/actions.d.ts.map +1 -0
  88. package/build-types/store/index.d.ts +6 -0
  89. package/build-types/store/index.d.ts.map +1 -0
  90. package/build-types/store/reducer.d.ts +7 -0
  91. package/build-types/store/reducer.d.ts.map +1 -0
  92. package/build-types/store/selectors.d.ts +7 -0
  93. package/build-types/store/selectors.d.ts.map +1 -0
  94. package/build-types/store/types.d.ts +63 -0
  95. package/build-types/store/types.d.ts.map +1 -0
  96. package/package.json +64 -0
  97. package/src/components/app/index.tsx +45 -0
  98. package/src/components/app/router.tsx +198 -0
  99. package/src/components/navigation/drilldown-item/index.tsx +88 -0
  100. package/src/components/navigation/dropdown-item/index.tsx +134 -0
  101. package/src/components/navigation/dropdown-item/style.scss +23 -0
  102. package/src/components/navigation/index.tsx +126 -0
  103. package/src/components/navigation/items.tsx +93 -0
  104. package/src/components/navigation/navigation-item/index.tsx +88 -0
  105. package/src/components/navigation/navigation-item/style.scss +52 -0
  106. package/src/components/navigation/navigation-screen/index.tsx +147 -0
  107. package/src/components/navigation/navigation-screen/style.scss +34 -0
  108. package/src/components/navigation/path-matching.ts +149 -0
  109. package/src/components/navigation/router-link-item.tsx +22 -0
  110. package/src/components/navigation/use-sidebar-parent.ts +77 -0
  111. package/src/components/root/index.tsx +42 -0
  112. package/src/components/root/style.scss +41 -0
  113. package/src/components/sidebar/index.tsx +17 -0
  114. package/src/components/sidebar/style.scss +15 -0
  115. package/src/components/site-hub/index.tsx +67 -0
  116. package/src/components/site-hub/style.scss +54 -0
  117. package/src/components/site-icon/index.tsx +60 -0
  118. package/src/components/site-icon/style.scss +19 -0
  119. package/src/components/site-icon-link/index.tsx +43 -0
  120. package/src/components/site-icon-link/style.scss +24 -0
  121. package/src/index.tsx +5 -0
  122. package/src/lock-unlock.ts +9 -0
  123. package/src/store/actions.ts +23 -0
  124. package/src/store/index.ts +23 -0
  125. package/src/store/reducer.ts +31 -0
  126. package/src/store/selectors.ts +12 -0
  127. package/src/store/types.ts +70 -0
  128. package/src/style.scss +2 -0
  129. package/tsconfig.json +23 -0
  130. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,67 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect, useDispatch } from '@wordpress/data';
5
+ import {
6
+ ExternalLink,
7
+ Button,
8
+ // @ts-ignore
9
+ __experimentalHStack as HStack,
10
+ } from '@wordpress/components';
11
+ import { __ } from '@wordpress/i18n';
12
+ import { store as coreStore } from '@wordpress/core-data';
13
+ import { decodeEntities } from '@wordpress/html-entities';
14
+ import { search } from '@wordpress/icons';
15
+ import { displayShortcut } from '@wordpress/keycodes';
16
+ // @ts-expect-error Commands is not typed properly.
17
+ import { store as commandsStore } from '@wordpress/commands';
18
+ import { filterURLForDisplay } from '@wordpress/url';
19
+ import type { UnstableBase } from '@wordpress/core-data';
20
+
21
+ /**
22
+ * Internal dependencies
23
+ */
24
+ import SiteIconLink from '../site-icon-link';
25
+ import './style.scss';
26
+
27
+ function SiteHub() {
28
+ const { homeUrl, siteTitle } = useSelect( ( select ) => {
29
+ const { getEntityRecord } = select( coreStore );
30
+ const _base = getEntityRecord< UnstableBase >(
31
+ 'root',
32
+ '__unstableBase'
33
+ );
34
+ return {
35
+ homeUrl: _base?.home,
36
+ siteTitle:
37
+ ! _base?.name && !! _base?.url
38
+ ? filterURLForDisplay( _base?.url )
39
+ : _base?.name,
40
+ };
41
+ }, [] );
42
+ const { open: openCommandCenter } = useDispatch( commandsStore );
43
+
44
+ return (
45
+ <div className="boot-site-hub">
46
+ <SiteIconLink to="/" aria-label={ __( 'Go to the Dashboard' ) } />
47
+ <ExternalLink
48
+ href={ homeUrl ?? '/' }
49
+ className="boot-site-hub__title"
50
+ >
51
+ { siteTitle && decodeEntities( siteTitle ) }
52
+ </ExternalLink>
53
+ <HStack className="boot-site-hub__actions">
54
+ <Button
55
+ variant="tertiary"
56
+ icon={ search }
57
+ onClick={ () => openCommandCenter() }
58
+ size="compact"
59
+ label={ __( 'Open command palette' ) }
60
+ shortcut={ displayShortcut.primary( 'k' ) }
61
+ />
62
+ </HStack>
63
+ </div>
64
+ );
65
+ }
66
+
67
+ export default SiteHub;
@@ -0,0 +1,54 @@
1
+ @use "@wordpress/base-styles/variables";
2
+
3
+ .boot-site-hub {
4
+ position: sticky;
5
+ top: 0;
6
+ background-color: var(--wpds-color-bg-surface-neutral-weak, #f0f0f0);
7
+ z-index: 1;
8
+ display: grid;
9
+ grid-template-columns: 60px 1fr auto;
10
+ align-items: center;
11
+ padding-right: variables.$grid-unit-20;
12
+ flex-shrink: 0; // Prevent flex parent from shrinking this element.
13
+ }
14
+
15
+ .boot-site-hub__actions {
16
+ flex-shrink: 0;
17
+ }
18
+
19
+ .boot-site-hub__title {
20
+ color: var(--wpds-color-fg-content-neutral, #1e1e1e);
21
+ font-size: variables.$font-size-medium;
22
+ font-weight: variables.$font-weight-medium;
23
+ overflow: hidden;
24
+ text-overflow: ellipsis;
25
+ white-space: nowrap;
26
+ text-decoration: none;
27
+
28
+ .components-external-link__contents {
29
+ text-decoration: none;
30
+ margin-inline-start: variables.$grid-unit-05;
31
+ }
32
+
33
+ // Show icon on hover
34
+ .components-external-link__icon {
35
+ opacity: 0;
36
+ transition: opacity 0.1s ease-out;
37
+ }
38
+
39
+ &:hover .components-external-link__icon {
40
+ opacity: 1;
41
+ }
42
+
43
+ // Focus styles
44
+ @media not (prefers-reduced-motion) {
45
+ transition: outline 0.1s ease-out;
46
+ }
47
+
48
+ &:focus:not(:active) {
49
+ outline:
50
+ var(--wpds-border-width-focus, 2px) solid
51
+ var(--wpds-color-stroke-focus-brand, #0073aa);
52
+ outline-offset: calc(-1 * var(--wpds-border-width-focus, 2px));
53
+ }
54
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import clsx from 'clsx';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useSelect } from '@wordpress/data';
10
+ import { Icon, wordpress } from '@wordpress/icons';
11
+ import { __ } from '@wordpress/i18n';
12
+ import { store as coreDataStore } from '@wordpress/core-data';
13
+ import type { UnstableBase } from '@wordpress/core-data';
14
+
15
+ /**
16
+ * Internal dependencies
17
+ */
18
+ import './style.scss';
19
+
20
+ function SiteIcon( { className }: { className?: string } ) {
21
+ const { isRequestingSite, siteIconUrl } = useSelect( ( select ) => {
22
+ const { getEntityRecord } = select( coreDataStore );
23
+ const siteData = getEntityRecord< UnstableBase >(
24
+ 'root',
25
+ '__unstableBase',
26
+ undefined
27
+ );
28
+
29
+ return {
30
+ isRequestingSite: ! siteData,
31
+ siteIconUrl: siteData?.site_icon_url,
32
+ };
33
+ }, [] );
34
+
35
+ let icon = null;
36
+
37
+ if ( isRequestingSite && ! siteIconUrl ) {
38
+ icon = <div className="boot-site-icon__image" />;
39
+ } else {
40
+ icon = siteIconUrl ? (
41
+ <img
42
+ className="boot-site-icon__image"
43
+ alt={ __( 'Site Icon' ) }
44
+ src={ siteIconUrl }
45
+ />
46
+ ) : (
47
+ <Icon
48
+ className="boot-site-icon__icon"
49
+ icon={ wordpress }
50
+ size={ 48 }
51
+ />
52
+ );
53
+ }
54
+
55
+ return (
56
+ <div className={ clsx( className, 'boot-site-icon' ) }>{ icon }</div>
57
+ );
58
+ }
59
+
60
+ export default SiteIcon;
@@ -0,0 +1,19 @@
1
+ @use "@wordpress/base-styles/variables";
2
+
3
+ .boot-site-icon {
4
+ display: flex;
5
+ }
6
+
7
+ .boot-site-icon__icon {
8
+ width: variables.$grid-unit-40;
9
+ height: variables.$grid-unit-40;
10
+ color: var(--wpds-color-fg-content-neutral, #1e1e1e);
11
+ }
12
+
13
+ .boot-site-icon__image {
14
+ width: variables.$grid-unit-40;
15
+ height: variables.$grid-unit-40;
16
+ object-fit: cover;
17
+ aspect-ratio: 1 / 1;
18
+ border-radius: var(--wpds-border-radius-medium, 4px);
19
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { Link, useCanGoBack, useRouter } from '@tanstack/react-router';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import SiteIcon from '../site-icon';
10
+ import './style.scss';
11
+
12
+ function SiteIconLink( {
13
+ to,
14
+ isBackButton,
15
+ ...props
16
+ }: {
17
+ to: string;
18
+ 'aria-label': string;
19
+ isBackButton?: boolean;
20
+ } ) {
21
+ const router = useRouter();
22
+ const canGoBack = useCanGoBack();
23
+
24
+ return (
25
+ <Link
26
+ to={ to }
27
+ aria-label={ props[ 'aria-label' ] }
28
+ className="boot-site-icon-link"
29
+ onClick={ ( event ) => {
30
+ // If possible, restore the previous page with
31
+ // filters etc.
32
+ if ( canGoBack && isBackButton ) {
33
+ event.preventDefault();
34
+ router.history.back();
35
+ }
36
+ } }
37
+ >
38
+ <SiteIcon />
39
+ </Link>
40
+ );
41
+ }
42
+
43
+ export default SiteIconLink;
@@ -0,0 +1,24 @@
1
+ @use "@wordpress/base-styles/variables";
2
+
3
+ $header-height: variables.$header-height;
4
+
5
+ .boot-site-icon-link {
6
+ width: $header-height;
7
+ height: $header-height;
8
+ display: inline-flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ background: var(--wpds-color-bg-surface-neutral-weak, #f0f0f0);
12
+ text-decoration: none;
13
+
14
+ @media not (prefers-reduced-motion) {
15
+ transition: outline 0.1s ease-out;
16
+ }
17
+
18
+ &:focus:not(:active) {
19
+ outline:
20
+ var(--wpds-border-width-focus, 2px) solid
21
+ var(--wpds-color-stroke-focus-brand, #0073aa);
22
+ outline-offset: calc(-1 * var(--wpds-border-width-focus, 2px));
23
+ }
24
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import './style.scss';
5
+ export { init } from './components/app';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis';
5
+ export const { lock, unlock } =
6
+ __dangerousOptInToUnstableAPIsOnlyForCoreModules(
7
+ 'I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.',
8
+ '@wordpress/boot'
9
+ );
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { MenuItem, Route } from './types';
5
+
6
+ export function registerMenuItem( id: string, menuItem: MenuItem ) {
7
+ return {
8
+ type: 'REGISTER_MENU_ITEM' as const,
9
+ id,
10
+ menuItem,
11
+ };
12
+ }
13
+
14
+ export function registerRoute( route: Route ) {
15
+ return {
16
+ type: 'REGISTER_ROUTE' as const,
17
+ route,
18
+ };
19
+ }
20
+
21
+ export type Action =
22
+ | ReturnType< typeof registerMenuItem >
23
+ | ReturnType< typeof registerRoute >;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { createReduxStore, register } from '@wordpress/data';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import { reducer } from './reducer';
10
+ import * as actions from './actions';
11
+ import * as selectors from './selectors';
12
+
13
+ const STORE_NAME = 'wordpress/boot';
14
+
15
+ export const store = createReduxStore( STORE_NAME, {
16
+ reducer,
17
+ actions,
18
+ selectors,
19
+ } );
20
+
21
+ register( store );
22
+
23
+ export { STORE_NAME };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { Action } from './actions';
5
+ import type { State } from './types';
6
+
7
+ const initialState: State = {
8
+ menuItems: {},
9
+ routes: [],
10
+ };
11
+
12
+ export function reducer( state: State = initialState, action: Action ): State {
13
+ switch ( action.type ) {
14
+ case 'REGISTER_MENU_ITEM':
15
+ return {
16
+ ...state,
17
+ menuItems: {
18
+ ...state.menuItems,
19
+ [ action.id ]: action.menuItem,
20
+ },
21
+ };
22
+
23
+ case 'REGISTER_ROUTE':
24
+ return {
25
+ ...state,
26
+ routes: [ ...state.routes, action.route ],
27
+ };
28
+ }
29
+
30
+ return state;
31
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { State } from './types';
5
+
6
+ export function getMenuItems( state: State ) {
7
+ return Object.values( state.menuItems );
8
+ }
9
+
10
+ export function getRoutes( state: State ) {
11
+ return state.routes;
12
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { ReactNode, ComponentType } from 'react';
5
+
6
+ /**
7
+ * Icon type supporting multiple formats:
8
+ * - Dashicon strings (e.g., "dashicons-admin-generic")
9
+ * - JSX elements
10
+ * - SVG icons from @wordpress/icons
11
+ * - Data URLs for images
12
+ */
13
+ export type IconType = string | JSX.Element | ReactNode;
14
+
15
+ export interface MenuItem {
16
+ id: string;
17
+ label: string;
18
+ to: string;
19
+ icon?: IconType;
20
+ parent?: string;
21
+ parent_type?: 'drilldown' | 'dropdown';
22
+ }
23
+
24
+ /**
25
+ * Route surfaces exported from content_module.
26
+ * Stage is required, inspector is optional.
27
+ */
28
+ export interface RouteSurfaces {
29
+ stage?: ComponentType;
30
+ inspector?: ComponentType;
31
+ }
32
+
33
+ /**
34
+ * Route loader context containing params and search.
35
+ */
36
+ export interface RouteLoaderContext {
37
+ params: Record< string, string >;
38
+ search: Record< string, unknown >;
39
+ }
40
+
41
+ /**
42
+ * Route configuration interface.
43
+ * Routes specify content_module for surfaces and optionally route_module for lifecycle functions.
44
+ */
45
+ export interface Route {
46
+ /**
47
+ * Route path (e.g., "/post-edit/$postId")
48
+ */
49
+ path: string;
50
+
51
+ /**
52
+ * Module path for lazy loading the route's surfaces (stage, inspector).
53
+ * The module must export: RouteSurfaces (stage and/or inspector components)
54
+ * This enables code splitting for better performance.
55
+ */
56
+ content_module?: string;
57
+
58
+ /**
59
+ * Module path for route lifecycle functions.
60
+ * The module should export a named export `route` containing:
61
+ * - beforeLoad?: Pre-navigation hook (authentication, validation, redirects)
62
+ * - loader?: Data preloading function
63
+ */
64
+ route_module?: string;
65
+ }
66
+
67
+ export interface State {
68
+ menuItems: Record< string, MenuItem >;
69
+ routes: Route[];
70
+ }
package/src/style.scss ADDED
@@ -0,0 +1,2 @@
1
+ @use "@wordpress/theme/src/prebuilt/css/design-tokens.css" as *;
2
+ @use "@wordpress/admin-ui/build-style/style.css" as *;
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig.json",
3
+ "extends": "../../tsconfig.base.json",
4
+ "compilerOptions": {
5
+ "checkJs": false
6
+ },
7
+ "references": [
8
+ { "path": "../admin-ui" },
9
+ { "path": "../components" },
10
+ { "path": "../compose" },
11
+ { "path": "../core-data" },
12
+ { "path": "../data" },
13
+ { "path": "../element" },
14
+ { "path": "../html-entities" },
15
+ { "path": "../i18n" },
16
+ { "path": "../icons" },
17
+ { "path": "../keycodes" },
18
+ { "path": "../primitives" },
19
+ { "path": "../private-apis" },
20
+ { "path": "../theme" },
21
+ { "path": "../url" }
22
+ ]
23
+ }