@docusaurus/theme-classic 3.8.1-canary-6372 → 3.8.1-canary-6374

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.
@@ -25,14 +25,29 @@ import useIsBrowser from '@docusaurus/useIsBrowser';
25
25
  import DocSidebarItems from '@theme/DocSidebarItems';
26
26
  // If we navigate to a category and it becomes active, it should automatically
27
27
  // expand itself
28
- function useAutoExpandActiveCategory({isActive, collapsed, updateCollapsed}) {
28
+ function useAutoExpandActiveCategory({
29
+ isActive,
30
+ collapsed,
31
+ updateCollapsed,
32
+ activePath,
33
+ }) {
29
34
  const wasActive = usePrevious(isActive);
35
+ const previousActivePath = usePrevious(activePath);
30
36
  useEffect(() => {
31
37
  const justBecameActive = isActive && !wasActive;
32
- if (justBecameActive && collapsed) {
38
+ const stillActiveButPathChanged =
39
+ isActive && wasActive && activePath !== previousActivePath;
40
+ if ((justBecameActive || stillActiveButPathChanged) && collapsed) {
33
41
  updateCollapsed(false);
34
42
  }
35
- }, [isActive, wasActive, collapsed, updateCollapsed]);
43
+ }, [
44
+ isActive,
45
+ wasActive,
46
+ collapsed,
47
+ updateCollapsed,
48
+ activePath,
49
+ previousActivePath,
50
+ ]);
36
51
  }
