Просмотр исходного кода

Merge branch 'supprt/correspond-with-forms-breaking-changes' into support/129013-remove-droped-classes

soumaeda 2 лет назад
Родитель
Сommit
0a198005d2
86 измененных файлов с 601 добавлено и 552 удалено
  1. 12 12
      apps/app/src/components/Admin/App/AppSetting.jsx
  2. 3 3
      apps/app/src/components/Admin/App/FileUploadSetting.tsx
  3. 3 8
      apps/app/src/components/Admin/App/MailSetting.tsx
  4. 6 6
      apps/app/src/components/Admin/App/QuestionnaireSettings.tsx
  5. 3 3
      apps/app/src/components/Admin/Customize/CustomizeFunctionOption.tsx
  6. 6 6
      apps/app/src/components/Admin/Customize/CustomizeLogoSetting.tsx
  7. 6 6
      apps/app/src/components/Admin/Customize/CustomizeSidebarSetting.tsx
  8. 4 4
      apps/app/src/components/Admin/ExportArchiveData/SelectCollectionsModal.tsx
  9. 21 21
      apps/app/src/components/Admin/ImportData/GrowiArchive/ImportCollectionConfigurationModal.jsx
  10. 3 3
      apps/app/src/components/Admin/ImportData/GrowiArchive/ImportCollectionItem.jsx
  11. 0 1
      apps/app/src/components/Admin/ImportData/GrowiArchive/UploadForm.jsx
  12. 3 3
      apps/app/src/components/Admin/LegacySlackIntegration/SlackConfiguration.jsx
  13. 3 3
      apps/app/src/components/Admin/MarkdownSetting/IndentForm.tsx
  14. 6 6
      apps/app/src/components/Admin/MarkdownSetting/LineBreakForm.jsx
  15. 9 9
      apps/app/src/components/Admin/MarkdownSetting/XssForm.jsx
  16. 6 6
      apps/app/src/components/Admin/Notification/GlobalNotification.jsx
  17. 3 3
      apps/app/src/components/Admin/Notification/GlobalNotificationList.jsx
  18. 7 7
      apps/app/src/components/Admin/Notification/ManageGlobalNotification.tsx
  19. 3 3
      apps/app/src/components/Admin/Notification/TriggerEventCheckBox.jsx
  20. 6 6
      apps/app/src/components/Admin/Security/GitHubSecuritySettingContents.jsx
  21. 6 6
      apps/app/src/components/Admin/Security/GoogleSecuritySettingContents.jsx
  22. 6 6
      apps/app/src/components/Admin/Security/LdapSecuritySettingContents.jsx
  23. 9 9
      apps/app/src/components/Admin/Security/LocalSecuritySettingContents.jsx
  24. 9 9
      apps/app/src/components/Admin/Security/OidcSecuritySettingContents.jsx
  25. 9 9
      apps/app/src/components/Admin/Security/SamlSecuritySettingContents.jsx
  26. 9 9
      apps/app/src/components/Admin/Security/SecuritySetting.jsx
  27. 3 3
      apps/app/src/components/Admin/Security/ShareLinkSetting.tsx
  28. 1 1
      apps/app/src/components/Admin/SlackIntegration/ManageCommandsProcess.jsx
  29. 2 2
      apps/app/src/components/Admin/SlackIntegration/ManageCommandsProcessWithoutProxy.jsx
  30. 4 3
      apps/app/src/components/Admin/SlackIntegration/SlackAppIntegrationControl.tsx
  31. 4 4
      apps/app/src/components/Admin/UserGroupDetail/CheckBoxForSerchUserOption.jsx
  32. 4 4
      apps/app/src/components/Admin/UserGroupDetail/RadioButtonForSerchUserOption.jsx
  33. 3 3
      apps/app/src/components/Admin/UserGroupDetail/UpdateParentConfirmModal.tsx
  34. 3 3
      apps/app/src/components/Admin/UserManagement.tsx
  35. 3 3
      apps/app/src/components/Admin/Users/UserInviteModal.jsx
  36. 6 2
      apps/app/src/components/Common/ImageCropModal.tsx
  37. 1 1
      apps/app/src/components/Layout/BasicLayout.tsx
  38. 9 9
      apps/app/src/components/Me/BasicInfoSettings.tsx
  39. 3 3
      apps/app/src/components/Me/InAppNotificationSettings.tsx
  40. 3 3
      apps/app/src/components/Me/OtherSettings.tsx
  41. 6 6
      apps/app/src/components/Me/ProfileImageSettings.tsx
  42. 3 3
      apps/app/src/components/Navbar/SubNavButtons.tsx
  43. 3 3
      apps/app/src/components/Page/CopyDropdown.jsx
  44. 9 9
      apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLinkForm.tsx
  45. 9 9
      apps/app/src/components/PageAlert/FixPageGrantAlert.tsx
  46. 6 6
      apps/app/src/components/PageDeleteModal.tsx
  47. 6 6
      apps/app/src/components/PageDuplicateModal.tsx
  48. 3 3
      apps/app/src/components/PageEditor/GridEditModal.jsx
  49. 6 6
      apps/app/src/components/PageEditor/LinkEditModal.tsx
  50. 66 57
      apps/app/src/components/PageEditor/PageEditor.tsx
  51. 6 6
      apps/app/src/components/PageHistory/PageRevisionTable.tsx
  52. 12 12
      apps/app/src/components/PageRenameModal.tsx
  53. 1 1
      apps/app/src/components/PrivateLegacyPages.tsx
  54. 3 3
      apps/app/src/components/PrivateLegacyPagesMigrationModal.tsx
  55. 3 3
      apps/app/src/components/PutbackPageModal.jsx
  56. 1 1
      apps/app/src/components/SearchPage.tsx
  57. 6 6
      apps/app/src/components/SearchPage/SearchControl.tsx
  58. 1 1
      apps/app/src/components/SearchPage/SearchPageBase.tsx
  59. 1 3
      apps/app/src/components/SearchPage/SearchResultContent.tsx
  60. 9 9
      apps/app/src/components/Sidebar/AppearanceModeDropdown.tsx
  61. 2 2
      apps/app/src/components/Sidebar/RecentChanges/RecentChangesSubstance.module.scss
  62. 3 3
      apps/app/src/components/Sidebar/RecentChanges/RecentChangesSubstance.tsx
  63. 2 2
      apps/app/src/components/SlackNotification.module.scss
  64. 3 3
      apps/app/src/components/SlackNotification.tsx
  65. 3 3
      apps/app/src/components/TemplateTab.tsx
  66. 6 0
      apps/app/src/stores/use-static-swr.ts
  67. 0 35
      apps/app/src/stores/use-static-swr.tsx
  68. 42 42
      apps/app/src/styles/atoms/_custom_control.scss
  69. 4 4
      apps/app/src/styles/theme/_apply-colors-dark.scss
  70. 2 2
      apps/app/src/styles/theme/_apply-colors-light.scss
  71. 6 6
      apps/app/src/styles/theme/_reboot-bootstrap-theme-colors.scss
  72. 5 5
      apps/app/src/styles/theme/apply-colors.scss
  73. 3 3
      packages/core/scss/bootstrap/_override.scss
  74. 7 7
      packages/core/scss/bootstrap/_variables.scss
  75. 4 1
      packages/core/scss/placeholders/_flex-expand.scss
  76. 1 0
      packages/core/src/swr/index.ts
  77. 7 5
      packages/core/src/swr/use-swr-static.ts
  78. 2 4
      packages/editor/src/components/playground/Playground.tsx
  79. 4 14
      packages/editor/src/components/playground/PlaygroundController.tsx
  80. 1 0
      packages/editor/src/index.ts
  81. 0 42
      packages/editor/src/services/codemirror-editor.ts
  82. 1 0
      packages/editor/src/services/codemirror-editor/index.ts
  83. 11 0
      packages/editor/src/services/codemirror-editor/interfaces/react-codemirror.ts
  84. 70 0
      packages/editor/src/services/codemirror-editor/use-codemirror-editor.ts
  85. 29 5
      packages/editor/src/stores/codemirror-editor.ts
  86. 13 0
      turbo.json

+ 12 - 12
apps/app/src/components/Admin/App/AppSetting.jsx

@@ -83,11 +83,11 @@ const AppSetting = (props) => {
               const fixedT = i18n.getFixedT(locale, 'admin');
 
               return (
-                <div key={locale} className="custom-control custom-radio custom-control-inline">
+                <div key={locale} className="form-check form-check-inline">
                   <input
                     type="radio"
                     id={`radioLang${locale}`}
-                    className="custom-control-input"
+                    className="form-check-input"
                     name="globalLang"
                     value={locale}
                     checked={adminAppContainer.state.globalLang === locale}
@@ -95,7 +95,7 @@ const AppSetting = (props) => {
                       adminAppContainer.changeGlobalLang(e.target.value);
                     }}
                   />
-                  <label className="form-label custom-control-label" htmlFor={`radioLang${locale}`}>{fixedT('meta.display_name')}</label>
+                  <label className="form-label form-check-label" htmlFor={`radioLang${locale}`}>{fixedT('meta.display_name')}</label>
                 </div>
               );
             })
