2
0
mirror of https://github.com/tenrok/bootstrap.git synced 2026-06-11 18:02:28 +03:00

Extract Component config functionality to a separate class (#33872)

Co-authored-by: XhmikosR <xhmikosr@gmail.com>
This commit is contained in:
GeoSot
2021-12-10 18:18:18 +02:00
committed by GitHub
parent 68f226750d
commit 886b940796
18 changed files with 283 additions and 240 deletions
+18 -9
View File
@@ -6,7 +6,8 @@
*/
import EventHandler from '../dom/event-handler'
import { execute, executeAfterTransition, getElement, reflow, typeCheckConfig } from './index'
import { execute, executeAfterTransition, getElement, reflow } from './index'
import Config from './config'
/**
* Constants
@@ -37,13 +38,27 @@ const DefaultType = {
* Class definition
*/
class Backdrop {
class Backdrop extends Config {
constructor(config) {
super()
this._config = this._getConfig(config)
this._isAppended = false
this._element = null
}
// Getters
static get Default() {
return Default
}
static get DefaultType() {
return DefaultType
}
static get NAME() {
return NAME
}
// Public
show(callback) {
if (!this._config.isVisible) {
@@ -104,15 +119,9 @@ class Backdrop {
return this._element
}
_getConfig(config) {
config = {
...Default,
...(typeof config === 'object' ? config : {})
}
_configAfterMerge(config) {
// use getElement() with the default "body" to get a fresh Element on each instantiation
config.rootElement = getElement(config.rootElement)
typeCheckConfig(NAME, config, DefaultType)
return config
}
+63
View File
@@ -0,0 +1,63 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/config.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { isElement, toType } from './index'
import Manipulator from '../dom/manipulator'
/**
* Class definition
*/
class Config {
// Getters
static get Default() {
return {}
}
static get DefaultType() {
return {}
}
static get NAME() {
throw new Error('You have to implement the static method "NAME", for each component!')
}
_getConfig(config) {
config = this._mergeConfigObj(config)
config = this._configAfterMerge(config)
this._typeCheckConfig(config)
return config
}
_configAfterMerge(config) {
return config
}
_mergeConfigObj(config, element) {
return {
...this.constructor.Default,
...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),
...(typeof config === 'object' ? config : {})
}
}
_typeCheckConfig(config, configTypes = this.constructor.DefaultType) {
for (const property of Object.keys(configTypes)) {
const expectedTypes = configTypes[property]
const value = config[property]
const valueType = isElement(value) ? 'element' : toType(value)
if (!new RegExp(expectedTypes).test(valueType)) {
throw new TypeError(
`${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`
)
}
}
}
}
export default Config
+16 -11
View File
@@ -7,7 +7,7 @@
import EventHandler from '../dom/event-handler'
import SelectorEngine from '../dom/selector-engine'
import { typeCheckConfig } from './index'
import Config from './config'
/**
* Constants
@@ -37,13 +37,27 @@ const DefaultType = {
* Class definition
*/
class FocusTrap {
class FocusTrap extends Config {
constructor(config) {
super()
this._config = this._getConfig(config)
this._isActive = false
this._lastTabNavDirection = null
}
// Getters
static get Default() {
return Default
}
static get DefaultType() {
return DefaultType
}
static get NAME() {
return NAME
}
// Public
activate() {
const { trapElement, autofocus } = this._config
@@ -99,15 +113,6 @@ class FocusTrap {
this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD
}
_getConfig(config) {
config = {
...Default,
...(typeof config === 'object' ? config : {})
}
typeCheckConfig(NAME, config, DefaultType)
return config
}
}
export default FocusTrap
+1 -15
View File
@@ -123,20 +123,6 @@ const getElement = object => {
return null
}
const typeCheckConfig = (componentName, config, configTypes) => {
for (const property of Object.keys(configTypes)) {
const expectedTypes = configTypes[property]
const value = config[property]
const valueType = value && isElement(value) ? 'element' : toType(value)
if (!new RegExp(expectedTypes).test(valueType)) {
throw new TypeError(
`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`
)
}
}
}
const isVisible = element => {
if (!isElement(element) || element.getClientRects().length === 0) {
return false
@@ -327,5 +313,5 @@ export {
onDOMContentLoaded,
reflow,
triggerTransitionEnd,
typeCheckConfig
toType
}
+17 -11
View File
@@ -5,8 +5,9 @@
* --------------------------------------------------------------------------
*/
import Config from './config'
import EventHandler from '../dom/event-handler'
import { execute, typeCheckConfig } from './index'
import { execute } from './index'
/**
* Constants
@@ -40,8 +41,9 @@ const DefaultType = {
* Class definition
*/
class Swipe {
class Swipe extends Config {
constructor(element, config) {
super()
this._element = element
if (!element || !Swipe.isSupported()) {
@@ -54,6 +56,19 @@ class Swipe {
this._initEvents()
}
// Getters
static get Default() {
return Default
}
static get DefaultType() {
return DefaultType
}
static get NAME() {
return NAME
}
// Public
dispose() {
EventHandler.off(this._element, EVENT_KEY)
@@ -118,15 +133,6 @@ class Swipe {
}
}
_getConfig(config) {
config = {
...Default,
...(typeof config === 'object' ? config : {})
}
typeCheckConfig(NAME, config, DefaultType)
return config
}
_eventIsPointerPenTouch(event) {
return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)
}
+15 -16
View File
@@ -6,8 +6,9 @@
*/
import { DefaultAllowlist, sanitizeHtml } from './sanitizer'
import { getElement, isElement, typeCheckConfig } from '../util/index'
import { getElement, isElement } from '../util/index'
import SelectorEngine from '../dom/selector-engine'
import Config from './config'
/**
* Constants
@@ -44,20 +45,25 @@ const DefaultContentType = {
* Class definition
*/
class TemplateFactory {
class TemplateFactory extends Config {
constructor(config) {
super()
this._config = this._getConfig(config)
}
// Getters
static get NAME() {
return NAME
}
static get Default() {
return Default
}
static get DefaultType() {
return DefaultType
}
static get NAME() {
return NAME
}
// Public
getContent() {
return Object.values(this._config.content)
@@ -94,21 +100,14 @@ class TemplateFactory {
}
// Private
_getConfig(config) {
config = {
...Default,
...(typeof config === 'object' ? config : {})
}
typeCheckConfig(NAME, config, DefaultType)
_typeCheckConfig(config) {
super._typeCheckConfig(config)
this._checkContent(config.content)
return config
}
_checkContent(arg) {
for (const [selector, content] of Object.entries(arg)) {
typeCheckConfig(NAME, { selector, entry: content }, DefaultContentType)
super._typeCheckConfig({ selector, entry: content }, DefaultContentType)
}
}