37
52
  /**
38
53
  * When a collapsible category has no link, we still link it to its first child
@@ -118,7 +133,12 @@ export default function DocSidebarItemCategory({
118
133
  setExpandedItem(toCollapsed ? null : index);
119
134
  setCollapsed(toCollapsed);
120
135
  };
121
- useAutoExpandActiveCategory({isActive, collapsed, updateCollapsed});
136
+ useAutoExpandActiveCategory({
137
+ isActive,
138
+ collapsed,
139
+ updateCollapsed,
140
+ activePath,
141
+ });
122
142
  useEffect(() => {
123
143
  if (
124
144
  collapsible &&
@@ -8,34 +8,79 @@ import React from 'react';
8
8
  import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
9
9
  import {useAlternatePageUtils} from '@docusaurus/theme-common/internal';
10
10
  import {translate} from '@docusaurus/Translate';
11
- import {useHistorySelector} from '@docusaurus/theme-common';
11
+ import {mergeSearchStrings, useHistorySelector} from '@docusaurus/theme-common';
12
12
  import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
13
13
  import IconLanguage from '@theme/Icon/Language';
14
14
  import styles from './styles.module.css';
15
+ function useLocaleDropdownUtils() {
16
+ const {
17
+ siteConfig,
18
+ i18n: {localeConfigs},
19
+ } = useDocusaurusContext();
20
+ const alternatePageUtils = useAlternatePageUtils();
21
+ const search = useHistorySelector((history) => history.location.search);
22
+ const hash = useHistorySelector((history) => history.location.hash);
23
+ const getLocaleConfig = (locale) => {
24
+ const localeConfig = localeConfigs[locale];
25
+ if (!localeConfig) {
26
+ throw new Error(
27
+ `Docusaurus bug, no locale config found for locale=${locale}`,
28
+ );
29
+ }
30
+ return localeConfig;
31
+ };
32
+ const getBaseURLForLocale = (locale) => {
33
+ const localeConfig = getLocaleConfig(locale);
34
+ const isSameDomain = localeConfig.url === siteConfig.url;
35
+ if (isSameDomain) {
36
+ // Shorter paths if localized sites are hosted on the same domain
37
+ // This reduces HTML size a bit
38
+ return `pathname://${alternatePageUtils.createUrl({
39
+ locale,
40
+ fullyQualified: false,
41
+ })}`;
42
+ }
43
+ return alternatePageUtils.createUrl({
44
+ locale,
45
+ fullyQualified: true,
46
+ });
47
+ };
48
+ return {
49
+ getURL: (locale, options) => {
50
+ // We have 2 query strings because
51
+ // - there's the current one
52
+ // - there's one user can provide through navbar config
53
+ // see https://github.com/facebook/docusaurus/pull/8915
54
+ const finalSearch = mergeSearchStrings(
55
+ [search, options.queryString],
56
+ 'append',
57
+ );
58
+ return `${getBaseURLForLocale(locale)}${finalSearch}${hash}`;
59
+ },
60
+ getLabel: (locale) => {
61
+ return getLocaleConfig(locale).label;
62
+ },
63
+ getLang: (locale) => {
64
+ return getLocaleConfig(locale).htmlLang;
65
+ },
66
+ };
67
+ }
15
68
  export default function LocaleDropdownNavbarItem({
16
69
  mobile,
17
70
  dropdownItemsBefore,
18
71
  dropdownItemsAfter,
19
- queryString = '',
72
+ queryString,
20
73
  ...props
21
74
  }) {
75
+ const utils = useLocaleDropdownUtils();
22
76
  const {
23
- i18n: {currentLocale, locales, localeConfigs},
77
+ i18n: {currentLocale, locales},
24
78
  } = useDocusaurusContext();
25
- const alternatePageUtils = useAlternatePageUtils();
26
- const search = useHistorySelector((history) => history.location.search);
27
- const hash = useHistorySelector((history) => history.location.hash);
28
79
  const localeItems = locales.map((locale) => {
29
- const baseTo = `pathname://${alternatePageUtils.createUrl({
30
- locale,
31
- fullyQualified: false,
32
- })}`;
33
- // preserve ?search#hash suffix on locale switches
34
- const to = `${baseTo}${search}${hash}${queryString}`;
35
80
  return {
36
- label: localeConfigs[locale].label,
37
- lang: localeConfigs[locale].htmlLang,
38
- to,
81
+ label: utils.getLabel(locale),
82
+ lang: utils.getLang(locale),
83
+ to: utils.getURL(locale, {queryString}),
39
84
  target: '_self',
40
85
  autoAddBaseUrl: false,
41
86
  className:
@@ -58,7 +103,7 @@ export default function LocaleDropdownNavbarItem({
58
103
  id: 'theme.navbar.mobileLanguageDropdown.label',
59
104
  description: 'The label for the mobile language switcher dropdown',
60
105
  })
61
- : localeConfigs[currentLocale].label;
106
+ : utils.getLabel(currentLocale);
62
107
  return (
63
108
  <DropdownNavbarItem
64
109
  {...props}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/theme-classic",
3
- "version": "3.8.1-canary-6372",
3
+ "version": "3.8.1-canary-6374",
4
4
  "description": "Classic theme for Docusaurus",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/theme-classic.d.ts",
@@ -20,19 +20,19 @@
20
20
  "copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
21
21
  },
22
22
  "dependencies": {
23
- "@docusaurus/core": "3.8.1-canary-6372",
24
- "@docusaurus/logger": "3.8.1-canary-6372",
25
- "@docusaurus/mdx-loader": "3.8.1-canary-6372",
26
- "@docusaurus/module-type-aliases": "3.8.1-canary-6372",
27
- "@docusaurus/plugin-content-blog": "3.8.1-canary-6372",
28
- "@docusaurus/plugin-content-docs": "3.8.1-canary-6372",
29
- "@docusaurus/plugin-content-pages": "3.8.1-canary-6372",
30
- "@docusaurus/theme-common": "3.8.1-canary-6372",
31
- "@docusaurus/theme-translations": "3.8.1-canary-6372",
32
- "@docusaurus/types": "3.8.1-canary-6372",
33
- "@docusaurus/utils": "3.8.1-canary-6372",
34
- "@docusaurus/utils-common": "3.8.1-canary-6372",
35
- "@docusaurus/utils-validation": "3.8.1-canary-6372",
23
+ "@docusaurus/core": "3.8.1-canary-6374",
24
+ "@docusaurus/logger": "3.8.1-canary-6374",
25
+ "@docusaurus/mdx-loader": "3.8.1-canary-6374",
26
+ "@docusaurus/module-type-aliases": "3.8.1-canary-6374",
27
+ "@docusaurus/plugin-content-blog": "3.8.1-canary-6374",
28
+ "@docusaurus/plugin-content-docs": "3.8.1-canary-6374",
29
+ "@docusaurus/plugin-content-pages": "3.8.1-canary-6374",
30
+ "@docusaurus/theme-common": "3.8.1-canary-6374",
31
+ "@docusaurus/theme-translations": "3.8.1-canary-6374",
32
+ "@docusaurus/types": "3.8.1-canary-6374",
33
+ "@docusaurus/utils": "3.8.1-canary-6374",
34
+ "@docusaurus/utils-common": "3.8.1-canary-6374",
35
+ "@docusaurus/utils-validation": "3.8.1-canary-6374",
36
36
  "@mdx-js/react": "^3.0.0",
37
37
  "clsx": "^2.0.0",
38
38
  "copy-text-to-clipboard": "^3.2.0",
@@ -62,5 +62,5 @@
62
62
  "engines": {
63
63
  "node": ">=18.0"
64
64
  },
65
- "gitHead": "0229ae8aadbcfbebd1f49b3bdd174bea21ae93d4"
65
+ "gitHead": "d7c2ad4c6a14ff1185b4ee7bef89cd56c15d3869"
66
66
  }
@@ -37,18 +37,30 @@ function useAutoExpandActiveCategory({
37
37
  isActive,
38
38
  collapsed,
39
39
  updateCollapsed,
40
+ activePath,
40
41
  }: {
41
42
  isActive: boolean;
42
43
  collapsed: boolean;
43
44
  updateCollapsed: (b: boolean) => void;
45
+ activePath: string;
44
46
  }) {
45
47
  const wasActive = usePrevious(isActive);
48
+ const previousActivePath = usePrevious(activePath);
46
49
  useEffect(() => {
47
50
  const justBecameActive = isActive && !wasActive;
48
- if (justBecameActive && collapsed) {
51
+ const stillActiveButPathChanged =
52
+ isActive && wasActive && activePath !== previousActivePath;
53
+ if ((justBecameActive || stillActiveButPathChanged) && collapsed) {
49
54
  updateCollapsed(false);
50
55
  }
51
- }, [isActive, wasActive, collapsed, updateCollapsed]);
56
+ }, [
57
+ isActive,
58
+ wasActive,
59
+ collapsed,
60
+ updateCollapsed,
61
+ activePath,
62
+ previousActivePath,
63
+ ]);
52
64
  }
53
65
 
54
66
  /**
@@ -150,7 +162,12 @@ export default function DocSidebarItemCategory({
150
162
  setExpandedItem(toCollapsed ? null : index);
151
163
  setCollapsed(toCollapsed);
152
164
  };
153
- useAutoExpandActiveCategory({isActive, collapsed, updateCollapsed});
165
+ useAutoExpandActiveCategory({
166
+ isActive,
167
+ collapsed,
168
+ updateCollapsed,
169
+ activePath,
170
+ });
154
171
  useEffect(() => {
155
172
  if (
156
173
  collapsible &&
@@ -9,7 +9,7 @@ import React, {type ReactNode} from 'react';
9
9
  import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
10
10
  import {useAlternatePageUtils} from '@docusaurus/theme-common/internal';
11
11
  import {translate} from '@docusaurus/Translate';
12
- import {useHistorySelector} from '@docusaurus/theme-common';
12
+ import {mergeSearchStrings, useHistorySelector} from '@docusaurus/theme-common';
13
13
  import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
14
14
  import IconLanguage from '@theme/Icon/Language';
15
15
  import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem';
@@ -17,31 +17,80 @@ import type {Props} from '@theme/NavbarItem/LocaleDropdownNavbarItem';
17
17
 
18
18
  import styles from './styles.module.css';
19
19
 
20
+ function useLocaleDropdownUtils() {
21
+ const {
22
+ siteConfig,
23
+ i18n: {localeConfigs},
24
+ } = useDocusaurusContext();
25
+ const alternatePageUtils = useAlternatePageUtils();
26
+ const search = useHistorySelector((history) => history.location.search);
27
+ const hash = useHistorySelector((history) => history.location.hash);
28
+
29
+ const getLocaleConfig = (locale: string) => {
30
+ const localeConfig = localeConfigs[locale];
31
+ if (!localeConfig) {
32
+ throw new Error(
33
+ `Docusaurus bug, no locale config found for locale=${locale}`,
34
+ );
35
+ }
36
+ return localeConfig;
37
+ };
38
+
39
+ const getBaseURLForLocale = (locale: string) => {
40
+ const localeConfig = getLocaleConfig(locale);
41
+ const isSameDomain = localeConfig.url === siteConfig.url;
42
+ if (isSameDomain) {
43
+ // Shorter paths if localized sites are hosted on the same domain
44
+ // This reduces HTML size a bit
45
+ return `pathname://${alternatePageUtils.createUrl({
46
+ locale,
47
+ fullyQualified: false,
48
+ })}`;
49
+ }
50
+ return alternatePageUtils.createUrl({
51
+ locale,
52
+ fullyQualified: true,
53
+ });
54
+ };
55
+
56
+ return {
57
+ getURL: (locale: string, options: {queryString: string | undefined}) => {
58
+ // We have 2 query strings because
59
+ // - there's the current one
60
+ // - there's one user can provide through navbar config
61
+ // see https://github.com/facebook/docusaurus/pull/8915
62
+ const finalSearch = mergeSearchStrings(
63
+ [search, options.queryString],
64
+ 'append',
65
+ );
66
+ return `${getBaseURLForLocale(locale)}${finalSearch}${hash}`;
67
+ },
68
+ getLabel: (locale: string) => {
69
+ return getLocaleConfig(locale).label;
70
+ },
71
+ getLang: (locale: string) => {
72
+ return getLocaleConfig(locale).htmlLang;
73
+ },
74
+ };
75
+ }
76
+
20
77
  export default function LocaleDropdownNavbarItem({
21
78
  mobile,
22
79
  dropdownItemsBefore,
23
80
  dropdownItemsAfter,
24
- queryString = '',
81
+ queryString,
25
82
  ...props
26
83
  }: Props): ReactNode {
84
+ const utils = useLocaleDropdownUtils();
85
+
27
86
  const {
28
- i18n: {currentLocale, locales, localeConfigs},
87
+ i18n: {currentLocale, locales},
29
88
  } = useDocusaurusContext();
30
- const alternatePageUtils = useAlternatePageUtils();
31
- const search = useHistorySelector((history) => history.location.search);
32
- const hash = useHistorySelector((history) => history.location.hash);
33
-
34
89
  const localeItems = locales.map((locale): LinkLikeNavbarItemProps => {
35
- const baseTo = `pathname://${alternatePageUtils.createUrl({
36
- locale,
37
- fullyQualified: false,
38
- })}`;
39
- // preserve ?search#hash suffix on locale switches
40
- const to = `${baseTo}${search}${hash}${queryString}`;
41
90
  return {
42
- label: localeConfigs[locale]!.label,
43
- lang: localeConfigs[locale]!.htmlLang,
44
- to,
91
+ label: utils.getLabel(locale),
92
+ lang: utils.getLang(locale),
93
+ to: utils.getURL(locale, {queryString}),
45
94
  target: '_self',
46
95
  autoAddBaseUrl: false,
47
96
  className:
@@ -66,7 +115,7 @@ export default function LocaleDropdownNavbarItem({
66
115
  id: 'theme.navbar.mobileLanguageDropdown.label',
67
116
  description: 'The label for the mobile language switcher dropdown',
68
117
  })
69
- : localeConfigs[currentLocale]!.label;
118
+ : utils.getLabel(currentLocale);
70
119
 
71
120
  return (
72
121
  <DropdownNavbarItem