diff --git a/extensions/statistics/js/src/admin/components/StatisticsWidgetDateSelectionModal.tsx b/extensions/statistics/js/src/admin/components/StatisticsWidgetDateSelectionModal.tsx
index da4deaa900..db82d7da7c 100644
--- a/extensions/statistics/js/src/admin/components/StatisticsWidgetDateSelectionModal.tsx
+++ b/extensions/statistics/js/src/admin/components/StatisticsWidgetDateSelectionModal.tsx
@@ -1,6 +1,6 @@
import app from 'flarum/admin/app';
import ItemList from 'flarum/common/utils/ItemList';
-import generateElementId from 'flarum/admin/utils/generateElementId';
+import generateElementId from 'flarum/common/utils/generateElementId';
import FormModal, { IFormModalAttrs } from 'flarum/common/components/FormModal';
import Mithril from 'mithril';
diff --git a/extensions/tags/js/src/admin/addTagSelectionSettingComponent.tsx b/extensions/tags/js/src/admin/addTagSelectionSettingComponent.tsx
index b710140cfa..a507cdd1d8 100644
--- a/extensions/tags/js/src/admin/addTagSelectionSettingComponent.tsx
+++ b/extensions/tags/js/src/admin/addTagSelectionSettingComponent.tsx
@@ -1,11 +1,12 @@
import { extend } from 'flarum/common/extend';
-import AdminPage from 'flarum/admin/components/AdminPage';
import SelectTagsSettingComponent from './components/SelectTagsSettingComponent';
+import FormGroup from 'flarum/common/components/FormGroup';
+import type { IFormGroupAttrs } from 'flarum/common/components/FormGroup';
export default function () {
- extend(AdminPage.prototype, 'customSettingComponents', function (items) {
- items.add('flarum-tags.select-tags', (attrs) => {
- return ;
+ extend(FormGroup.prototype, 'customFieldComponents', function (items) {
+ items.add('flarum-tags.select-tags', (attrs: IFormGroupAttrs) => {
+ return ;
});
});
}
diff --git a/framework/core/js/src/admin/admin.ts b/framework/core/js/src/admin/admin.ts
index 954b284432..df3052cdcb 100644
--- a/framework/core/js/src/admin/admin.ts
+++ b/framework/core/js/src/admin/admin.ts
@@ -4,7 +4,6 @@ import './utils/saveSettings';
import './utils/ExtensionData';
import './utils/isExtensionEnabled';
import './utils/getCategorizedExtensions';
-import './utils/generateElementId';
import './components/SettingDropdown';
import './components/EditCustomFooterModal';
@@ -22,7 +21,6 @@ import './components/ExtensionLinkButton';
import './components/PermissionGrid';
import './components/ExtensionPermissionGrid';
import './components/MailPage';
-import './components/UploadImageButton';
import './components/LoadingModal';
import './components/DashboardPage';
import './components/BasicsPage';
diff --git a/framework/core/js/src/admin/components/AdminPage.tsx b/framework/core/js/src/admin/components/AdminPage.tsx
index 5c0368414b..dcac3ed034 100644
--- a/framework/core/js/src/admin/components/AdminPage.tsx
+++ b/framework/core/js/src/admin/components/AdminPage.tsx
@@ -3,17 +3,11 @@ import type Mithril from 'mithril';
import app from '../app';
import Page, { IPageAttrs } from '../../common/components/Page';
import Button from '../../common/components/Button';
-import Switch from '../../common/components/Switch';
-import Select from '../../common/components/Select';
import classList from '../../common/utils/classList';
import Stream from '../../common/utils/Stream';
import saveSettings from '../utils/saveSettings';
import AdminHeader from './AdminHeader';
-import generateElementId from '../utils/generateElementId';
-import ColorPreviewInput from '../../common/components/ColorPreviewInput';
-import ItemList from '../../common/utils/ItemList';
-import type { IUploadImageButtonAttrs } from './UploadImageButton';
-import UploadImageButton from './UploadImageButton';
+import FormGroup, { FieldComponentOptions } from '../../common/components/FormGroup';
import extractText from '../../common/utils/extractText';
export interface AdminHeaderOptions {
@@ -28,115 +22,9 @@ export interface AdminHeaderOptions {
className: string;
}
-/**
- * A type that matches any valid value for the `type` attribute on an HTML `` element.
- *
- * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-type
- *
- * Note: this will be exported from a different location in the future.
- *
- * @see https://github.com/flarum/core/issues/3039
- */
-export type HTMLInputTypes =
- | 'button'
- | 'checkbox'
- | 'color'
- | 'date'
- | 'datetime-local'
- | 'email'
- | 'file'
- | 'hidden'
- | 'image'
- | 'month'
- | 'number'
- | 'password'
- | 'radio'
- | 'range'
- | 'reset'
- | 'search'
- | 'submit'
- | 'tel'
- | 'text'
- | 'time'
- | 'url'
- | 'week';
-
-export interface CommonSettingsItemOptions extends Mithril.Attributes {
+export type SettingsComponentOptions = FieldComponentOptions & {
setting: string;
- label?: Mithril.Children;
- help?: Mithril.Children;
- className?: string;
-}
-
-/**
- * Valid options for the setting component builder to generate an HTML input element.
- */
-export interface HTMLInputSettingsComponentOptions extends CommonSettingsItemOptions {
- /**
- * Any valid HTML input `type` value.
- */
- type: HTMLInputTypes;
-}
-
-const BooleanSettingTypes = ['bool', 'checkbox', 'switch', 'boolean'] as const;
-const SelectSettingTypes = ['select', 'dropdown', 'selectdropdown'] as const;
-const TextareaSettingTypes = ['textarea'] as const;
-const ColorPreviewSettingType = 'color-preview' as const;
-const ImageUploadSettingType = 'image-upload' as const;
-
-/**
- * Valid options for the setting component builder to generate a Switch.
- */
-export interface SwitchSettingComponentOptions extends CommonSettingsItemOptions {
- type: typeof BooleanSettingTypes[number];
-}
-
-/**
- * Valid options for the setting component builder to generate a Select dropdown.
- */
-export interface SelectSettingComponentOptions extends CommonSettingsItemOptions {
- type: typeof SelectSettingTypes[number];
- /**
- * Map of values to their labels
- */
- options: { [value: string]: Mithril.Children };
- default: string;
-}
-
-/**
- * Valid options for the setting component builder to generate a Textarea.
- */
-export interface TextareaSettingComponentOptions extends CommonSettingsItemOptions {
- type: typeof TextareaSettingTypes[number];
-}
-
-/**
- * Valid options for the setting component builder to generate a ColorPreviewInput.
- */
-export interface ColorPreviewSettingComponentOptions extends CommonSettingsItemOptions {
- type: typeof ColorPreviewSettingType;
-}
-
-export interface ImageUploadSettingComponentOptions extends CommonSettingsItemOptions, IUploadImageButtonAttrs {
- type: typeof ImageUploadSettingType;
-}
-
-export interface CustomSettingComponentOptions extends CommonSettingsItemOptions {
- type: string;
- [key: string]: unknown;
-}
-
-/**
- * All valid options for the setting component builder.
- */
-export type SettingsComponentOptions =
- | HTMLInputSettingsComponentOptions
- | SwitchSettingComponentOptions
- | SelectSettingComponentOptions
- | TextareaSettingComponentOptions
- | ColorPreviewSettingComponentOptions
- | ImageUploadSettingComponentOptions
- | CustomSettingComponentOptions;
+};
/**
* Valid attrs that can be returned by the `headerInfo` function
@@ -206,41 +94,6 @@ export default abstract class AdminPage {
- * return (
- *
- *
- * {attrs.help &&
{attrs.help}
}
- *
- * My setting component!
- *
- * );
- * })
- * })
- * ```
- */
- customSettingComponents(): ItemList<(attributes: CommonSettingsItemOptions) => Mithril.Children> {
- const items = new ItemList<(attributes: CommonSettingsItemOptions) => Mithril.Children>();
-
- return items;
- }
-
/**
* `buildSettingComponent` takes a settings object and turns it into a component.
* Depending on the type of input, you can set the type to 'bool', 'select', or
@@ -284,77 +137,9 @@ export default abstract class AdminPage
-
- {label}
-
- {help ?
+ );
+ }
+
+ /**
+ * A list of extension-defined custom setting components to be available.
+ *
+ * The ItemList key represents the value for the `type` attribute.
+ * All attributes passed are provided as arguments to the function added to the ItemList.
+ *
+ * ItemList priority has no effect here.
+ *
+ * @example
+ * ```tsx
+ * extend(AdminPage.prototype, 'customFieldComponents', function (items) {
+ * // You can access the AdminPage instance with `this` to access its `settings` property.
+ *
+ * // Prefixing the key with your extension ID is recommended to avoid collisions.
+ * items.add('my-ext.setting-component', (attrs) => {
+ * return (
+ *
+ *
+ * {attrs.help &&
{attrs.help}
}
+ *
+ * My setting component!
+ *
+ * );
+ * })
+ * })
+ * ```
+ */
+ customFieldComponents(): ItemList<(attributes: CustomAttrs) => Mithril.Children> {
+ const items = new ItemList<(attributes: CustomAttrs) => Mithril.Children>();
+
+ return items;
+ }
+}
diff --git a/framework/core/js/src/admin/components/UploadImageButton.tsx b/framework/core/js/src/common/components/UploadImageButton.tsx
similarity index 100%
rename from framework/core/js/src/admin/components/UploadImageButton.tsx
rename to framework/core/js/src/common/components/UploadImageButton.tsx
diff --git a/framework/core/js/src/admin/utils/generateElementId.ts b/framework/core/js/src/common/utils/generateElementId.ts
similarity index 100%
rename from framework/core/js/src/admin/utils/generateElementId.ts
rename to framework/core/js/src/common/utils/generateElementId.ts