@@ -111,28 +111,28 @@ const AppSetting = (props) => {
         </label>
         <div className="col-md-6 py-2">
 
-          <div className="custom-control custom-radio custom-control-inline">
+          <div className="form-check form-check-inline">
             <input
               type="radio"
               id="radio-email-show"
-              className="custom-control-input"
+              className="form-check-input"
               name="mailVisibility"
               checked={adminAppContainer.state.isEmailPublishedForNewUser === true}
               onChange={() => { adminAppContainer.changeIsEmailPublishedForNewUserShow(true) }}
             />
-            <label className="form-label custom-control-label" htmlFor="radio-email-show">{t('commons:Show')}</label>
+            <label className="form-label form-check-label" htmlFor="radio-email-show">{t('commons:Show')}</label>
           </div>
 
-          <div className="custom-control custom-radio custom-control-inline">
+          <div className="form-check form-check-inline">
             <input
               type="radio"
               id="radio-email-hide"
-              className="custom-control-input"
+              className="form-check-input"
               name="mailVisibility"
               checked={adminAppContainer.state.isEmailPublishedForNewUser === false}
               onChange={() => { adminAppContainer.changeIsEmailPublishedForNewUserShow(false) }}
             />
-            <label className="form-label custom-control-label" htmlFor="radio-email-hide">{t('commons:Hide')}</label>
+            <label className="form-label form-check-label" htmlFor="radio-email-hide">{t('commons:Hide')}</label>
           </div>
 
         </div>
@@ -145,11 +145,11 @@ const AppSetting = (props) => {
           {/* {t('admin:app_setting.file_uploading')} */}
         </label>
         <div className="col-md-6">
-          <div className="custom-control custom-checkbox custom-checkbox-info">
+          <div className="form-check form-check-info">
             <input
               type="checkbox"
               id="cbFileUpload"
-              className="custom-control-input"
+              className="form-check-input"
               name="fileUpload"
               checked={adminAppContainer.state.fileUpload}
               onChange={(e) => {
@@ -157,7 +157,7 @@ const AppSetting = (props) => {
               }}
             />
             <label
-              className="custom-control-label form-label"
+              className="form-label form-check-label"
               htmlFor="cbFileUpload"
             >
               {t('admin:app_setting.enable_files_except_image')}

+ 3 - 3
apps/app/src/components/Admin/App/FileUploadSetting.tsx

@@ -45,17 +45,17 @@ export const FileUploadSettingMolecule = React.memo((props: FileUploadSettingMol
         <div className="col-md-6 py-2">
           {fileUploadTypes.map((type) => {
             return (
-              <div key={type} className="custom-control custom-radio custom-control-inline">
+              <div key={type} className="form-check form-check-inline">
                 <input
                   type="radio"
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="file-upload-type"
                   id={`file-upload-type-radio-${type}`}
                   checked={props.fileUploadType === type}
                   disabled={props.isFixedFileUploadByEnvVar}
                   onChange={(e) => { props?.onChangeFileUploadType(e, type) }}
                 />
-                <label className="form-label custom-control-label" htmlFor={`file-upload-type-radio-${type}`}>{t(`admin:app_setting.${type}_label`)}</label>
+                <label className="form-label form-check-label" htmlFor={`file-upload-type-radio-${type}`}>{t(`admin:app_setting.${type}_label`)}</label>
               </div>
             );
           })}

+ 3 - 8
apps/app/src/components/Admin/App/MailSetting.tsx

@@ -69,10 +69,10 @@ const MailSetting = (props: Props) => {
         <div className="col-md-6 py-2">
           {transmissionMethods.map((method) => {
             return (
-              <div key={method} className="custom-control custom-radio custom-control-inline">
+              <div key={method} className="form-check form-check-inline">
                 <input
                   type="radio"
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="transmission-method"
                   id={`transmission-method-radio-${method}`}
                   checked={adminAppContainer.state.transmissionMethod === method}
@@ -80,12 +80,7 @@ const MailSetting = (props: Props) => {
                     adminAppContainer.changeTransmissionMethod(method);
                   }}
                 />
-                <label
-                  className="form-label custom-control-label"
-                  htmlFor={`transmission-method-radio-${method}`}
-                >
-                  {t(`admin:app_setting.${method}_label`)}
-                </label>
+                <label className="form-label form-check-label" htmlFor={`transmission-method-radio-${method}`}>{t(`admin:app_setting.${method}_label`)}</label>
               </div>
             );
           })}

+ 6 - 6
apps/app/src/components/Admin/App/QuestionnaireSettings.tsx

@@ -72,31 +72,31 @@ const QuestionnaireSettings = (): JSX.Element => {
       {!isLoading && (
         <>
           <div className="row my-3">
-            <div className="custom-control custom-switch custom-checkbox-info col-md-5 offset-md-5">
+            <div className="form-check form-switch form-check-info col-md-5 offset-md-5">
               <input
                 type="checkbox"
-                className="custom-control-input"
+                className="form-check-input"
                 id="isQuestionnaireEnabled"
                 checked={isQuestionnaireEnabled}
                 onChange={onChangeIsQuestionnaireEnabledHandler}
               />
-              <label className="form-label custom-control-label" htmlFor="isQuestionnaireEnabled">
+              <label className="form-label form-check-label" htmlFor="isQuestionnaireEnabled">
                 {t('app_setting.enable_questionnaire')}
               </label>
             </div>
           </div>
 
           <div className="row my-4">
-            <div className="custom-control custom-checkbox custom-checkbox-info col-md-5 offset-md-5">
+            <div className="form-check form-check-info col-md-5 offset-md-5">
               <input
                 type="checkbox"
-                className="custom-control-input"
+                className="form-check-input"
                 id="isAppSiteUrlHashed"
                 checked={isAppSiteUrlHashed}
                 onChange={onChangeisAppSiteUrlHashedHandler}
                 disabled={!isQuestionnaireEnabled}
               />
-              <label className="form-label custom-control-label" htmlFor="isAppSiteUrlHashed">
+              <label className="form-label form-check-label" htmlFor="isAppSiteUrlHashed">
                 {t('app_setting.anonymize_app_site_url')}
               </label>
               <p className="form-text text-muted small">

+ 3 - 3
apps/app/src/components/Admin/Customize/CustomizeFunctionOption.tsx

@@ -16,15 +16,15 @@ const CustomizeFunctionOption = (props: Props): JSX.Element => {
 
   return (
     <React.Fragment>
-      <div className="custom-control custom-checkbox custom-checkbox-success">
+      <div className="form-check form-check-success">
         <input
-          className="custom-control-input"
+          className="form-check-input"
           type="checkbox"
           id={optionId}
           checked={isChecked}
           onChange={onChecked}
         />
-        <label className="form-label custom-control-label" htmlFor={optionId}>
+        <label className="form-label form-check-label" htmlFor={optionId}>
           <strong>{label}</strong>
         </label>
       </div>

+ 6 - 6
apps/app/src/components/Admin/Customize/CustomizeLogoSetting.tsx

@@ -83,17 +83,17 @@ const CustomizeLogoSetting = (): JSX.Element => {
             <div className="row">
               <div className="col-md-6 col-12 mb-3 mb-md-0">
                 <h4>
-                  <div className="custom-control custom-radio radio-primary">
+                  <div className="form-check radio-primary">
                     <input
                       type="radio"
                       id="radioDefaultLogo"
-                      className="custom-control-input"
+                      className="form-check-input"
                       form="formImageType"
                       name="imagetypeForm[isDefaultLogo]"
                       checked={isDefaultLogoSelected}
                       onChange={() => { setIsDefaultLogoSelected(true) }}
                     />
-                    <label className="custom-control-label" htmlFor="radioDefaultLogo">
+                    <label className="form-check-label" htmlFor="radioDefaultLogo">
                       {t('admin:customize_settings.default_logo')}
                     </label>
                   </div>
@@ -102,17 +102,17 @@ const CustomizeLogoSetting = (): JSX.Element => {
               </div>
               <div className="col-md-6 col-12">
                 <h4>
-                  <div className="custom-control custom-radio radio-primary">
+                  <div className="form-check radio-primary">
                     <input
                       type="radio"
                       id="radioUploadLogo"
-                      className="custom-control-input"
+                      className="form-check-input"
                       form="formImageType"
                       name="imagetypeForm[isDefaultLogo]"
                       checked={!isDefaultLogoSelected}
                       onChange={() => { setIsDefaultLogoSelected(false) }}
                     />
-                    <label className="custom-control-label" htmlFor="radioUploadLogo">
+                    <label className="form-check-label" htmlFor="radioUploadLogo">
                       { t('admin:customize_settings.upload_logo') }
                     </label>
                   </div>

+ 6 - 6
apps/app/src/components/Admin/Customize/CustomizeSidebarSetting.tsx

@@ -73,31 +73,31 @@ const CustomizeSidebarsetting = (): JSX.Element => {
           </Card>
 
           <div className="px-3">
-            <div className="custom-control custom-radio my-3">
+            <div className="form-check my-3">
               <input
                 type="radio"
                 id="is-open"
-                className="custom-control-input"
+                className="form-check-input"
                 name="mailVisibility"
                 checked={isSidebarDrawerMode === false && isSidebarClosedAtDockMode === false}
                 disabled={isSidebarDrawerMode}
                 onChange={() => setIsSidebarClosedAtDockMode(false)}
               />
-              <label className="form-label custom-control-label" htmlFor="is-open">
+              <label className="form-label form-check-label" htmlFor="is-open">
                 {t('customize_settings.default_sidebar_mode.dock_mode_default_open')}
               </label>
             </div>
-            <div className="custom-control custom-radio my-3">
+            <div className="form-check my-3">
               <input
                 type="radio"
                 id="is-closed"
-                className="custom-control-input"
+                className="form-check-input"
                 name="mailVisibility"
                 checked={isSidebarDrawerMode === false && isSidebarClosedAtDockMode === true}
                 disabled={isSidebarDrawerMode}
                 onChange={() => setIsSidebarClosedAtDockMode(true)}
               />
-              <label className="form-label custom-control-label" htmlFor="is-closed">
+              <label className="form-label form-check-label" htmlFor="is-closed">
                 {t('customize_settings.default_sidebar_mode.dock_mode_default_close')}
               </label>
             </div>

+ 4 - 4
apps/app/src/components/Admin/ExportArchiveData/SelectCollectionsModal.tsx

@@ -107,24 +107,24 @@ const SelectCollectionsModal = (props: Props): JSX.Element => {
   }, [selectedCollections, t]);
 
   const renderCheckboxes = useCallback((collectionNames, color?) => {
-    const checkboxColor = color ? `custom-checkbox-${color}` : 'custom-checkbox-info';
+    const checkboxColor = color ? `form-check-${color}` : 'form-check-info';
 
     return (
-      <div className={`custom-control custom-checkbox ${checkboxColor}`}>
+      <div className={`form-check ${checkboxColor}`}>
         <div className="row">
           {collectionNames.map((collectionName) => {
             return (
               <div className="col-sm-6 my-1" key={collectionName}>
                 <input
                   type="checkbox"
-                  className="custom-control-input"
+                  className="form-check-input"
                   id={collectionName}
                   name={collectionName}
                   value={collectionName}
                   checked={selectedCollections.has(collectionName)}
                   onChange={toggleCheckbox}
                 />
-                <label className="form-label text-capitalize custom-control-label ml-3" htmlFor={collectionName}>
+                <label className="form-label text-capitalize form-check-label ml-3" htmlFor={collectionName}>
                   {collectionName}
                 </label>
               </div>

+ 21 - 21
apps/app/src/components/Admin/ImportData/GrowiArchive/ImportCollectionConfigurationModal.jsx

@@ -66,28 +66,28 @@ class ImportCollectionConfigurationModal extends React.Component {
     /* eslint-disable react/no-unescaped-entities */
     return (
       <>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt4"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.isOverwriteAuthorWithCurrentUser || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ isOverwriteAuthorWithCurrentUser: !option.isOverwriteAuthorWithCurrentUser })}
           />
-          <label htmlFor="cbOpt4" className="form-label custom-control-label">
+          <label htmlFor="cbOpt4" className="form-label form-check-label">
             {t(`${translationBase}.overwrite_author.label`)}
             <p className="form-text text-muted mt-0" dangerouslySetInnerHTML={{ __html: t(`${translationBase}.overwrite_author.desc`) }} />
           </label>
         </div>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt1"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.makePublicForGrant2 || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ makePublicForGrant2: !option.makePublicForGrant2 })}
           />
-          <label htmlFor="cbOpt1" className="form-label custom-control-label">
+          <label htmlFor="cbOpt1" className="form-label form-check-label">
             {t(`${translationBase}.set_public_to_page.label`, { from: t('Anyone with the link') })}
             <p
               className="form-text text-muted mt-0"
@@ -95,15 +95,15 @@ class ImportCollectionConfigurationModal extends React.Component {
             />
           </label>
         </div>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt2"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.makePublicForGrant4 || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ makePublicForGrant4: !option.makePublicForGrant4 })}
           />
-          <label htmlFor="cbOpt2" className="form-label custom-control-label">
+          <label htmlFor="cbOpt2" className="form-label form-check-label">
             {t(`${translationBase}.set_public_to_page.label`, { from: t('Only me') })}
             <p
               className="form-text text-muted mt-0"
@@ -111,15 +111,15 @@ class ImportCollectionConfigurationModal extends React.Component {
             />
           </label>
         </div>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt3"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.makePublicForGrant5 || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ makePublicForGrant5: !option.makePublicForGrant5 })}
           />
-          <label htmlFor="cbOpt3" className="form-label custom-control-label">
+          <label htmlFor="cbOpt3" className="form-label form-check-label">
             {t(`${translationBase}.set_public_to_page.label`, { from: t('Only inside the group') })}
             <p
               className="form-text text-muted mt-0"
@@ -127,28 +127,28 @@ class ImportCollectionConfigurationModal extends React.Component {
             />
           </label>
         </div>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt5"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.initPageMetadatas || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ initPageMetadatas: !option.initPageMetadatas })}
           />
-          <label htmlFor="cbOpt5" className="form-label custom-control-label">
+          <label htmlFor="cbOpt5" className="form-label form-check-label">
             {t(`${translationBase}.initialize_meta_datas.label`)}
             <p className="form-text text-muted mt-0" dangerouslySetInnerHTML={{ __html: t(`${translationBase}.initialize_meta_datas.desc`) }} />
           </label>
         </div>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt6"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.initHackmdDatas || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ initHackmdDatas: !option.initHackmdDatas })}
           />
-          <label htmlFor="cbOpt6" className="form-label custom-control-label">
+          <label htmlFor="cbOpt6" className="form-label form-check-label">
             {t(`${translationBase}.initialize_hackmd_related_datas.label`)}
             <p className="form-text text-muted mt-0" dangerouslySetInnerHTML={{ __html: t(`${translationBase}.initialize_hackmd_related_datas.desc`) }} />
           </label>
@@ -167,15 +167,15 @@ class ImportCollectionConfigurationModal extends React.Component {
     /* eslint-disable react/no-unescaped-entities */
     return (
       <>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt1"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.isOverwriteAuthorWithCurrentUser || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ isOverwriteAuthorWithCurrentUser: !option.isOverwriteAuthorWithCurrentUser })}
           />
-          <label htmlFor="cbOpt1" className="form-label custom-control-label">
+          <label htmlFor="cbOpt1" className="form-label form-check-label">
             {t(`${translationBase}.overwrite_author.label`)}
             <p className="form-text text-muted mt-0" dangerouslySetInnerHTML={{ __html: t(`${translationBase}.overwrite_author.desc`) }} />
           </label>

+ 3 - 3
apps/app/src/components/Admin/ImportData/GrowiArchive/ImportCollectionItem.jsx

@@ -81,18 +81,18 @@ export default class ImportCollectionItem extends React.Component {
     } = this.props;
 
     return (
-      <div className="custom-control custom-checkbox custom-checkbox-info my-0">
+      <div className="form-check form-check-info my-0">
         <input
           type="checkbox"
           id={collectionName}
           name={collectionName}
-          className="custom-control-input"
+          className="form-check-input"
           value={collectionName}
           checked={isSelected}
           disabled={isImporting}
           onChange={this.changeHandler}
         />
-        <label className="form-label text-capitalize custom-control-label" htmlFor={collectionName}>
+        <label className="form-label text-capitalize form-check-label" htmlFor={collectionName}>
           {collectionName}
         </label>
       </div>

+ 0 - 1
apps/app/src/components/Admin/ImportData/GrowiArchive/UploadForm.jsx

@@ -68,7 +68,6 @@ class UploadForm extends React.Component {
               <input
                 type="file"
                 name="file"
-                className="form-control-file"
                 accept=".zip"
                 ref={this.inputRef}
                 onChange={this.changeFileName}

+ 3 - 3
apps/app/src/components/Admin/LegacySlackIntegration/SlackConfiguration.jsx

@@ -78,15 +78,15 @@ class SlackConfiguration extends React.Component {
 
             <div className="row mb-3">
               <div className="offset-md-3 col-md-6 text-left">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     type="checkbox"
-                    className="custom-control-input"
+                    className="form-check-input"
                     id="cbPrioritizeIWH"
                     checked={adminSlackIntegrationLegacyContainer.state.isIncomingWebhookPrioritized || false}
                     onChange={() => { adminSlackIntegrationLegacyContainer.switchIsIncomingWebhookPrioritized() }}
                   />
-                  <label className="form-label custom-control-label" htmlFor="cbPrioritizeIWH">
+                  <label className="form-label form-check-label" htmlFor="cbPrioritizeIWH">
                     {t('notification_settings.prioritize_webhook')}
                   </label>
                 </div>

+ 3 - 3
apps/app/src/components/Admin/MarkdownSetting/IndentForm.tsx

@@ -74,17 +74,17 @@ const IndentForm = (props: Props) => {
 
     return (
       <div className="col">
-        <div className="custom-control custom-checkbox custom-checkbox-success">
+        <div className="form-check form-check-success">
           <input
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             id="isIndentSizeForced"
             checked={isIndentSizeForced || false}
             onChange={() => {
               adminMarkDownContainer.setState({ isIndentSizeForced: !isIndentSizeForced });
             }}
           />
-          <label className="form-label custom-control-label" htmlFor="isIndentSizeForced">
+          <label className="form-label form-check-label" htmlFor="isIndentSizeForced">
             {t('markdown_settings.indent_options.disallow_indent_change')}
           </label>
         </div>

+ 6 - 6
apps/app/src/components/Admin/MarkdownSetting/LineBreakForm.jsx

@@ -43,15 +43,15 @@ class LineBreakForm extends React.Component {
 
     return (
       <div className="col">
-        <div className="custom-control custom-checkbox custom-checkbox-success">
+        <div className="form-check form-check-success">
           <input
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             id="isEnabledLinebreaks"
             checked={isEnabledLinebreaks}
             onChange={() => { adminMarkDownContainer.setState({ isEnabledLinebreaks: !isEnabledLinebreaks }) }}
           />
-          <label className="form-label custom-control-label" htmlFor="isEnabledLinebreaks">
+          <label className="form-label form-check-label" htmlFor="isEnabledLinebreaks">
             {t('markdown_settings.lineBreak_options.enable_lineBreak') }
           </label>
         </div>
@@ -68,15 +68,15 @@ class LineBreakForm extends React.Component {
 
     return (
       <div className="col">
-        <div className="custom-control custom-checkbox custom-checkbox-success">
+        <div className="form-check form-check-success">
           <input
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             id="isEnabledLinebreaksInComments"
             checked={isEnabledLinebreaksInComments}
             onChange={() => { adminMarkDownContainer.setState({ isEnabledLinebreaksInComments: !isEnabledLinebreaksInComments }) }}
           />
-          <label className="form-label custom-control-label" htmlFor="isEnabledLinebreaksInComments">
+          <label className="form-label form-check-label" htmlFor="isEnabledLinebreaksInComments">
             {t('markdown_settings.lineBreak_options.enable_lineBreak_for_comment') }
           </label>
         </div>

+ 9 - 9
apps/app/src/components/Admin/MarkdownSetting/XssForm.jsx

@@ -49,16 +49,16 @@ class XssForm extends React.Component {
         <div className="row">
 
           <div className="col-md-6 col-sm-12 align-self-start mb-4">
-            <div className="custom-control custom-radio">
+            <div className="form-check">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id="xssOption1"
                 name="XssOption"
                 checked={xssOption === RehypeSanitizeOption.RECOMMENDED}
                 onChange={() => { adminMarkDownContainer.setState({ xssOption: RehypeSanitizeOption.RECOMMENDED }) }}
               />
-              <label className="form-label custom-control-label w-100" htmlFor="xssOption1">
+              <label className="form-label form-check-label w-100" htmlFor="xssOption1">
                 <p className="font-weight-bold">{t('markdown_settings.xss_options.recommended_setting')}</p>
                 <div className="mt-4">
                   <div className="d-flex justify-content-between">
@@ -91,16 +91,16 @@ class XssForm extends React.Component {
           </div>
 
           <div className="col-md-6 col-sm-12 align-self-start mb-4">
-            <div className="custom-control custom-radio">
+            <div className="form-check">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id="xssOption2"
                 name="XssOption"
                 checked={xssOption === RehypeSanitizeOption.CUSTOM}
                 onChange={() => { adminMarkDownContainer.setState({ xssOption: RehypeSanitizeOption.CUSTOM }) }}
               />
-              <label className="form-label custom-control-label w-100" htmlFor="xssOption2">
+              <label className="form-label form-check-label w-100" htmlFor="xssOption2">
                 <p className="font-weight-bold">{t('markdown_settings.xss_options.custom_whitelist')}</p>
                 <WhitelistInput customizable />
               </label>
@@ -120,16 +120,16 @@ class XssForm extends React.Component {
         <fieldset className="col-12">
           <div>
             <div className="col-8 offset-4 my-3">
-              <div className="custom-control custom-switch custom-checkbox-success">
+              <div className="form-check form-switch form-check-success">
                 <input
                   type="checkbox"
-                  className="custom-control-input"
+                  className="form-check-input"
                   id="XssEnable"
                   name="isEnabledXss"
                   checked={isEnabledXss}
                   onChange={adminMarkDownContainer.switchEnableXss}
                 />
-                <label className="form-label custom-control-label w-100" htmlFor="XssEnable">
+                <label className="form-label form-check-label w-100" htmlFor="XssEnable">
                   {t('markdown_settings.xss_options.enable_xss_prevention')}
                 </label>
               </div>

+ 6 - 6
apps/app/src/components/Admin/Notification/GlobalNotification.jsx

@@ -42,15 +42,15 @@ const GlobalNotification = (props) => {
       </p>
       <div className="row mb-4">
         <div className="col-md-8 offset-md-2">
-          <div className="custom-control custom-checkbox custom-checkbox-success">
+          <div className="form-check form-check-success">
             <input
               id="isNotificationForOwnerPageEnabled"
-              className="custom-control-input"
+              className="form-check-input"
               type="checkbox"
               checked={adminNotificationContainer.state.isNotificationForOwnerPageEnabled || false}
               onChange={() => { adminNotificationContainer.switchIsNotificationForOwnerPageEnabled() }}
             />
-            <label className="form-label custom-control-label" htmlFor="isNotificationForOwnerPageEnabled">
+            <label className="form-label form-check-label" htmlFor="isNotificationForOwnerPageEnabled">
               {/* eslint-disable-next-line react/no-danger */}
               <span dangerouslySetInnerHTML={{ __html: t('notification_settings.just_me_notification_help') }} />
             </label>
@@ -60,15 +60,15 @@ const GlobalNotification = (props) => {
 
       <div className="row mb-4">
         <div className="col-md-8 offset-md-2">
-          <div className="custom-control custom-checkbox custom-checkbox-success">
+          <div className="form-check form-check-success">
             <input
               id="isNotificationForGroupPageEnabled"
-              className="custom-control-input"
+              className="form-check-input"
               type="checkbox"
               checked={adminNotificationContainer.state.isNotificationForGroupPageEnabled || false}
               onChange={() => { adminNotificationContainer.switchIsNotificationForGroupPageEnabled() }}
             />
-            <label className="form-label custom-control-label" htmlFor="isNotificationForGroupPageEnabled">
+            <label className="form-label form-check-label" htmlFor="isNotificationForGroupPageEnabled">
               {/* eslint-disable-next-line react/no-danger */}
               <span dangerouslySetInnerHTML={{ __html: t('notification_settings.group_notification_help') }} />
             </label>

+ 3 - 3
apps/app/src/components/Admin/Notification/GlobalNotificationList.jsx

@@ -80,15 +80,15 @@ class GlobalNotificationList extends React.Component {
           return (
             <tr key={notification._id}>
               <td className="align-middle td-abs-center">
-                <div className="custom-control custom-switch custom-checkbox-success">
+                <div className="form-check form-switch form-check-success">
                   <input
                     type="checkbox"
-                    className="custom-control-input"
+                    className="form-check-input"
                     id={notification._id}
                     defaultChecked={notification.isEnabled}
                     onClick={() => this.toggleIsEnabled(notification)}
                   />
-                  <label className="form-label custom-control-label" htmlFor={notification._id} />
+                  <label className="form-label form-check-label" htmlFor={notification._id} />
                 </div>
               </td>
               <td>

+ 7 - 7
apps/app/src/components/Admin/Notification/ManageGlobalNotification.tsx

@@ -143,10 +143,10 @@ const ManageGlobalNotification = (props: Props): JSX.Element => {
           </div>
 
           <h3>{t('notification_settings.notify_to')}</h3>
-          <div>
-            <div className="custom-control custom-radio">
+          <div className="form-group form-inline">
+            <div className="form-check">
               <input
-                className="custom-control-input"
+                className="form-check-input"
                 type="radio"
                 id="mail"
                 name="notifyType"
@@ -154,13 +154,13 @@ const ManageGlobalNotification = (props: Props): JSX.Element => {
                 checked={notifyType === NotifyType.Email}
                 onChange={() => { setNotifyType(NotifyType.Email) }}
               />
-              <label className="form-label custom-control-label" htmlFor="mail">
+              <label className="form-label form-check-label" htmlFor="mail">
                 <p className="font-weight-bold">Email</p>
               </label>
             </div>
-            <div className="custom-control custom-radio ml-2">
+            <div className="form-check ml-2">
               <input
-                className="custom-control-input"
+                className="form-check-input"
                 type="radio"
                 id="slack"
                 name="notifyType"
@@ -168,7 +168,7 @@ const ManageGlobalNotification = (props: Props): JSX.Element => {
                 checked={notifyType === NotifyType.SLACK}
                 onChange={() => { setNotifyType(NotifyType.SLACK) }}
               />
-              <label className="form-label custom-control-label" htmlFor="slack">
+              <label className="form-label form-check-label" htmlFor="slack">
                 <p className="font-weight-bold">Slack</p>
               </label>
             </div>

+ 3 - 3
apps/app/src/components/Admin/Notification/TriggerEventCheckBox.jsx

@@ -7,15 +7,15 @@ const TriggerEventCheckBox = (props) => {
   const { t } = props;
 
   return (
-    <div className={`custom-control custom-checkbox custom-checkbox-${props.checkbox}`}>
+    <div className={`form-check form-check-${props.checkbox}`}>
       <input
-        className="custom-control-input"
+        className="form-check-input"
         type="checkbox"
         id={`trigger-event-${props.event}`}
         checked={props.checked}
         onChange={props.onChange}
       />
-      <label className="form-label custom-control-label" htmlFor={`trigger-event-${props.event}`}>
+      <label className="form-label form-check-label" htmlFor={`trigger-event-${props.event}`}>
         {props.children}{' '}
         {t(`notification_settings.event_${props.event}`)}
       </label>

+ 6 - 6
apps/app/src/components/Admin/Security/GitHubSecuritySettingContents.jsx

@@ -58,15 +58,15 @@ class GitHubSecurityManagementContents extends React.Component {
 
         <div className="row">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 id="isGitHubEnabled"
-                className="custom-control-input"
+                className="form-check-input"
                 type="checkbox"
                 checked={adminGeneralSecurityContainer.state.isGitHubEnabled || false}
                 onChange={() => { adminGeneralSecurityContainer.switchIsGitHubOAuthEnabled() }}
               />
-              <label className="form-label custom-control-label" htmlFor="isGitHubEnabled">
+              <label className="form-label form-check-label" htmlFor="isGitHubEnabled">
                 {t('security_settings.OAuth.GitHub.enable_github')}
               </label>
             </div>
@@ -137,16 +137,16 @@ class GitHubSecurityManagementContents extends React.Component {
 
             <div className="row mb-5">
               <div className="offset-3 col-6 text-left">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByUserNameGitHub"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminGitHubSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser || false}
                     onChange={() => { adminGitHubSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="custom-control-label"
+                    className="form-check-label"
                     htmlFor="bindByUserNameGitHub"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat email matching as identical') }}
                   />

+ 6 - 6
apps/app/src/components/Admin/Security/GoogleSecuritySettingContents.jsx

@@ -56,15 +56,15 @@ class GoogleSecurityManagementContents extends React.Component {
 
         <div className="row">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 id="isGoogleEnabled"
-                className="custom-control-input"
+                className="form-check-input"
                 type="checkbox"
                 checked={adminGeneralSecurityContainer.state.isGoogleEnabled || false}
                 onChange={() => { adminGeneralSecurityContainer.switchIsGoogleOAuthEnabled() }}
               />
-              <label className="form-label custom-control-label" htmlFor="isGoogleEnabled">
+              <label className="form-label form-check-label" htmlFor="isGoogleEnabled">
                 {t('security_settings.OAuth.Google.enable_google')}
               </label>
             </div>
@@ -135,16 +135,16 @@ class GoogleSecurityManagementContents extends React.Component {
 
             <div className="row mb-5">
               <div className="offset-3 col-6">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByUserNameGoogle"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminGoogleSecurityContainer.state.isSameEmailTreatedAsIdenticalUser || false}
                     onChange={() => { adminGoogleSecurityContainer.switchIsSameEmailTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="custom-control-label"
+                    className="form-check-label"
                     htmlFor="bindByUserNameGoogle"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat email matching as identical') }}
                   />

+ 6 - 6
apps/app/src/components/Admin/Security/LdapSecuritySettingContents.jsx

@@ -60,15 +60,15 @@ class LdapSecuritySettingContents extends React.Component {
 
         <div className="row">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 id="isLdapEnabled"
-                className="custom-control-input"
+                className="form-check-input"
                 type="checkbox"
                 checked={isLdapEnabled}
                 onChange={() => { adminGeneralSecurityContainer.switchIsLdapEnabled() }}
               />
-              <label className="form-label custom-control-label" htmlFor="isLdapEnabled">
+              <label className="form-label form-check-label" htmlFor="isLdapEnabled">
                 {t('security_settings.ldap.enable_ldap')}
               </label>
             </div>
@@ -260,16 +260,16 @@ class LdapSecuritySettingContents extends React.Component {
 
             <div className="row">
               <div className="offset-md-3 col-md-6">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     type="checkbox"
-                    className="custom-control-input"
+                    className="form-check-input"
                     id="isSameUsernameTreatedAsIdenticalUser"
                     checked={adminLdapSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser}
                     onChange={() => { adminLdapSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="custom-control-label"
+                    className="form-check-label"
                     htmlFor="isSameUsernameTreatedAsIdenticalUser"
                     // eslint-disable-next-line react/no-danger
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat username matching as identical') }}

+ 9 - 9
apps/app/src/components/Admin/Security/LocalSecuritySettingContents.jsx

@@ -64,16 +64,16 @@ class LocalSecuritySettingContents extends React.Component {
 
         <div className="row mb-5">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 type="checkbox"
-                className="custom-control-input"
+                className="form-check-input"
                 id="isLocalEnabled"
                 checked={isLocalEnabled}
                 onChange={() => adminGeneralSecurityContainer.switchIsLocalEnabled()}
                 disabled={adminLocalSecurityContainer.state.useOnlyEnvVars}
               />
-              <label className="form-label custom-control-label" htmlFor="isLocalEnabled">
+              <label className="form-label form-check-label" htmlFor="isLocalEnabled">
                 {t('security_settings.Local.enable_local')}
               </label>
             </div>
@@ -165,15 +165,15 @@ class LocalSecuritySettingContents extends React.Component {
             <div className="row">
               <label className="col-12 col-md-3 text-left text-md-right  col-form-label">{t('security_settings.Local.password_reset_by_users')}</label>
               <div className="col-12 col-md-6">
-                <div className="custom-control custom-switch custom-checkbox-success">
+                <div className="form-check form-switch form-check-success">
                   <input
                     type="checkbox"
-                    className="custom-control-input"
+                    className="form-check-input"
                     id="isPasswordResetEnabled"
                     checked={isPasswordResetEnabled}
                     onChange={() => adminLocalSecurityContainer.switchIsPasswordResetEnabled()}
                   />
-                  <label className="form-label custom-control-label" htmlFor="isPasswordResetEnabled">
+                  <label className="form-label form-check-label" htmlFor="isPasswordResetEnabled">
                     {t('security_settings.Local.enable_password_reset_by_users')}
                   </label>
                 </div>
@@ -194,15 +194,15 @@ class LocalSecuritySettingContents extends React.Component {
             <div className="row">
               <label className="col-12 col-md-3 text-left text-md-right  col-form-label">{t('security_settings.Local.email_authentication')}</label>
               <div className="col-12 col-md-6">
-                <div className="custom-control custom-switch custom-checkbox-success">
+                <div className="form-check form-switch form-check-success">
                   <input
                     type="checkbox"
-                    className="custom-control-input"
+                    className="form-check-input"
                     id="isEmailAuthenticationEnabled"
                     checked={isEmailAuthenticationEnabled}
                     onChange={() => adminLocalSecurityContainer.switchIsEmailAuthenticationEnabled()}
                   />
-                  <label className="form-label custom-control-label" htmlFor="isEmailAuthenticationEnabled">
+                  <label className="form-label form-check-label" htmlFor="isEmailAuthenticationEnabled">
                     {t('security_settings.Local.enable_email_authentication')}
                   </label>
                 </div>

+ 9 - 9
apps/app/src/components/Admin/Security/OidcSecuritySettingContents.jsx

@@ -50,15 +50,15 @@ class OidcSecurityManagementContents extends React.Component {
 
         <div className="row mb-5">
           <div className="offset-3 col-6">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 id="isOidcEnabled"
-                className="custom-control-input"
+                className="form-check-input"
                 type="checkbox"
                 checked={adminGeneralSecurityContainer.state.isOidcEnabled}
                 onChange={() => { adminGeneralSecurityContainer.switchIsOidcEnabled() }}
               />
-              <label className="form-label custom-control-label" htmlFor="isOidcEnabled">
+              <label className="form-label form-check-label" htmlFor="isOidcEnabled">
                 {t('security_settings.OAuth.enable_oidc')}
               </label>
             </div>
@@ -387,16 +387,16 @@ class OidcSecurityManagementContents extends React.Component {
 
             <div className="row mb-5">
               <div className="offset-md-3 col-md-6">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByUserName-oidc"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminOidcSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser}
                     onChange={() => { adminOidcSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="form-label custom-control-label"
+                    className="form-label form-check-label"
                     htmlFor="bindByUserName-oidc"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat username matching as identical') }}
                   />
@@ -409,16 +409,16 @@ class OidcSecurityManagementContents extends React.Component {
 
             <div className="row mb-5">
               <div className="offset-md-3 col-md-6">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByEmail-oidc"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminOidcSecurityContainer.state.isSameEmailTreatedAsIdenticalUser || false}
                     onChange={() => { adminOidcSecurityContainer.switchIsSameEmailTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="form-label custom-control-label"
+                    className="form-label form-check-label"
                     htmlFor="bindByEmail-oidc"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat email matching as identical') }}
                   />

+ 9 - 9
apps/app/src/components/Admin/Security/SamlSecuritySettingContents.jsx

@@ -66,16 +66,16 @@ class SamlSecurityManagementContents extends React.Component {
 
         <div className="row mb-5">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 id="isSamlEnabled"
-                className="custom-control-input"
+                className="form-check-input"
                 type="checkbox"
                 checked={adminGeneralSecurityContainer.state.isSamlEnabled}
                 onChange={() => { adminGeneralSecurityContainer.switchIsSamlEnabled() }}
                 disabled={adminSamlSecurityContainer.state.useOnlyEnvVars}
               />
-              <label className="form-label custom-control-label" htmlFor="isSamlEnabled">
+              <label className="form-label form-check-label" htmlFor="isSamlEnabled">
                 {t('security_settings.SAML.enable_saml')}
               </label>
             </div>
@@ -392,16 +392,16 @@ pWVdnzS1VCO8fKsJ7YYIr+JmHvseph3kFUOI5RqkCcMZlKUv83aUThsTHw==
 
             <div className="row mb-5">
               <div className="offset-md-3 col-md-6 text-left">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByUserName-SAML"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminSamlSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser || false}
                     onChange={() => { adminSamlSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="form-label custom-control-label"
+                    className="form-label form-check-label"
                     htmlFor="bindByUserName-SAML"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat username matching as identical') }}
                   />
@@ -414,16 +414,16 @@ pWVdnzS1VCO8fKsJ7YYIr+JmHvseph3kFUOI5RqkCcMZlKUv83aUThsTHw==
 
             <div className="row mb-5">
               <div className="offset-md-3 col-md-6 text-left">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByEmail-SAML"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminSamlSecurityContainer.state.isSameEmailTreatedAsIdenticalUser || false}
                     onChange={() => { adminSamlSecurityContainer.switchIsSameEmailTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="form-label custom-control-label"
+                    className="form-label form-check-label"
                     htmlFor="bindByEmail-SAML"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat email matching as identical') }}
                   />

+ 9 - 9
apps/app/src/components/Admin/Security/SecuritySetting.jsx

@@ -356,15 +356,15 @@ class SecuritySetting extends React.Component {
               <tr>
                 <th scope="row">{ t('only_me') }</th>
                 <td>
-                  <div className="custom-control custom-switch custom-checkbox-success">
+                  <div className="form-check form-switch form-check-success">
                     <input
                       type="checkbox"
-                      className="custom-control-input"
+                      className="form-check-input"
                       id="isShowRestrictedByOwner"
                       checked={!adminGeneralSecurityContainer.state.isShowRestrictedByOwner}
                       onChange={() => { adminGeneralSecurityContainer.switchIsShowRestrictedByOwner() }}
                     />
-                    <label className="form-label custom-control-label" htmlFor="isShowRestrictedByOwner">
+                    <label className="form-label form-check-label" htmlFor="isShowRestrictedByOwner">
                       {t('security_settings.displayed_or_hidden')}
                     </label>
                   </div>
@@ -373,15 +373,15 @@ class SecuritySetting extends React.Component {
               <tr>
                 <th scope="row">{ t('only_inside_the_group') }</th>
                 <td>
-                  <div className="custom-control custom-switch custom-checkbox-success">
+                  <div className="form-check form-switch form-check-success">
                     <input
                       type="checkbox"
-                      className="custom-control-input"
+                      className="form-check-input"
                       id="isShowRestrictedByGroup"
                       checked={!adminGeneralSecurityContainer.state.isShowRestrictedByGroup}
                       onChange={() => { adminGeneralSecurityContainer.switchIsShowRestrictedByGroup() }}
                     />
-                    <label className="form-label custom-control-label" htmlFor="isShowRestrictedByGroup">
+                    <label className="form-label form-check-label" htmlFor="isShowRestrictedByGroup">
                       {t('security_settings.displayed_or_hidden')}
                     </label>
                   </div>
@@ -456,15 +456,15 @@ class SecuritySetting extends React.Component {
         <h4>{t('security_settings.user_homepage_deletion.user_homepage_deletion')}</h4>
         <div className="row mb-4">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 type="checkbox"
-                className="custom-control-input"
+                className="form-check-input"
                 id="is-user-page-deletion-enabled"
                 checked={adminGeneralSecurityContainer.state.isUsersHomepageDeletionEnabled}
                 onChange={() => { adminGeneralSecurityContainer.switchIsUsersHomepageDeletionEnabled() }}
               />
-              <label className="form-label custom-control-label" htmlFor="is-user-page-deletion-enabled">
+              <label className="form-label form-check-label" htmlFor="is-user-page-deletion-enabled">
                 {t('security_settings.user_homepage_deletion.enable_user_homepage_deletion')}
               </label>
             </div>

+ 3 - 3
apps/app/src/components/Admin/Security/ShareLinkSetting.tsx

@@ -116,15 +116,15 @@ const ShareLinkSetting = (props: ShareLinkSettingProps) => {
       <h4>{t('security_settings.share_link_rights')}</h4>
       <div className="row mb-5">
         <div className="col-6 offset-3">
-          <div className="custom-control custom-switch custom-checkbox-success">
+          <div className="form-check form-switch form-check-success">
             <input
               type="checkbox"
-              className="custom-control-input"
+              className="form-check-input"
               id="disableLinkSharing"
               checked={!disableLinkSharing}
               onChange={() => switchDisableLinkSharing()}
             />
-            <label className="form-label custom-control-label" htmlFor="disableLinkSharing">
+            <label className="form-label form-check-label" htmlFor="disableLinkSharing">
               {t('security_settings.enable_link_sharing')}
             </label>
           </div>

+ 1 - 1
apps/app/src/components/Admin/SlackIntegration/ManageCommandsProcess.jsx

@@ -305,7 +305,7 @@ const ManageCommandsProcess = ({
           </div>
         )}
 
-        <div className="custom-control custom-checkbox">
+        <div className="form-check">
           <div className="row mb-5 d-block">
             {defaultCommandsName.map(keyName => (
               <PermissionSettingForEachPermissionTypeComponent

+ 2 - 2
apps/app/src/components/Admin/SlackIntegration/ManageCommandsProcessWithoutProxy.jsx

@@ -220,7 +220,7 @@ const ManageCommandsProcessWithoutProxy = ({ commandPermission, eventActionsPerm
       <p className="mb-4 font-weight-bold">{t('admin:slack_integration.accordion.growi_commands')}</p>
       <div className="row d-flex flex-column align-items-center">
         <div className="col-8">
-          <div className="custom-control custom-checkbox">
+          <div className="form-check">
             <div className="row mb-5 d-block">
               { defaultCommandsName.map((commandName) => {
                 // eslint-disable-next-line max-len
@@ -241,7 +241,7 @@ const ManageCommandsProcessWithoutProxy = ({ commandPermission, eventActionsPerm
       <p className="mb-4 font-weight-bold">Events</p>
       <div className="row d-flex flex-column align-items-center">
         <div className="col-8">
-          <div className="custom-control custom-checkbox">
+          <div className="form-check">
             <div className="row mb-5 d-block">
               { defaultSupportedSlackEventActions.map(actionName => (
                 <SinglePermissionSettingComponent

+ 4 - 3
apps/app/src/components/Admin/SlackIntegration/SlackAppIntegrationControl.tsx

@@ -1,4 +1,5 @@
 import React, { FC } from 'react';
+
 import { useTranslation } from 'next-i18next';
 
 type Props = {
@@ -19,9 +20,9 @@ export const SlackAppIntegrationControl: FC<Props> = (props: Props) => {
 
   return (
     <div className="d-flex align-items-center">
-      <div className="my-1 custom-control custom-switch">
+      <div className="my-1 form-check form-switch">
         <input
-          className="custom-control-input"
+          className="form-check-input"
           id={inputId}
           type="checkbox"
           checked={isPrimary}
@@ -32,7 +33,7 @@ export const SlackAppIntegrationControl: FC<Props> = (props: Props) => {
             }
           }}
         />
-        <label className="form-label custom-control-label" htmlFor={inputId}>
+        <label className="form-label form-check-label" htmlFor={inputId}>
           Primary
         </label>
       </div>

+ 4 - 4
apps/app/src/components/Admin/UserGroupDetail/CheckBoxForSerchUserOption.jsx

@@ -1,23 +1,23 @@
 
 import React from 'react';
 
-import PropTypes from 'prop-types';
 import { useTranslation } from 'next-i18next';
+import PropTypes from 'prop-types';
 
 class CheckBoxForSerchUserOption extends React.Component {
 
   render() {
     const { t, option } = this.props;
     return (
-      <div className="custom-control custom-checkbox custom-checkbox-info" key={`isAlso${option}Searched`}>
+      <div className="form-check form-check-info" key={`isAlso${option}Searched`}>
         <input
           type="checkbox"
           id={`isAlso${option}Searched`}
-          className="custom-control-input"
+          className="form-check-input"
           checked={this.props.checked}
           onChange={this.props.onChange}
         />
-        <label className="form-label text-capitalize custom-control-label ml-3" htmlFor={`isAlso${option}Searched`}>
+        <label className="form-label text-capitalize form-check-label ml-3" htmlFor={`isAlso${option}Searched`}>
           {t('admin:user_group_management.add_modal.enable_option', { option })}
         </label>
       </div>

+ 4 - 4
apps/app/src/components/Admin/UserGroupDetail/RadioButtonForSerchUserOption.jsx

@@ -1,23 +1,23 @@
 
 import React from 'react';
 
-import PropTypes from 'prop-types';
 import { useTranslation } from 'next-i18next';
+import PropTypes from 'prop-types';
 
 const RadioButtonForSerchUserOption = (props) => {
 
   const { searchType } = props;
   const { t } = useTranslation();
   return (
-    <div className="custom-control custom-radio custom-control-inline" key={`${searchType}Match`}>
+    <div className="form-check form-check-inline" key={`${searchType}Match`}>
       <input
         type="radio"
         id={`${searchType}Match`}
-        className="custom-control-input"
+        className="form-check-input"
         checked={props.checked}
         onChange={props.onChange}
       />
-      <label className="form-label text-capitalize custom-control-label ml-3" htmlFor={`${searchType}Match`}>
+      <label className="form-label text-capitalize form-check-label ml-3" htmlFor={`${searchType}Match`}>
         {t(`admin:user_group_management.add_modal.${searchType}_match`)}
       </label>
     </div>

+ 3 - 3
apps/app/src/components/Admin/UserGroupDetail/UpdateParentConfirmModal.tsx

@@ -43,16 +43,16 @@ export const UpdateParentConfirmModal: FC = () => {
                 {t('admin:user_group_management.update_parent_confirm_modal.danger_message')}
               </div>
 
-              <div className="custom-control custom-checkbox custom-checkbox-succsess pl-5">
+              <div className="form-check form-check-succsess pl-5">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="forceUpdateParents"
                   id="forceUpdateParents"
                   type="checkbox"
                   checked={isForceUpdate}
                   onChange={() => setForceUpdate(!isForceUpdate)}
                 />
-                <label className="form-label custom-control-label" htmlFor="forceUpdateParents">
+                <label className="form-label form-check-label" htmlFor="forceUpdateParents">
                   {t('admin:user_group_management.update_parent_confirm_modal.force_update_parents_label')}
                   <p className="form-text text-muted mt-0">{t('admin:user_group_management.update_parent_confirm_modal.force_update_parents_description')}</p>
                 </label>

+ 3 - 3
apps/app/src/components/Admin/UserManagement.tsx

@@ -81,15 +81,15 @@ const UserManagement = (props: UserManagementProps) => {
 
   const renderCheckbox = (status: string, statusLabel: string, statusColor: string) => {
     return (
-      <div className={`custom-control custom-checkbox custom-checkbox-${statusColor} mr-2`}>
+      <div className={`form-check form-check-${statusColor} mr-2`}>
         <input
-          className="custom-control-input"
+          className="form-check-input"
           type="checkbox"
           id={`c_${status}`}
           checked={adminUsersContainer.isSelected(status)}
           onChange={() => clickHandler(status)}
         />
-        <label className="form-label custom-control-label" htmlFor={`c_${status}`}>
+        <label className="form-label form-check-label" htmlFor={`c_${status}`}>
           <span className={`badge badge-pill badge-${statusColor} d-inline-block vt mt-1`}>
             {statusLabel}
           </span>

+ 3 - 3
apps/app/src/components/Admin/Users/UserInviteModal.jsx

@@ -105,16 +105,16 @@ class UserInviteModal extends React.Component {
 
     return (
       <>
-        <div className="col text-left custom-control custom-checkbox custom-checkbox-info text-left" onChange={this.handleCheckBox}>
+        <div className="col text-left form-check form-check-info" onChange={this.handleCheckBox}>
           <input
             type="checkbox"
             id="sendEmail"
-            className="custom-control-input"
+            className="form-check-input"
             name="sendEmail"
             defaultChecked={this.state.sendEmail}
             disabled={!isMailerSetup}
           />
-          <label className="form-label custom-control-label" htmlFor="sendEmail">
+          <label className="form-label form-check-label" htmlFor="sendEmail">
             {t('admin:user_management.invite_modal.invite_thru_email')}
           </label>
           {isMailerSetup

+ 6 - 2
apps/app/src/components/Common/ImageCropModal.tsx

@@ -162,15 +162,19 @@ const ImageCropModal: FC<Props> = (props: Props) => {
         </button>
         { !showCropOption && (
           <div className="mr-auto">
-            <div className="custom-control custom-switch ">
+            <div className="form-check form-switch ">
               <input
                 id="cropImageOption"
-                className="custom-control-input mr-auto"
+                className="form-check-input mr-auto"
                 type="checkbox"
                 checked={isCropImage}
                 onChange={() => { setIsCropImage(!isCropImage) }}
               />
+<<<<<<< HEAD
               <label className="form-label custom-control-label" htmlFor="cropImageOption">
+=======
+              <label className="form-check-label" htmlFor="cropImageOption">
+>>>>>>> supprt/correspond-with-forms-breaking-changes
                 { t('crop_image_modal.image_crop') }
               </label>
             </div>

+ 1 - 1
apps/app/src/components/Layout/BasicLayout.tsx

@@ -40,7 +40,7 @@ export const BasicLayout = ({ children, className }: Props): JSX.Element => {
 
           <div className="flex-expand-vert">{/* neccessary for nested {children} make expanded */}
             <AlertSiteUrlUndefined />
-            <div className="flex-expand-horiz h-100">{/* neccessary for nested {children} make expanded */}
+            <div className="flex-expand-horiz">{/* neccessary for nested {children} make expanded */}
               {children}
             </div>
           </div>

+ 9 - 9
apps/app/src/components/Me/BasicInfoSettings.tsx

@@ -86,27 +86,27 @@ export const BasicInfoSettings = (): JSX.Element => {
       <div className="row">
         <label className="text-left text-md-right col-md-3 col-form-label">{t('Disclose E-mail')}</label>
         <div className="col-md-6">
-          <div className="custom-control custom-radio custom-control-inline">
+          <div className="form-check form-check-inline">
             <input
               type="radio"
               id="radioEmailShow"
-              className="custom-control-input"
+              className="form-check-input"
               name="userForm[isEmailPublished]"
               checked={personalSettingsInfo?.isEmailPublished === true}
               onChange={() => changePersonalSettingsHandler({ isEmailPublished: true })}
             />
-            <label className="form-label custom-control-label" htmlFor="radioEmailShow">{t('Show')}</label>
+            <label className="form-label form-check-label" htmlFor="radioEmailShow">{t('Show')}</label>
           </div>
-          <div className="custom-control custom-radio custom-control-inline">
+          <div className="form-check form-check-inline">
             <input
               type="radio"
               id="radioEmailHide"
-              className="custom-control-input"
+              className="form-check-input"
               name="userForm[isEmailPublished]"
               checked={personalSettingsInfo?.isEmailPublished === false}
               onChange={() => changePersonalSettingsHandler({ isEmailPublished: false })}
             />
-            <label className="form-label custom-control-label" htmlFor="radioEmailHide">{t('Hide')}</label>
+            <label className="form-label form-check-label" htmlFor="radioEmailHide">{t('Hide')}</label>
           </div>
         </div>
       </div>
@@ -120,16 +120,16 @@ export const BasicInfoSettings = (): JSX.Element => {
               const fixedT = i18n.getFixedT(locale);
 
               return (
-                <div key={locale} className="custom-control custom-radio custom-control-inline">
+                <div key={locale} className="form-check form-check-inline">
                   <input
                     type="radio"
                     id={`radioLang${locale}`}
-                    className="custom-control-input"
+                    className="form-check-input"
                     name="userForm[lang]"
                     checked={personalSettingsInfo?.lang === locale}
                     onChange={() => changePersonalSettingsHandler({ lang: locale })}
                   />
-                  <label className="form-label custom-control-label" htmlFor={`radioLang${locale}`}>{fixedT('meta.display_name') as string}</label>
+                  <label className="form-label form-check-label" htmlFor={`radioLang${locale}`}>{fixedT('meta.display_name') as string}</label>
                 </div>
               );
             })

+ 3 - 3
apps/app/src/components/Me/InAppNotificationSettings.tsx

@@ -74,16 +74,16 @@ const InAppNotificationSettings: FC = () => {
           {subscribeRulesMenuItems.map(rule => (
             <div
               key={rule.name}
-              className="custom-control custom-switch custom-checkbox-success"
+              className="form-check form-switch form-check-success"
             >
               <input
                 type="checkbox"
-                className="custom-control-input"
+                className="form-check-input"
                 id={rule.name}
                 checked={isCheckedRule(rule.name, subscribeRules)}
                 onChange={e => ruleCheckboxHandler(rule.name, e.target.checked)}
               />
-              <label className="form-label custom-control-label" htmlFor={rule.name}>
+              <label className="form-label form-check-label" htmlFor={rule.name}>
                 <strong>{rule.name}</strong>
               </label>
               <p className="form-text text-muted small">

+ 3 - 3
apps/app/src/components/Me/OtherSettings.tsx

@@ -53,17 +53,17 @@ const OtherSettings = (): JSX.Element => {
       <div className="row">
         <div className="offset-md-3 col-md-6 text-left">
           {!isLoadingCurrentUser && (
-            <div className="custom-control custom-switch custom-checkbox-primary">
+            <div className="form-check form-switch form-check-primary">
               <span id="grw-questionnaire-settings-toggle-wrapper">
                 <input
                   type="checkbox"
-                  className="custom-control-input"
+                  className="form-check-input"
                   id="isQuestionnaireEnabled"
                   checked={growiIsQuestionnaireEnabled && isQuestionnaireEnabled}
                   onChange={onChangeIsQuestionnaireEnabledHandler}
                   disabled={!growiIsQuestionnaireEnabled}
                 />
-                <label className="form-label custom-control-label" htmlFor="isQuestionnaireEnabled">
+                <label className="form-label form-check-label" htmlFor="isQuestionnaireEnabled">
                   {t('questionnaire.enable_questionnaire')}
                 </label>
               </span>

+ 6 - 6
apps/app/src/components/Me/ProfileImageSettings.tsx

@@ -94,17 +94,17 @@ const ProfileImageSettings = (): JSX.Element => {
       <div className="row">
         <div className="col-md-6 col-12 mb-3 mb-md-0">
           <h4>
-            <div className="custom-control custom-radio radio-primary">
+            <div className="form-check radio-primary">
               <input
                 type="radio"
                 id="radioGravatar"
-                className="custom-control-input"
+                className="form-check-input"
                 form="formImageType"
                 name="imagetypeForm[isGravatarEnabled]"
                 checked={isGravatarEnabled}
                 onChange={() => setGravatarEnabled(true)}
               />
-              <label className="form-label custom-control-label" htmlFor="radioGravatar">
+              <label className="form-label form-check-label" htmlFor="radioGravatar">
                 <img src={GRAVATAR_DEFAULT} data-vrt-blackout-profile /> Gravatar
               </label>
               <a href="https://gravatar.com/">
@@ -117,17 +117,17 @@ const ProfileImageSettings = (): JSX.Element => {
 
         <div className="col-md-6 col-12">
           <h4>
-            <div className="custom-control custom-radio radio-primary">
+            <div className="form-check radio-primary">
               <input
                 type="radio"
                 id="radioUploadPicture"
-                className="custom-control-input"
+                className="form-check-input"
                 form="formImageType"
                 name="imagetypeForm[isGravatarEnabled]"
                 checked={!isGravatarEnabled}
                 onChange={() => setGravatarEnabled(false)}
               />
-              <label className="form-label custom-control-label" htmlFor="radioUploadPicture">
+              <label className="form-label form-check-label" htmlFor="radioUploadPicture">
                 { t('Upload Image') }
               </label>
             </div>

+ 3 - 3
apps/app/src/components/Navbar/SubNavButtons.tsx

@@ -45,15 +45,15 @@ const WideViewMenuItem = (props: WideViewMenuItemProps): JSX.Element => {
       onClick={() => onClickMenuItem(!(expandContentWidth))}
       className="grw-page-control-dropdown-item"
     >
-      <div className="custom-control custom-switch ml-1">
+      <div className="form-check form-switch ml-1">
         <input
           id="switchContentWidth"
-          className="custom-control-input"
+          className="form-check-input"
           type="checkbox"
           checked={expandContentWidth}
           onChange={() => {}}
         />
-        <label className="form-label custom-control-label" htmlFor="switchContentWidth">
+        <label className="form-label form-check-label" htmlFor="switchContentWidth">
           { t('wide_view') }
         </label>
       </div>

+ 3 - 3
apps/app/src/components/Page/CopyDropdown.jsx

@@ -127,15 +127,15 @@ const CopyDropdown = (props) => {
               { t('copy_to_clipboard.Copy to clipboard') }
             </DropdownItem>
             { !isShareLinkMode && (
-              <div className="px-3 custom-control custom-switch custom-switch-sm">
+              <div className="px-3 form-check form-switch form-switch-sm">
                 <input
                   type="checkbox"
                   id={customSwitchForParamsId}
-                  className="custom-control-input"
+                  className="form-check-input"
                   checked={isParamsAppended}
                   onChange={toggleAppendParams}
                 />
-                <label className="form-label custom-control-label small" htmlFor={customSwitchForParamsId}>Append params</label>
+                <label className="form-label form-check-label small" htmlFor={customSwitchForParamsId}>Append params</label>
               </div>
             ) }
           </div>

+ 9 - 9
apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLinkForm.tsx

@@ -110,30 +110,30 @@ export const ShareLinkForm: FC<Props> = (props: Props) => {
           <label htmlFor="inputDesc" className="col-md-5 col-form-label">{t('share_links.expire')}</label>
           <div className="col-md-7">
 
-            <div className="custom-control custom-radio ">
+            <div className="form-check">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id="customRadio1"
                 name="expirationType"
                 value="customRadio1"
                 checked={expirationType === ExpirationType.UNLIMITED}
                 onChange={() => { handleChangeExpirationType(ExpirationType.UNLIMITED) }}
               />
-              <label className="form-label custom-control-label" htmlFor="customRadio1">{t('share_links.Unlimited')}</label>
+              <label className="form-label form-check-label" htmlFor="customRadio1">{t('share_links.Unlimited')}</label>
             </div>
 
-            <div className="custom-control custom-radio ">
+            <div className="form-check">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id="customRadio2"
                 value="customRadio2"
                 checked={expirationType === ExpirationType.NUMBER_OF_DAYS}
                 onChange={() => { handleChangeExpirationType(ExpirationType.NUMBER_OF_DAYS) }}
                 name="expirationType"
               />
-              <label className="form-label custom-control-label" htmlFor="customRadio2">
+              <label className="form-label form-check-label" htmlFor="customRadio2">
                 <div className="row align-items-center m-0">
                   <input
                     type="number"
@@ -149,17 +149,17 @@ export const ShareLinkForm: FC<Props> = (props: Props) => {
               </label>
             </div>
 
-            <div className="custom-control custom-radio text-nowrap mb-0">
+            <div className="form-check text-nowrap mb-0">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id="customRadio3"
                 name="expirationType"
                 value="customRadio3"
                 checked={expirationType === ExpirationType.CUSTOM}
                 onChange={() => { handleChangeExpirationType(ExpirationType.CUSTOM) }}
               />
-              <label className="form-label custom-control-label" htmlFor="customRadio3">
+              <label className="form-label form-check-label" htmlFor="customRadio3">
                 {t('share_links.Custom')}
               </label>
               <div className="d-inline-flex flex-wrap">

+ 9 - 9
apps/app/src/components/PageAlert/FixPageGrantAlert.tsx

@@ -133,9 +133,9 @@ const FixPageGrantModal = (props: ModalProps): JSX.Element => {
             {renderGrantDataLabel()}
 
             <div className="ml-2">
-              <div className="custom-control custom-radio mb-3">
+              <div className="form-check mb-3">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="grantRestricted"
                   id="grantRestricted"
                   type="radio"
@@ -143,13 +143,13 @@ const FixPageGrantModal = (props: ModalProps): JSX.Element => {
                   checked={selectedGrant === PageGrant.GRANT_RESTRICTED}
                   onChange={() => setSelectedGrant(PageGrant.GRANT_RESTRICTED)}
                 />
-                <label className="form-label custom-control-label" htmlFor="grantRestricted">
+                <label className="form-label form-check-label" htmlFor="grantRestricted">
                   { t('fix_page_grant.modal.radio_btn.restrected') }
                 </label>
               </div>
-              <div className="custom-control custom-radio mb-3">
+              <div className="form-check mb-3">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="grantUser"
                   id="grantUser"
                   type="radio"
@@ -157,13 +157,13 @@ const FixPageGrantModal = (props: ModalProps): JSX.Element => {
                   checked={selectedGrant === PageGrant.GRANT_OWNER}
                   onChange={() => setSelectedGrant(PageGrant.GRANT_OWNER)}
                 />
-                <label className="form-label custom-control-label" htmlFor="grantUser">
+                <label className="form-label form-check-label" htmlFor="grantUser">
                   { t('fix_page_grant.modal.radio_btn.only_me') }
                 </label>
               </div>
-              <div className="custom-control custom-radio d-flex mb-3">
+              <div className="form-check d-flex mb-3">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="grantUserGroup"
                   id="grantUserGroup"
                   type="radio"
@@ -171,7 +171,7 @@ const FixPageGrantModal = (props: ModalProps): JSX.Element => {
                   checked={selectedGrant === PageGrant.GRANT_USER_GROUP}
                   onChange={() => setSelectedGrant(PageGrant.GRANT_USER_GROUP)}
                 />
-                <label className="form-label custom-control-label" htmlFor="grantUserGroup">
+                <label className="form-label form-check-label" htmlFor="grantUserGroup">
                   { t('fix_page_grant.modal.radio_btn.grant_group') }
                 </label>
                 <div className="dropdown ml-2">

+ 6 - 6
apps/app/src/components/PageDeleteModal.tsx

@@ -182,16 +182,16 @@ const PageDeleteModal: FC = () => {
 
   function renderDeleteRecursivelyForm() {
     return (
-      <div className="custom-control custom-checkbox custom-checkbox-warning">
+      <div className="form-check form-check-warning">
         <input
-          className="custom-control-input"
+          className="form-check-input"
           id="deleteRecursively"
           type="checkbox"
           checked={isDeleteRecursively}
           onChange={changeIsDeleteRecursivelyHandler}
           // disabled // Todo: enable this at https://redmine.weseek.co.jp/issues/82222
         />
-        <label className="form-label custom-control-label" htmlFor="deleteRecursively">
+        <label className="form-label form-check-label" htmlFor="deleteRecursively">
           { t('modal_delete.delete_recursively') }
           <p className="form-text text-muted mt-0"> { t('modal_delete.recursively') }</p>
         </label>
@@ -201,9 +201,9 @@ const PageDeleteModal: FC = () => {
 
   function renderDeleteCompletelyForm() {
     return (
-      <div className="custom-control custom-checkbox custom-checkbox-danger">
+      <div className="form-check form-check-danger">
         <input
-          className="custom-control-input"
+          className="form-check-input"
           name="completely"
           id="deleteCompletely"
           type="checkbox"
@@ -211,7 +211,7 @@ const PageDeleteModal: FC = () => {
           checked={isDeleteCompletely}
           onChange={changeIsDeleteCompletelyHandler}
         />
-        <label className="form-label custom-control-label" htmlFor="deleteCompletely">
+        <label className="form-label form-check-label" htmlFor="deleteCompletely">
           { t('modal_delete.delete_completely')}
           <p className="form-text text-muted mt-0"> { t('modal_delete.completely') }</p>
         </label>

+ 6 - 6
apps/app/src/components/PageDuplicateModal.tsx

@@ -193,32 +193,32 @@ const PageDuplicateModal = (): JSX.Element => {
           <p className="text-danger">Error: Target path is duplicated.</p>
         ) }
 
-        <div className="custom-control custom-checkbox custom-checkbox-warning mb-3">
+        <div className="form-check form-check-warning mb-3">
           <input
-            className="custom-control-input"
+            className="form-check-input"
             name="recursively"
             id="cbDuplicateRecursively"
             type="checkbox"
             checked={isDuplicateRecursively}
             onChange={changeIsDuplicateRecursivelyHandler}
           />
-          <label className="form-label custom-control-label" htmlFor="cbDuplicateRecursively">
+          <label className="form-label form-check-label" htmlFor="cbDuplicateRecursively">
             { t('modal_duplicate.label.Recursively') }
             <p className="form-text text-muted mt-0">{ t('modal_duplicate.help.recursive') }</p>
           </label>
 
           <div>
             {isDuplicateRecursively && existingPaths.length !== 0 && (
-              <div className="custom-control custom-checkbox custom-checkbox-warning">
+              <div className="form-check form-check-warning">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="withoutExistRecursively"
                   id="cbDuplicatewithoutExistRecursively"
                   type="checkbox"
                   checked={isDuplicateRecursivelyWithoutExistPath}
                   onChange={() => setIsDuplicateRecursivelyWithoutExistPath(!isDuplicateRecursivelyWithoutExistPath)}
                 />
-                <label className="form-label custom-control-label" htmlFor="cbDuplicatewithoutExistRecursively">
+                <label className="form-label form-check-label" htmlFor="cbDuplicatewithoutExistRecursively">
                   { t('modal_duplicate.label.Duplicate without exist path') }
                 </label>
               </div>

+ 3 - 3
apps/app/src/components/PageEditor/GridEditModal.jsx

@@ -92,16 +92,16 @@ class GridEditModal extends React.Component {
     const { t } = this.props;
     const output = Object.entries(resSizeObj).map((responsiveSizeForMap) => {
       return (
-        <div key={responsiveSizeForMap[0]} className="custom-control custom-radio custom-control-inline">
+        <div key={responsiveSizeForMap[0]} className="form-check form-check-inline">
           <input
             type="radio"
-            className="custom-control-input"
+            className="form-check-input"
             id={responsiveSizeForMap[1].displayText}
             value={responsiveSizeForMap[1].displayText}
             checked={this.state.responsiveSize === responsiveSizeForMap[0]}
             onChange={e => this.checkResposiveSize(responsiveSizeForMap[0])}
           />
-          <label className="form-label custom-control-label" htmlFor={responsiveSizeForMap[1].displayText}>
+          <label className="form-label form-check-label" htmlFor={responsiveSizeForMap[1].displayText}>
             {t(responsiveSizeForMap[1].displayText)}
           </label>
         </div>

+ 6 - 6
apps/app/src/components/PageEditor/LinkEditModal.tsx

@@ -301,29 +301,29 @@ export const LinkEditModal = (): JSX.Element => {
           <div className="mb-0 row">
             <label className="form-label col-sm-3">{t('link_edit.path_format')}</label>
             <div className="col-sm-9">
-              <div className="custom-control custom-checkbox custom-checkbox-info custom-control-inline">
+              <div className="form-check form-check-info form-check-inline">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   id="relativePath"
                   type="checkbox"
                   checked={isUseRelativePath}
                   onChange={toggleIsUseRelativePath}
                   disabled={!linkInputValue.startsWith('/') || linkerType === Linker.types.growiLink}
                 />
-                <label className="form-label custom-control-label" htmlFor="relativePath">
+                <label className="form-label form-check-label" htmlFor="relativePath">
                   {t('link_edit.use_relative_path')}
                 </label>
               </div>
-              <div className="custom-control custom-checkbox custom-checkbox-info custom-control-inline">
+              <div className="form-check form-check-info form-check-inline">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   id="permanentLink"
                   type="checkbox"
                   checked={isUsePermanentLink}
                   onChange={toggleIsUsePamanentLink}
                   disabled={permalink === '' || linkerType === Linker.types.growiLink}
                 />
-                <label className="form-label custom-control-label" htmlFor="permanentLink">
+                <label className="form-label form-check-label" htmlFor="permanentLink">
                   {t('link_edit.use_permanent_link')}
                 </label>
               </div>

+ 66 - 57
apps/app/src/components/PageEditor/PageEditor.tsx

@@ -8,7 +8,7 @@ import nodePath from 'path';
 
 import type { IPageHasId } from '@growi/core';
 import { pathUtils } from '@growi/core/dist/utils';
-import { CodeMirrorEditorContainer, useCodeMirrorEditor } from '@growi/editor';
+import { CodeMirrorEditorContainer, useCodeMirrorEditorMain } from '@growi/editor';
 import detectIndent from 'detect-indent';
 import { useTranslation } from 'next-i18next';
 import { useRouter } from 'next/router';
@@ -85,7 +85,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   const { t } = useTranslation();
   const router = useRouter();
 
-  const editorRef = useRef<IEditorMethods>(null);
   const previewRef = useRef<HTMLDivElement>(null);
   const codeMirrorEditorContainerRef = useRef<HTMLDivElement>(null);
 
@@ -116,14 +115,8 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   const { mutate: mutateRemoteRevisionLastUpdatedAt } = useRemoteRevisionLastUpdatedAt();
   const { mutate: mutateRemoteRevisionLastUpdateUser } = useRemoteRevisionLastUpdateUser();
 
-  const { setContainer } = useCodeMirrorEditor({
-    container: codeMirrorEditorContainerRef.current,
-  });
-  useEffect(() => {
-    if (codeMirrorEditorContainerRef.current != null) {
-      setContainer(codeMirrorEditorContainerRef.current);
-    }
-  }, [setContainer]);
+  const { data: codemirrorEditor } = useCodeMirrorEditorMain(codeMirrorEditorContainerRef.current);
+  const { initDoc } = codemirrorEditor ?? {};
 
   const { data: rendererOptions } = usePreviewOptions();
   const { mutate: mutateIsEnabledUnsavedWarning } = useIsEnabledUnsavedWarning();
@@ -156,7 +149,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
 
   }, [isNotFound, currentPathname, editingMarkdown, isEnabledAttachTitleHeader, templateBodyData]);
 
-  const markdownToSave = useRef<string>(initialValue);
   const [markdownToPreview, setMarkdownToPreview] = useState<string>(initialValue);
 
   const { data: socket } = useGlobalSocket();
@@ -179,11 +171,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     setCreatedPageRevisionIdWithAttachment(undefined);
   }, [router]);
 
-  useEffect(() => {
-    markdownToSave.current = initialValue;
-    setMarkdownToPreview(initialValue);
-  }, [initialValue]);
-
   useEffect(() => {
     if (socket == null) { return }
 
@@ -211,7 +198,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   }, [grantData, isSlackEnabled, pageTags]);
 
   const setMarkdownWithDebounce = useMemo(() => debounce(100, throttle(150, (value: string, isClean: boolean) => {
-    markdownToSave.current = value;
     setMarkdownToPreview(value);
 
     // Displays an unsaved warning alert
@@ -235,7 +221,10 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
       mutateWaitingSaveProcessing(true);
 
       const { page } = await saveOrUpdate(
-        markdownToSave.current,
+        // TODO: get contents from the custom hook
+        // refs: https://redmine.weseek.co.jp/issues/128973
+        // markdownToSave.current,
+        '',
         { pageId, path: currentPagePath || currentPathname, revisionId: currentRevisionId },
         options,
       );
@@ -312,9 +301,11 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
    * @param {any} file
    */
   const uploadHandler = useCallback(async(file) => {
-    if (editorRef.current == null) {
-      return;
-    }
+    // TODO: implement
+    // refs: https://redmine.weseek.co.jp/issues/126528
+    // if (editorRef.current == null) {
+    //   return;
+    // }
 
     try {
       // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -335,9 +326,11 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
       if (pageId != null) {
         formData.append('page_id', pageId);
       }
-      if (pageId == null && markdownToSave.current != null) {
-        formData.append('page_body', markdownToSave.current);
-      }
+      // TODO: get contents from the custom hook
+      // refs: https://redmine.weseek.co.jp/issues/128973
+      // if (pageId == null && markdownToSave.current != null) {
+      //   formData.append('page_body', markdownToSave.current);
+      // }
 
       res = await apiPostForm('/attachments.add', formData);
       const attachment = res.attachment;
@@ -349,7 +342,9 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
         // modify to "![fileName](url)" syntax
         insertText = `!${insertText}`;
       }
-      editorRef.current.insertText(insertText);
+      // TODO: implement
+      // refs: https://redmine.weseek.co.jp/issues/126528
+      // editorRef.current.insertText(insertText);
 
       // when if created newly
       // Not using 'mutateGrant' to inherit the grant of the parent page
@@ -367,7 +362,9 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
       toastError(e);
     }
     finally {
-      editorRef.current.terminateUploadingState();
+      // TODO: implement
+      // refs: https://redmine.weseek.co.jp/issues/126528
+      // editorRef.current.terminateUploadingState();
     }
   }, [currentPagePath, mutateCurrentPage, mutateCurrentPageId, mutateIsLatestRevision, pageId]);
 
@@ -445,24 +442,24 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
    * scroll Editor component by scroll event of Preview component
    * @param {number} offset
    */
-  const scrollEditorByPreviewScroll = useCallback((offset: number) => {
-    if (editorRef.current == null || previewRef.current == null) {
-      return;
-    }
+  // const scrollEditorByPreviewScroll = useCallback((offset: number) => {
+  //   if (editorRef.current == null || previewRef.current == null) {
+  //     return;
+  //   }
 
-    // prevent circular invocation
-    if (isOriginOfScrollSyncEditor) {
-      isOriginOfScrollSyncEditor = false; // turn off the flag
-      return;
-    }
+  //   // prevent circular invocation
+  //   if (isOriginOfScrollSyncEditor) {
+  //     isOriginOfScrollSyncEditor = false; // turn off the flag
+  //     return;
+  //   }
 
-    // turn on the flag
-    // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    isOriginOfScrollSyncPreview = true;
+  //   // turn on the flag
+  //   // eslint-disable-next-line @typescript-eslint/no-unused-vars
+  //   isOriginOfScrollSyncPreview = true;
 
-    scrollSyncHelper.scrollEditor(editorRef.current, previewRef.current, offset);
-  }, []);
-  const scrollEditorByPreviewScrollWithThrottle = useMemo(() => throttle(20, scrollEditorByPreviewScroll), [scrollEditorByPreviewScroll]);
+  //   scrollSyncHelper.scrollEditor(editorRef.current, previewRef.current, offset);
+  // }, []);
+  // const scrollEditorByPreviewScrollWithThrottle = useMemo(() => throttle(20, scrollEditorByPreviewScroll), [scrollEditorByPreviewScroll]);
 
   const afterResolvedHandler = useCallback(async() => {
     // get page data from db
@@ -487,24 +484,29 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     if (initialValue == null) {
       return;
     }
-    markdownToSave.current = initialValue;
+    // markdownToSave.current = initialValue;
+    initDoc?.(initialValue);
     setMarkdownToPreview(initialValue);
     mutateIsEnabledUnsavedWarning(false);
-  }, [initialValue, mutateIsEnabledUnsavedWarning]);
+  }, [initDoc, initialValue, mutateIsEnabledUnsavedWarning]);
 
   // initial caret line
   useEffect(() => {
-    if (editorRef.current != null) {
-      editorRef.current.setCaretLine(0);
-    }
+    // TODO: implement
+    // refs: https://redmine.weseek.co.jp/issues/126516
+    // if (editorRef.current != null) {
+    //   editorRef.current.setCaretLine(0);
+    // }
   }, []);
 
   // set handler to set caret line
   useEffect(() => {
     const handler = (line) => {
-      if (editorRef.current != null) {
-        editorRef.current.setCaretLine(line);
-      }
+      // TODO: implement
+      // refs: https://redmine.weseek.co.jp/issues/126516
+      // if (editorRef.current != null) {
+      //   editorRef.current.setCaretLine(line);
+      // }
       if (previewRef.current != null) {
         scrollSyncHelper.scrollPreview(previewRef.current, line);
       }
@@ -527,9 +529,11 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
 
   // set handler to focus
   useEffect(() => {
-    if (editorRef.current != null && editorMode === EditorMode.Editor) {
-      editorRef.current.forceToFocus();
-    }
+    // TODO: implement
+    // refs: https://redmine.weseek.co.jp/issues/126516
+    // if (editorRef.current != null && editorMode === EditorMode.Editor) {
+    //   editorRef.current.forceToFocus();
+    // }
   }, [editorMode]);
 
   // Detect indent size from contents (only when users are allowed to change it)
@@ -551,9 +555,12 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   // when transitioning to a different page, if the initialValue is the same,
   // UnControlled CodeMirror value does not reset, so explicitly set the value to initialValue
   const onRouterChangeComplete = useCallback(() => {
-    editorRef.current?.setValue(initialValue);
-    editorRef.current?.setCaretLine(0);
-  }, [initialValue]);
+    initDoc?.(initialValue);
+
+    // TODO: implement
+    // refs: https://redmine.weseek.co.jp/issues/126516
+    // editorRef.current?.setCaretLine(0);
+  }, [initDoc, initialValue]);
 
   useEffect(() => {
     router.events.on('routeChangeComplete', onRouterChangeComplete);
@@ -573,7 +580,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   const isUploadable = isUploadableImage || isUploadableFile;
 
   return (
-    <div data-testid="page-editor" id="page-editor" className={`flex-grow-1 d-flex overflow-y-auto ${props.visibility ? '' : 'd-none'}`}>
+    <div data-testid="page-editor" id="page-editor" className={`flex-expand-horiz ${props.visibility ? '' : 'd-none'}`}>
       <div className="page-editor-editor-container flex-expand-vert">
         {/* <Editor
           ref={editorRef}
@@ -595,7 +602,9 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
           rendererOptions={rendererOptions}
           markdown={markdownToPreview}
           pagePath={currentPagePath}
-          onScroll={offset => scrollEditorByPreviewScrollWithThrottle(offset)}
+          // TODO: implement
+          // refs: https://redmine.weseek.co.jp/issues/126519
+          // onScroll={offset => scrollEditorByPreviewScrollWithThrottle(offset)}
         />
       </div>
       {/*

+ 6 - 6
apps/app/src/components/PageHistory/PageRevisionTable.tsx

@@ -157,33 +157,33 @@ export const PageRevisionTable = (props: PageRevisionTableProps): JSX.Element =>
         </td>
         <td className="col-1">
           {(hasDiff || revisionId === sourceRevision?._id) && (
-            <div className="custom-control custom-radio custom-control-inline mr-0">
+            <div className="form-check form-check-inline mr-0">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id={`compareSource-${revisionId}`}
                 name="compareSource"
                 value={revisionId}
                 checked={revisionId === sourceRevision?._id}
                 onChange={() => onChangeSourceInvoked(revision)}
               />
-              <label className="form-label custom-control-label" htmlFor={`compareSource-${revisionId}`} />
+              <label className="form-label form-check-label" htmlFor={`compareSource-${revisionId}`} />
             </div>
           )}
         </td>
         <td className="col-2">
           {(hasDiff || revisionId === targetRevision?._id) && (
-            <div className="custom-control custom-radio custom-control-inline mr-0">
+            <div className="form-check form-check-inline mr-0">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id={`compareTarget-${revisionId}`}
                 name="compareTarget"
                 value={revisionId}
                 checked={revisionId === targetRevision?._id}
                 onChange={() => onChangeTargetInvoked(revision)}
               />
-              <label className="form-label custom-control-label" htmlFor={`compareTarget-${revisionId}`} />
+              <label className="form-label form-check-label" htmlFor={`compareTarget-${revisionId}`} />
             </div>
           )}
         </td>

+ 12 - 12
apps/app/src/components/PageRenameModal.tsx

@@ -252,29 +252,29 @@ const PageRenameModal = (): JSX.Element => {
 
         { !isV5Compatible(page.meta) && (
           <>
-            <div className="custom-control custom-radio custom-radio-warning">
+            <div className="form-check form-check-warning">
               <input
-                className="custom-control-input"
+                className="form-check-input"
                 name="withoutExistRecursively"
                 id="cbRenameThisPageOnly"
                 type="radio"
                 checked={!isRenameRecursively}
                 onChange={() => setIsRenameRecursively(!isRenameRecursively)}
               />
-              <label className="form-label custom-control-label" htmlFor="cbRenameThisPageOnly">
+              <label className="form-label form-check-label" htmlFor="cbRenameThisPageOnly">
                 { t('modal_rename.label.Rename this page only') }
               </label>
             </div>
-            <div className="custom-control custom-radio custom-radio-warning mt-1">
+            <div className="form-check form-check-warning mt-1">
               <input
-                className="custom-control-input"
+                className="form-check-input"
                 name="recursively"
                 id="cbForceRenameRecursively"
                 type="radio"
                 checked={isRenameRecursively}
                 onChange={() => setIsRenameRecursively(!isRenameRecursively)}
               />
-              <label className="form-label custom-control-label" htmlFor="cbForceRenameRecursively">
+              <label className="form-label form-check-label" htmlFor="cbForceRenameRecursively">
                 { t('modal_rename.label.Force rename all child pages') }
                 <p className="form-text text-muted mt-0">{ t('modal_rename.help.recursive') }</p>
               </label>
@@ -292,31 +292,31 @@ const PageRenameModal = (): JSX.Element => {
           </button>
         </p>
         <Collapse isOpen={expandOtherOptions}>
-          <div className="custom-control custom-checkbox custom-checkbox-success">
+          <div className="form-check form-check-success">
             <input
-              className="custom-control-input"
+              className="form-check-input"
               name="create_redirect"
               id="cbRenameRedirect"
               type="checkbox"
               checked={isRenameRedirect}
               onChange={() => setIsRenameRedirect(!isRenameRedirect)}
             />
-            <label className="form-label custom-control-label" htmlFor="cbRenameRedirect">
+            <label className="form-label form-check-label" htmlFor="cbRenameRedirect">
               { t('modal_rename.label.Redirect') }
               <p className="form-text text-muted mt-0">{ t('modal_rename.help.redirect') }</p>
             </label>
           </div>
 
-          <div className="custom-control custom-checkbox custom-checkbox-success">
+          <div className="form-check form-check-success">
             <input
-              className="custom-control-input"
+              className="form-check-input"
               name="remain_metadata"
               id="cbRemainMetadata"
               type="checkbox"
               checked={isRemainMetadata}
               onChange={() => setIsRemainMetadata(!isRemainMetadata)}
             />
-            <label className="form-label custom-control-label" htmlFor="cbRemainMetadata">
+            <label className="form-label form-check-label" htmlFor="cbRemainMetadata">
               { t('modal_rename.label.Do not update metadata') }
               <p className="form-text text-muted mt-0">{ t('modal_rename.help.metadata') }</p>
             </label>

+ 1 - 1
apps/app/src/components/PrivateLegacyPages.tsx

@@ -103,7 +103,7 @@ const SearchResultListHead = React.memo((props: SearchResultListHeadProps): JSX.
           </div>
           <select
             defaultValue={pagingSize}
-            className="custom-select"
+            className="form-select"
             id="inputGroupSelect01"
             onChange={e => onPagingSizeChanged(Number(e.target.value))}
           >

+ 3 - 3
apps/app/src/components/PrivateLegacyPagesMigrationModal.tsx

@@ -47,9 +47,9 @@ export const PrivateLegacyPagesMigrationModal = (): JSX.Element => {
 
   function renderForm() {
     return (
-      <div className="custom-control custom-checkbox custom-checkbox-warning">
+      <div className="form-check form-check-warning">
         <input
-          className="custom-control-input"
+          className="form-check-input"
           id="convertRecursively"
           type="checkbox"
           checked={isRecursively}
@@ -57,7 +57,7 @@ export const PrivateLegacyPagesMigrationModal = (): JSX.Element => {
             setIsRecursively(e.target.checked);
           }}
         />
-        <label className="form-label custom-control-label" htmlFor="convertRecursively">
+        <label className="form-label form-check-label" htmlFor="convertRecursively">
           { t('private_legacy_pages.modal.convert_recursively_label') }
           <p className="form-text text-muted mt-0"> { t('private_legacy_pages.modal.convert_recursively_desc') }</p>
         </label>

+ 3 - 3
apps/app/src/components/PutbackPageModal.jsx

@@ -75,15 +75,15 @@ const PutBackPageModal = () => {
           <label className="form-label">{t('modal_putback.label.Put Back Page')}:</label><br />
           <code>{path}</code>
         </div>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
-            className="custom-control-input"
+            className="form-check-input"
             id="cbPutBackRecursively"
             type="checkbox"
             checked={isPutbackRecursively}
             onChange={changeIsPutbackRecursivelyHandler}
           />
-          <label htmlFor="cbPutBackRecursively" className="custom-control-label form-label">
+          <label htmlFor="cbPutBackRecursively" className="form-label form-check-label">
             { t('modal_putback.label.recursively') }
           </label>
           <p className="form-text text-muted mt-0">

+ 1 - 1
apps/app/src/components/SearchPage.tsx

@@ -73,7 +73,7 @@ const SearchResultListHead = React.memo((props: SearchResultListHeadProps): JSX.
         </div>
         <select
           defaultValue={pagingSize}
-          className="custom-select"
+          className="form-select"
           id="inputGroupSelect01"
           onChange={e => onPagingSizeChanged(Number(e.target.value))}
         >

+ 6 - 6
apps/app/src/components/SearchPage/SearchControl.tsx

@@ -122,16 +122,16 @@ const SearchControl = React.memo((props: Props): JSX.Element => {
             </div>
             <div className="d-none d-lg-flex align-items-center ml-auto search-control-include-options">
               <div className="border rounded px-2 py-1 mr-3">
-                <div className="custom-control custom-checkbox custom-checkbox-succsess">
+                <div className="form-check form-check-succsess">
                   <input
-                    className="custom-control-input mr-2"
+                    className="form-check-input mr-2"
                     type="checkbox"
                     id="flexCheckDefault"
                     defaultChecked={includeUserPages}
                     onChange={e => setIncludeUserPages(e.target.checked)}
                   />
                   <label
-                    className="form-label custom-control-label mb-0 d-flex align-items-center text-secondary with-no-font-weight"
+                    className="form-label form-check-label mb-0 d-flex align-items-center text-secondary with-no-font-weight"
                     htmlFor="flexCheckDefault"
                   >
                     {t('Include Subordinated Target Page', { target: '/user' })}
@@ -139,16 +139,16 @@ const SearchControl = React.memo((props: Props): JSX.Element => {
                 </div>
               </div>
               <div className="border rounded px-2 py-1">
-                <div className="custom-control custom-checkbox custom-checkbox-succsess">
+                <div className="form-check form-check-succsess">
                   <input
-                    className="custom-control-input mr-2"
+                    className="form-check-input mr-2"
                     type="checkbox"
                     id="flexCheckChecked"
                     checked={includeTrashPages}
                     onChange={e => setIncludeTrashPages(e.target.checked)}
                   />
                   <label
-                    className="form-label custom-control-label d-flex align-items-center text-secondary with-no-font-weight"
+                    className="form-label form-check-label d-flex align-items-center text-secondary with-no-font-weight"
                     htmlFor="flexCheckChecked"
                   >
                     {t('Include Subordinated Target Page', { target: '/trash' })}

+ 1 - 1
apps/app/src/components/SearchPage/SearchPageBase.tsx

@@ -169,7 +169,7 @@ const SearchPageBaseSubstance: ForwardRefRenderFunction<ISelectableAll & IReturn
     : undefined;
 
   return (
-    <div className="search-result-base flex-grow-1 d-flex overflow-y-auto" data-testid="search-result-base">
+    <div className="search-result-base flex-expand-horiz" data-testid="search-result-base">
 
       <div className="flex-expand-vert border boder-gray search-result-list" id="search-result-list">
 

+ 1 - 3
apps/app/src/components/SearchPage/SearchResultContent.tsx

@@ -213,9 +213,7 @@ export const SearchResultContent: FC<Props> = (props: Props) => {
     <div
       key={page._id}
       data-testid="search-result-content"
-      className={`search-result-content ${styles['search-result-content']}
-        dynamic-layout-root ${growiLayoutFluidClass}
-        overflow-y-auto`}
+      className={`dynamic-layout-root ${growiLayoutFluidClass} search-result-content ${styles['search-result-content']}`}
     >
       <div className="grw-page-path-text-muted-container">
         { isRenderable && (

+ 9 - 9
apps/app/src/components/Sidebar/AppearanceModeDropdown.tsx

@@ -80,15 +80,15 @@ export const AppearanceModeDropdown:FC<AppearanceModeDropdownProps> = (props: Ap
               <IconWithTooltip id={isEditMode ? 'iwt-sidebar-editor-drawer' : 'iwt-sidebar-drawer'} label="Drawer" additionalClasses="grw-sidebar-mode-icon">
                 <SidebarDrawerIcon />
               </IconWithTooltip>
-              <div className="custom-control custom-switch custom-checkbox-secondary ml-2">
+              <div className="form-check form-switch form-check-secondary ml-2">
                 <input
                   id={isEditMode ? 'swSidebarModeOnEditor' : 'swSidebarMode'}
-                  className="custom-control-input"
+                  className="form-check-input"
                   type="checkbox"
                   checked={isEditMode ? !isPreferDrawerModeOnEdit : !isPreferDrawerMode}
                   onChange={e => preferDrawerModeSwitchModifiedHandler(!e.target.checked, isEditMode)}
                 />
-                <label className="form-label custom-control-label" htmlFor={isEditMode ? 'swSidebarModeOnEditor' : 'swSidebarMode'}></label>
+                <label className="form-label form-check-label" htmlFor={isEditMode ? 'swSidebarModeOnEditor' : 'swSidebarMode'}></label>
               </div>
               <IconWithTooltip id={isEditMode ? 'iwt-sidebar-editor-dock' : 'iwt-sidebar-dock'} label="Dock" additionalClasses="grw-sidebar-mode-icon">
                 <SidebarDockIcon />
@@ -134,16 +134,16 @@ export const AppearanceModeDropdown:FC<AppearanceModeDropdownProps> = (props: Ap
                   <IconWithTooltip id="iwt-light" label="Light" additionalClasses={useOsSettings ? 'grw-color-mode-icon-muted' : 'grw-color-mode-icon'}>
                     <SunIcon />
                   </IconWithTooltip>
-                  <div className="custom-control custom-switch custom-checkbox-secondary ml-2">
+                  <div className="form-check form-switch form-check-secondary ml-2">
                     <input
                       id="swUserPreference"
-                      className="custom-control-input"
+                      className="form-check-input"
                       type="checkbox"
                       checked={isDarkMode}
                       disabled={useOsSettings}
                       onChange={e => userPreferenceSwitchModifiedHandler(e.target.checked)}
                     />
-                    <label className="form-label custom-control-label" htmlFor="swUserPreference"></label>
+                    <label className="form-label form-check-label" htmlFor="swUserPreference"></label>
                   </div>
                   <IconWithTooltip id="iwt-dark" label="Dark" additionalClasses={useOsSettings ? 'grw-color-mode-icon-muted' : 'grw-color-mode-icon'}>
                     <MoonIcon />
@@ -152,15 +152,15 @@ export const AppearanceModeDropdown:FC<AppearanceModeDropdownProps> = (props: Ap
               </div>
               <div>
                 <div className="col-auto">
-                  <div className="custom-control custom-checkbox">
+                  <div className="form-check">
                     <input
                       id="cbFollowOs"
-                      className="custom-control-input"
+                      className="form-check-input"
                       type="checkbox"
                       checked={useOsSettings}
                       onChange={e => followOsCheckboxModifiedHandler(e.target.checked)}
                     />
-                    <label className="form-label custom-control-label text-nowrap" htmlFor="cbFollowOs">{t('personal_dropdown.use_os_settings')}</label>
+                    <label className="form-label form-check-label text-nowrap" htmlFor="cbFollowOs">{t('personal_dropdown.use_os_settings')}</label>
                   </div>
                 </div>
               </div>

+ 2 - 2
apps/app/src/components/Sidebar/RecentChanges/RecentChangesSubstance.module.scss

@@ -5,12 +5,12 @@
   line-height: normal;
   transform: translateY(-2px);
 
-  .custom-control-label::before {
+  .form-check-label::before {
     padding-left: 19px;
     content: 'L';
   }
 
-  .custom-control-input:checked + .custom-control-label::before {
+  .form-check-input:checked + .form-check-label::before {
     padding-left: 5px;
     content: 'S';
   }

+ 3 - 3
apps/app/src/components/Sidebar/RecentChanges/RecentChangesSubstance.tsx

@@ -133,15 +133,15 @@ export const RecentChangesHeader = ({ isSmall, onSizeChange }: HeaderProps): JSX
     <>
       <SidebarHeaderReloadButton onClick={() => mutate()} />
       <div className="d-flex align-items-center">
-        <div className={`grw-recent-changes-resize-button ${styles['grw-recent-changes-resize-button']} custom-control custom-switch ml-1`}>
+        <div className={`grw-recent-changes-resize-button ${styles['grw-recent-changes-resize-button']} form-check form-switch ml-1`}>
           <input
             id="recentChangesResize"
-            className="custom-control-input"
+            className="form-check-input"
             type="checkbox"
             checked={isSmall}
             onChange={changeSizeHandler}
           />
-          <label className="form-label custom-control-label" htmlFor="recentChangesResize" />
+          <label className="form-label form-check-label" htmlFor="recentChangesResize" />
         </div>
       </div>
     </>

+ 2 - 2
apps/app/src/components/SlackNotification.module.scss

@@ -2,7 +2,7 @@
 
 // TODO: activate (https://redmine.weseek.co.jp/issues/128307)
 .grw-slack-notification :global {
-  // $input-height-slack: bs.$custom-control-indicator-size * 1.5;
+  // $input-height-slack: bs.$form-check-indicator-size * 1.5;
   // border-color: bs.$gray-200;
 
   // border-style: solid;
@@ -34,7 +34,7 @@
   //   }
   // }
 
-  // .custom-control-label {
+  // .form-check-label {
   //   &::before {
   //     border: transparent;
   //   }

+ 3 - 3
apps/app/src/components/SlackNotification.tsx

@@ -40,15 +40,15 @@ export const SlackNotification: FC<SlackNotificationProps> = ({
     <div className={`grw-slack-notification ${styles['grw-slack-notification']} w-100`}>
       <div className="grw-input-group-slack-notification input-group extended-setting">
         <label className="form-label input-group-addon">
-          <div className="custom-control custom-switch custom-switch-lg custom-switch-slack">
+          <div className="form-check form-switch form-switch-lg form-switch-slack">
             <input
               type="checkbox"
-              className="custom-control-input border-0"
+              className="form-check-input border-0"
               id={id}
               checked={isSlackEnabled}
               onChange={updateCheckboxHandler}
             />
-            <label className="form-label custom-control-label align-center" htmlFor={id}></label>
+            <label className="form-label form-check-label align-center" htmlFor={id}></label>
           </div>
         </label>
         <input

+ 3 - 3
apps/app/src/components/TemplateTab.tsx

@@ -13,16 +13,16 @@ export const TemplateTab = (props: Props): JSX.Element => {
   const { template, onChangeHandler } = props;
 
   return (
-    <div key={template.name} className="custom-control custom-radio">
+    <div key={template.name} className="form-check">
       <input
         type="radio"
-        className="custom-control-input"
+        className="form-check-input"
         id="string"
         value={template.value}
         // checked={this.state.linkerType === template.value}
         onChange={onChangeHandler}
       />
-      <label className="form-label custom-control-label" htmlFor="string">
+      <label className="form-label form-check-label" htmlFor="string">
         {template.name}
       </label>
     </div>

+ 6 - 0
apps/app/src/stores/use-static-swr.ts

@@ -0,0 +1,6 @@
+import { useSWRStatic } from '@growi/core/dist/swr';
+
+/**
+ * @deprecated Import { uswSWRStatic } from '@growi/core/dist/swr' instead.
+ */
+export const useStaticSWR = useSWRStatic;

+ 0 - 35
apps/app/src/stores/use-static-swr.tsx

@@ -1,35 +0,0 @@
-import assert from 'assert';
-
-import {
-  Key, SWRConfiguration, SWRResponse, useSWRConfig,
-} from 'swr';
-import useSWRImmutable from 'swr/immutable';
-
-
-export function useStaticSWR<Data, Error>(key: Key): SWRResponse<Data, Error>;
-export function useStaticSWR<Data, Error>(key: Key, data: Data | undefined): SWRResponse<Data, Error>;
-export function useStaticSWR<Data, Error>(key: Key, data: Data | undefined,
-  configuration: SWRConfiguration<Data, Error> | undefined): SWRResponse<Data, Error>;
-
-export function useStaticSWR<Data, Error>(
-    ...args: readonly [Key]
-    | readonly [Key, Data | undefined]
-    | readonly [Key, Data | undefined, SWRConfiguration<Data, Error> | undefined]
-): SWRResponse<Data, Error> {
-  const [key, data, configuration] = args;
-
-  assert.notStrictEqual(configuration?.fetcher, null, 'useStaticSWR does not support \'configuration.fetcher\'');
-
-  const { cache } = useSWRConfig();
-  const swrResponse = useSWRImmutable(key, null, {
-    ...configuration,
-    fallbackData: configuration?.fallbackData ?? cache.get(key)?.data,
-  });
-
-  // write data to cache directly
-  if (data !== undefined) {
-    cache.set(key, { ...cache.get(key), data });
-  }
-
-  return swrResponse;
-}

+ 42 - 42
apps/app/src/styles/atoms/_custom_control.scss

@@ -2,84 +2,84 @@
 
 // TODO: activate (https://redmine.weseek.co.jp/issues/128307)
 
-// .custom-checkbox .custom-control-label::before {
+// .form-check .form-check-label::before {
 //   border-radius: $border-radius !important;
 // }
 
-// label.custom-control-label {
+// label.form-check-label {
 //   font-weight: normal;
 // }
 
-// .custom-switch.custom-switch-sm {
-//   $custom-control-indicator-size-sm: $custom-control-indicator-size * 0.8;
-//   $custom-switch-width-sm: $custom-control-indicator-size-sm * 1.75;
-//   $custom-control-gutter-sm: $custom-control-gutter * 0.8;
-//   $custom-control-indicator-size-sm: $custom-control-indicator-size * 0.8;
-//   $custom-switch-indicator-size-sm: subtract($custom-control-indicator-size-sm, $custom-control-indicator-border-width * 4);
+// .form-switch.form-switch-sm {
+//   $form-check-indicator-size-sm: $form-check-indicator-size * 0.8;
+//   $form-switch-width-sm: $form-check-indicator-size-sm * 1.75;
+//   $form-check-gutter-sm: $form-check-gutter * 0.8;
+//   $form-check-indicator-size-sm: $form-check-indicator-size * 0.8;
+//   $form-switch-indicator-size-sm: subtract($form-check-indicator-size-sm, $form-check-indicator-border-width * 4);
 
-//   padding-left: $custom-switch-width-sm + $custom-control-gutter-sm;
+//   padding-left: $form-switch-width-sm + $form-check-gutter-sm;
 
-//   .custom-control-label {
+//   .form-check-label {
 //     &::before {
-//       left: -($custom-switch-width-sm + $custom-control-gutter-sm);
-//       width: $custom-switch-width-sm;
-//       height: $custom-control-indicator-size-sm;
+//       left: -($form-switch-width-sm + $form-check-gutter-sm);
+//       width: $form-switch-width-sm;
+//       height: $form-check-indicator-size-sm;
 //     }
 
 //     &::after {
-//       top: add(($font-size-base * $line-height-base - $custom-control-indicator-size) / 2, $custom-control-indicator-border-width * 2);
-//       left: add(-($custom-switch-width-sm + $custom-control-gutter-sm), $custom-control-indicator-border-width * 2);
-//       width: $custom-switch-indicator-size-sm;
-//       height: $custom-switch-indicator-size-sm;
+//       top: add(($font-size-base * $line-height-base - $form-check-indicator-size) / 2, $form-check-indicator-border-width * 2);
+//       left: add(-($form-switch-width-sm + $form-check-gutter-sm), $form-check-indicator-border-width * 2);
+//       width: $form-switch-indicator-size-sm;
+//       height: $form-switch-indicator-size-sm;
 //     }
 //   }
 
-//   .custom-control-input:checked ~ .custom-control-label {
+//   .form-check-input:checked ~ .form-check-label {
 //     &::after {
-//       transform: translateX($custom-switch-width-sm - $custom-control-indicator-size-sm);
+//       transform: translateX($form-switch-width-sm - $form-check-indicator-size-sm);
 //     }
 //   }
 // }
 
 // //lg
-// .custom-switch.custom-switch-lg {
-//   $custom-control-indicator-size-lg: $custom-control-indicator-size * 1.5;
-//   $custom-switch-width-lg: $custom-control-indicator-size-lg * 1.75;
-//   $custom-control-gutter-lg: $custom-control-gutter * 1.5;
-//   $custom-control-indicator-size-lg: $custom-control-indicator-size * 1.5;
-//   $custom-switch-indicator-size-lg: subtract($custom-control-indicator-size-lg, $custom-control-indicator-border-width * 4);
+// .form-switch.form-switch-lg {
+//   $form-check-indicator-size-lg: $form-check-indicator-size * 1.5;
+//   $form-switch-width-lg: $form-check-indicator-size-lg * 1.75;
+//   $form-check-gutter-lg: $form-check-gutter * 1.5;
+//   $form-check-indicator-size-lg: $form-check-indicator-size * 1.5;
+//   $form-switch-indicator-size-lg: subtract($form-check-indicator-size-lg, $form-check-indicator-border-width * 4);
 
-//   padding-left: $custom-switch-width-lg + $custom-control-gutter-lg;
+//   padding-left: $form-switch-width-lg + $form-check-gutter-lg;
 
-//   line-height: $custom-control-indicator-size-lg;
-//   .custom-control-label {
+//   line-height: $form-check-indicator-size-lg;
+//   .form-check-label {
 //     &::before {
-//       top: ($font-size-base * $line-height-base - $custom-control-indicator-size-lg) / 2;
+//       top: ($font-size-base * $line-height-base - $form-check-indicator-size-lg) / 2;
 
-//       left: -($custom-switch-width-lg + $custom-control-gutter-lg);
-//       width: $custom-switch-width-lg;
-//       height: $custom-control-indicator-size-lg;
-//       border-radius: $custom-control-indicator-size-lg/2;
+//       left: -($form-switch-width-lg + $form-check-gutter-lg);
+//       width: $form-switch-width-lg;
+//       height: $form-check-indicator-size-lg;
+//       border-radius: $form-check-indicator-size-lg/2;
 //     }
 
 //     &::after {
-//       top: add(($font-size-base * $line-height-base - $custom-control-indicator-size-lg) / 2, $custom-control-indicator-border-width * 2);
-//       left: add(-($custom-switch-width-lg + $custom-control-gutter-lg), $custom-control-indicator-border-width * 2);
-//       width: $custom-switch-indicator-size-lg;
-//       height: $custom-switch-indicator-size-lg;
-//       border-radius: $custom-control-indicator-size-lg/2;
+//       top: add(($font-size-base * $line-height-base - $form-check-indicator-size-lg) / 2, $form-check-indicator-border-width * 2);
+//       left: add(-($form-switch-width-lg + $form-check-gutter-lg), $form-check-indicator-border-width * 2);
+//       width: $form-switch-indicator-size-lg;
+//       height: $form-switch-indicator-size-lg;
+//       border-radius: $form-check-indicator-size-lg/2;
 //     }
 //   }
 
-//   .custom-control-input:checked ~ .custom-control-label {
+//   .form-check-input:checked ~ .form-check-label {
 //     &::after {
-//       transform: translateX($custom-switch-width-lg - $custom-control-indicator-size-lg);
+//       transform: translateX($form-switch-width-lg - $form-check-indicator-size-lg);
 //     }
 //   }
 // }
 
-// .custom-switch.custom-switch-slack {
-//   .custom-control-label {
+// .form-switch.form-switch-slack {
+//   .form-check-label {
 //     &::before {
 //       background-color: $gray-200;
 //       border-color: transparent;

+ 4 - 4
apps/app/src/styles/theme/_apply-colors-dark.scss

@@ -76,7 +76,7 @@
   //     */
   //   input.form-control,
   //   select.form-control,
-  //   select.custom-select,
+  //   select.form-select,
   //   textarea.form-control {
   //     color: var(--color-global);
   //     background-color: hsl.darken(var(--bgcolor-global), 5%);
@@ -108,7 +108,7 @@
   //     border-color: $border-color-global;
   //   }
 
-  //   label.custom-control-label::before {
+  //   label.form-check-label::before {
   //     background-color: hsl.darken(var(--bgcolor-global),5%);
   //   }
 
@@ -523,7 +523,7 @@
   //       background: var(--bgcolor-global);
   //     }
 
-  //     .custom-control-label {
+  //     .form-check-label {
   //       &::before {
   //         background-color: var(--secondary);
   //         border-color: transparent;
@@ -534,7 +534,7 @@
   //       }
   //     }
 
-  //     .custom-control-input:checked ~ .custom-control-label {
+  //     .form-check-input:checked ~ .form-check-label {
   //       &::before {
   //         background-color: lighten($color-slack, 10%);
   //       }

+ 2 - 2
apps/app/src/styles/theme/_apply-colors-light.scss

@@ -403,7 +403,7 @@
       background: white;
     }
 
-    .custom-control-label {
+    .form-check-label {
       &::before {
         background-color: $gray-200;
         border-color: transparent;
@@ -413,7 +413,7 @@
         background-image: url(/images/icons/slack/slack-logo-off.svg);
       }
     }
-    .custom-control-input:checked ~ .custom-control-label {
+    .form-check-input:checked ~ .form-check-label {
       &::before {
         background-color: lighten($color-slack, 60%);
       }

+ 6 - 6
apps/app/src/styles/theme/_reboot-bootstrap-theme-colors.scss

@@ -47,24 +47,24 @@
 }
 
 @each $theme-color, $color in $theme-colors {
-  .custom-checkbox-#{$theme-color} {
-    .custom-control-label::before {
+  .form-check-#{$theme-color} {
+    .form-check-label::before {
       border-color: $input-border-color;
       transition: 0.3s ease-in-out;
     }
-    .custom-control-input:checked + .custom-control-label::before {
+    .form-check-input:checked + .form-check-label::before {
       background-color: $color;
       border-color: $color;
     }
-    .custom-control-input:checked + .custom-control-label::after {
+    .form-check-input:checked + .form-check-label::after {
       color: var(--bgcolor-global);
     }
-    .custom-control-input:not(:disabled):active ~ .custom-control-label::before {
+    .form-check-input:not(:disabled):active ~ .form-check-label::before {
       color: var(--bgcolor-global);
       background-color: $color;
       border-color: $color;
     }
-    .custom-control-input:focus:not(:checked) ~ .custom-control-label::before {
+    .form-check-input:focus:not(:checked) ~ .form-check-label::before {
       color: var(--bgcolor-global);
       background-color: var(--bgcolor-global);
       border-color: $input-focus-border-color;

+ 5 - 5
apps/app/src/styles/theme/apply-colors.scss

@@ -260,24 +260,24 @@ ul.pagination {
     }
 
     .grw-recent-changes-resize-button {
-      .custom-control-label::before {
+      .form-check-label::before {
         background-color: var(--primary);
       }
 
-      .custom-control-label::after {
+      .form-check-label::after {
         background-color: var(--bgcolor-global);
       }
 
-      .custom-control-input:not(:checked) + .custom-control-label::before {
+      .form-check-input:not(:checked) + .form-check-label::before {
         color: var(--bgcolor-global);
       }
 
-      .custom-control-input:checked + .custom-control-label::before {
+      .form-check-input:checked + .form-check-label::before {
         color: var(--bgcolor-global);
         background-color: var(--primary);
         border-color: var(--primary);
       }
-      .custom-control-input:checked + .custom-control-label::after {
+      .form-check-input:checked + .form-check-label::after {
         color: var(--bgcolor-global);
       }
     }

+ 3 - 3
packages/core/scss/bootstrap/_override.scss

@@ -61,9 +61,9 @@
 // }
 
 // // Custom Control
-// .custom-control {
-//   .custom-control-input,
-//   .custom-control-input + .custom-control-label {
+// .form-check {
+//   .form-check-input,
+//   .form-check-input + .form-check-label {
 //     cursor: pointer;
 //   }
 // }

+ 7 - 7
packages/core/scss/bootstrap/_variables.scss

@@ -98,10 +98,10 @@ $font-family-base: $font-family-sans-serif;
 // $input-border-color: $gray-300;
 // $input-placeholder-color: $gray-500;
 
-// $custom-control-indicator-border-color: $gray-400;
-// $custom-control-label-disabled-color: $gray-500;
-// $custom-select-disabled-color: $gray-500;
-// $custom-range-thumb-disabled-bg: $gray-400;
+// $form-check-indicator-border-color: $gray-400;
+// $form-check-label-disabled-color: $gray-500;
+// $form-select-disabled-color: $gray-500;
+// $form-range-thumb-disabled-bg: $gray-400;
 
 //== Navs
 // $nav-link-padding-y: 0.75rem;
@@ -163,6 +163,6 @@ $font-family-base: $font-family-sans-serif;
 $pre-color: dummyinvalildcolor; // disable pre color specification with invalid value
 
 //== Custom Checkbox
-// $custom-checkbox-indicator-border-radius: 0px;
-// $custom-control-indicator-focus-box-shadow: none;
-// $custom-control-indicator-size: 1.2rem;
+// $form-check-indicator-border-radius: 0px;
+// $form-check-indicator-focus-box-shadow: none;
+// $form-check-indicator-size: 1.2rem;

+ 4 - 1
packages/core/scss/placeholders/_flex-expand.scss

@@ -1,8 +1,10 @@
 // ref: https://discuss.codemirror.net/t/how-to-fit-the-codemirror-6-widget-into-a-flex-div/4207/4
 %flex-expand-horiz {
   display: flex;
-  flex: 1;
   flex-direction: row;
+  flex-grow: 1;
+  height: 100%;
+  overflow-y: auto;
 }
 
 // ref: https://discuss.codemirror.net/t/how-to-fit-the-codemirror-6-widget-into-a-flex-div/4207/4
@@ -10,4 +12,5 @@
   display: flex;
   flex: 1;
   flex-direction: column;
+  overflow-y: auto;
 }

+ 1 - 0
packages/core/src/swr/index.ts

@@ -1 +1,2 @@
+export * from './use-swr-static';
 export * from './with-utils';

+ 7 - 5
packages/editor/src/stores/use-static-swr.tsx → packages/core/src/swr/use-swr-static.ts

@@ -4,19 +4,21 @@ import {
 import useSWRImmutable from 'swr/immutable';
 
 
-export function useStaticSWR<Data, Error>(key: Key): SWRResponse<Data, Error>;
-export function useStaticSWR<Data, Error>(key: Key, data: Data | undefined): SWRResponse<Data, Error>;
-export function useStaticSWR<Data, Error>(key: Key, data: Data | undefined,
+export function useSWRStatic<Data, Error>(key: Key): SWRResponse<Data, Error>;
+export function useSWRStatic<Data, Error>(key: Key, data: Data | undefined): SWRResponse<Data, Error>;
+export function useSWRStatic<Data, Error>(key: Key, data: Data | undefined,
   configuration: SWRConfiguration<Data, Error> | undefined): SWRResponse<Data, Error>;
 
-export function useStaticSWR<Data, Error>(
+export function useSWRStatic<Data, Error>(
     ...args: readonly [Key]
     | readonly [Key, Data | undefined]
     | readonly [Key, Data | undefined, SWRConfiguration<Data, Error> | undefined]
 ): SWRResponse<Data, Error> {
   const [key, data, configuration] = args;
 
-  // assert.notStrictEqual(configuration?.fetcher, null, 'useStaticSWR does not support \'configuration.fetcher\'');
+  if (configuration?.fetcher != null) {
+    throw new Error("useSWRStatic does not support 'configuration.fetcher'");
+  }
 
   const { cache } = useSWRConfig();
   const swrResponse = useSWRImmutable(key, null, {

+ 2 - 4
packages/editor/src/components/playground/Playground.tsx

@@ -9,16 +9,14 @@ export const Playground = (): JSX.Element => {
 
   const containerRef = useRef(null);
 
-  useCodeMirrorEditorMain({
-    container: containerRef.current,
-  });
+  useCodeMirrorEditorMain(containerRef.current);
 
   return (
     <>
       <div className="flex-expand-vert justify-content-center align-items-center bg-dark" style={{ minHeight: '83px' }}>
         <div className="text-white">GrowiSubNavigation</div>
       </div>
-      <div className="flex-grow-1 d-flex overflow-y-auto">
+      <div className="flex-expand-horiz">
         <div className="flex-expand-vert">
           <CodeMirrorEditorContainer ref={containerRef} />
         </div>

+ 4 - 14
packages/editor/src/components/playground/PlaygroundController.tsx

@@ -4,22 +4,12 @@ import { useCodeMirrorEditorMain } from '../../stores';
 
 export const PlaygroundController = (): JSX.Element => {
 
-  const { data: states } = useCodeMirrorEditorMain();
+  const { data } = useCodeMirrorEditorMain();
 
+  const initDoc = data?.initDoc;
   const initEditorValue = useCallback(() => {
-    if (states == null) {
-      return;
-    }
-
-    states.view?.dispatch({
-      changes: {
-        from: 0,
-        to: states.view.state.doc.toString().length,
-        insert: '# Header\n\n- foo\n-bar\n',
-      },
-    });
-
-  }, [states]);
+    initDoc?.('# Header\n\n- foo\n-bar\n');
+  }, [initDoc]);
 
   return (
     <>

+ 1 - 0
packages/editor/src/index.ts

@@ -1,2 +1,3 @@
 export * from './components';
 export * from './services';
+export * from './stores';

+ 0 - 42
packages/editor/src/services/codemirror-editor.ts

@@ -1,42 +0,0 @@
-import { useEffect } from 'react';
-
-import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
-import { languages } from '@codemirror/language-data';
-import { EditorState, Extension } from '@codemirror/state';
-import { EditorView, scrollPastEnd } from '@codemirror/view';
-import { useCodeMirror, type UseCodeMirror } from '@uiw/react-codemirror';
-
-
-export type UseCodeMirrorEditor = UseCodeMirror;
-
-export type UseCodeMirrorEditorStates = {
-  state: EditorState | undefined;
-  setState: import('react').Dispatch<import('react').SetStateAction<EditorState | undefined>>;
-  view: EditorView | undefined;
-  setView: import('react').Dispatch<import('react').SetStateAction<EditorView | undefined>>;
-  container: HTMLDivElement | undefined;
-  setContainer: import('react').Dispatch<import('react').SetStateAction<HTMLDivElement | undefined>>;
-}
-
-const defaultExtensions: Extension[] = [
-  markdown({ base: markdownLanguage, codeLanguages: languages }),
-  scrollPastEnd(),
-];
-
-export const useCodeMirrorEditor = (props?: UseCodeMirrorEditor): UseCodeMirrorEditorStates => {
-
-  const codemirror = useCodeMirror({
-    extensions: defaultExtensions,
-    ...props,
-  });
-
-  const { setContainer } = codemirror;
-
-  useEffect(() => {
-    if (props?.container != null) {
-      setContainer(props.container);
-    }
-  }, [props?.container, setContainer]);
-
-  return codemirror;
-};

+ 1 - 0
packages/editor/src/services/codemirror-editor/index.ts

@@ -0,0 +1 @@
+export * from './use-codemirror-editor';

+ 11 - 0
packages/editor/src/services/codemirror-editor/interfaces/react-codemirror.ts

@@ -0,0 +1,11 @@
+import type { EditorState } from '@codemirror/state';
+import type { EditorView } from '@codemirror/view';
+
+export type UseCodeMirrorEditorStates = {
+  state: EditorState | undefined;
+  setState: import('react').Dispatch<import('react').SetStateAction<EditorState | undefined>>;
+  view: EditorView | undefined;
+  setView: import('react').Dispatch<import('react').SetStateAction<EditorView | undefined>>;
+  container: HTMLDivElement | undefined;
+  setContainer: import('react').Dispatch<import('react').SetStateAction<HTMLDivElement | undefined>>;
+}

+ 70 - 0
packages/editor/src/services/codemirror-editor/use-codemirror-editor.ts

@@ -0,0 +1,70 @@
+import { useCallback, useEffect } from 'react';
+
+import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
+import { languages } from '@codemirror/language-data';
+import { EditorState, type EditorStateConfig, type Extension } from '@codemirror/state';
+import { basicSetup, useCodeMirror, type UseCodeMirror } from '@uiw/react-codemirror';
+
+import { UseCodeMirrorEditorStates } from './interfaces/react-codemirror';
+
+export type UseCodeMirrorEditor = UseCodeMirror;
+
+type UseCodeMirrorEditorUtils = {
+  initState: (config?: EditorStateConfig) => void,
+  initDoc: (doc?: string) => void,
+}
+
+export type UseCodeMirrorEditorResponse = UseCodeMirrorEditorStates & UseCodeMirrorEditorUtils;
+
+const defaultExtensions: Extension[] = [
+  markdown({ base: markdownLanguage, codeLanguages: languages }),
+];
+
+const defaultExtensionsToInit: Extension[] = [
+  ...basicSetup(),
+  ...defaultExtensions,
+];
+
+export const useCodeMirrorEditor = (props?: UseCodeMirrorEditor): UseCodeMirrorEditorResponse => {
+
+  const codemirror = useCodeMirror({
+    extensions: defaultExtensions,
+    ...props,
+  });
+
+  const { view, setContainer } = codemirror;
+
+  // implement initState method
+  const initState = useCallback((config?: EditorStateConfig): void => {
+    if (view == null) {
+      return;
+    }
+
+    const newState = EditorState.create({
+      ...config,
+      extensions: [
+        ...defaultExtensionsToInit,
+        ...(props?.extensions ?? []),
+      ],
+    });
+
+    view.setState(newState);
+  }, [props?.extensions, view]);
+
+  // implement initDoc method
+  const initDoc = useCallback((doc?: string): void => {
+    initState({ doc });
+  }, [initState]);
+
+  useEffect(() => {
+    if (props?.container != null) {
+      setContainer(props.container);
+    }
+  }, [props?.container, setContainer]);
+
+  return {
+    ...codemirror,
+    initState,
+    initDoc,
+  };
+};

+ 29 - 5
packages/editor/src/stores/codemirror-editor.ts

@@ -1,12 +1,36 @@
-import type { SWRResponse } from 'swr';
+import { useMemo } from 'react';
 
+import { type Extension } from '@codemirror/state';
+import { scrollPastEnd } from '@codemirror/view';
+import {
+  type SWRResponseWithUtils, withUtils, useSWRStatic,
+} from '@growi/core/dist/swr';
 
-import type { UseCodeMirrorEditor, UseCodeMirrorEditorStates } from '../services';
+import type { UseCodeMirrorEditor, UseCodeMirrorEditorResponse } from '../services';
 import { useCodeMirrorEditor } from '../services';
 
-import { useStaticSWR } from './use-static-swr';
+const defaultExtensionsMain: Extension[] = [
+  scrollPastEnd(),
+];
+
+type MainEditorUtils = {
+  // impl something
+};
+
+export const useCodeMirrorEditorMain = (container?: HTMLDivElement | null): SWRResponseWithUtils<MainEditorUtils, UseCodeMirrorEditorResponse> => {
+  const props = useMemo<UseCodeMirrorEditor>(() => {
+    return {
+      container,
+      autoFocus: true,
+      extensions: defaultExtensionsMain,
+    };
+  }, [container]);
 
-export const useCodeMirrorEditorMain = (props?: UseCodeMirrorEditor): SWRResponse<UseCodeMirrorEditorStates> => {
   const states = useCodeMirrorEditor(props);
-  return useStaticSWR('codeMirrorEditorMain', props != null ? states : undefined);
+
+  const swrResponse = useSWRStatic('codeMirrorEditorMain', container != null ? states : undefined);
+
+  return withUtils(swrResponse, {
+    // impl something
+  });
 };

+ 13 - 0
turbo.json

@@ -19,6 +19,11 @@
       "cache": false
     },
 
+    "@growi/editor#build": {
+      "dependsOn": ["@growi/core#build"],
+      "outputs": ["dist/**"],
+      "outputMode": "new-only"
+    },
     "@growi/pluginkit#build": {
       "dependsOn": ["@growi/core#build"],
       "outputs": ["dist/**"],
@@ -68,6 +73,11 @@
       "outputMode": "new-only"
     },
 
+    "@growi/editor#dev": {
+      "dependsOn": ["@growi/core#dev"],
+      "outputs": ["dist/**"],
+      "outputMode": "new-only"
+    },
     "@growi/pluginkit#dev": {
       "dependsOn": ["@growi/core#dev"],
       "outputs": ["dist/**"],
@@ -144,6 +154,9 @@
       "persistent": true
     },
 
+    "@growi/editor#lint": {
+      "dependsOn": ["@growi/core#dev"]
+    },
     "@growi/pluginkit#lint": {
       "dependsOn": ["@growi/core#dev"]
     },