@ui5/webcomponents-base
Advanced tools
Comparing version 0.10.1 to 0.11.0
@@ -75,3 +75,3 @@ module.exports = { | ||
"no-sequences": 2, | ||
"no-unused-expressions": 1, | ||
"no-unused-expressions": [1, { allowShortCircuit: true }], | ||
"no-void": 2, | ||
@@ -78,0 +78,0 @@ "no-warning-comments": 0, |
@@ -6,2 +6,24 @@ # Change Log | ||
# [0.11.0](https://github.com/SAP/ui5-webcomponents/compare/v0.10.1...v0.11.0) (2019-05-22) | ||
### Bug Fixes | ||
* broken child property observation ([#423](https://github.com/SAP/ui5-webcomponents/issues/423)) ([b3e3b3f](https://github.com/SAP/ui5-webcomponents/commit/b3e3b3f)) | ||
* prevent dual event dispatching in no conflict mode ([#363](https://github.com/SAP/ui5-webcomponents/issues/363)) ([4cbe3de](https://github.com/SAP/ui5-webcomponents/commit/4cbe3de)) | ||
### Code Refactoring | ||
* make custom CSS theme independent ([#386](https://github.com/SAP/ui5-webcomponents/issues/386)) ([d6b4ab5](https://github.com/SAP/ui5-webcomponents/commit/d6b4ab5)) | ||
### BREAKING CHANGES | ||
* the signature of the addCustomCSS method exported by "@ui5/webcomponents-base/Theming.js" is changed from addCustomCSS(tag, theme, css) to addCustomCSS(tag, css) | ||
## [0.10.1](https://github.com/SAP/ui5-webcomponents/compare/v0.10.0...v0.10.1) (2019-04-24) | ||
@@ -8,0 +30,0 @@ |
{ | ||
"name": "@ui5/webcomponents-base", | ||
"version": "0.10.1", | ||
"version": "0.11.0", | ||
"description": "UI5 Web Components: webcomponents.base", | ||
@@ -23,3 +23,3 @@ "author": "SAP SE (https://www.sap.com)", | ||
"dependencies": { | ||
"@ui5/webcomponents-core": "0.10.1", | ||
"@ui5/webcomponents-core": "0.11.0", | ||
"lit-html": "^1.0.0", | ||
@@ -26,0 +26,0 @@ "regenerator-runtime": "0.12.1", |
213
src/CLDR.js
@@ -1,164 +0,12 @@ | ||
/* eslint-disable camelcase */ | ||
import ar from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/ar.json"; | ||
import ar_EG from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/ar_EG.json"; | ||
import ar_SA from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/ar_SA.json"; | ||
import bg from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/bg.json"; | ||
import ca from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/ca.json"; | ||
import cs from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/cs.json"; | ||
import da from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/da.json"; | ||
import de from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/de.json"; | ||
import de_AT from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/de_AT.json"; | ||
import de_CH from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/de_CH.json"; | ||
import el from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/el.json"; | ||
import el_CY from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/el_CY.json"; | ||
import en from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/en.json"; | ||
import en_AU from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/en_AU.json"; | ||
import en_GB from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/en_GB.json"; | ||
import en_HK from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/en_HK.json"; | ||
import en_IE from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/en_IE.json"; | ||
import en_IN from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/en_IN.json"; | ||
import en_NZ from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/en_NZ.json"; | ||
import en_PG from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/en_PG.json"; | ||
import en_SG from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/en_SG.json"; | ||
import en_ZA from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/en_ZA.json"; | ||
import es from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/es.json"; | ||
import es_AR from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/es_AR.json"; | ||
import es_BO from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/es_BO.json"; | ||
import es_CL from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/es_CL.json"; | ||
import es_CO from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/es_CO.json"; | ||
import es_MX from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/es_MX.json"; | ||
import es_PE from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/es_PE.json"; | ||
import es_UY from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/es_UY.json"; | ||
import es_VE from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/es_VE.json"; | ||
import et from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/et.json"; | ||
import fa from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/fa.json"; | ||
import fi from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/fi.json"; | ||
import fr from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/fr.json"; | ||
import fr_BE from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/fr_BE.json"; | ||
import fr_CA from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/fr_CA.json"; | ||
import fr_CH from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/fr_CH.json"; | ||
import fr_LU from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/fr_LU.json"; | ||
import he from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/he.json"; | ||
import hi from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/hi.json"; | ||
import hr from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/hr.json"; | ||
import hu from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/hu.json"; | ||
import id from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/id.json"; | ||
import it from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/it.json"; | ||
import it_CH from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/it_CH.json"; | ||
import ja from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/ja.json"; | ||
import kk from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/kk.json"; | ||
import ko from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/ko.json"; | ||
import lt from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/lt.json"; | ||
import lv from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/lv.json"; | ||
import ms from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/ms.json"; | ||
import nb from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/nb.json"; | ||
import nl from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/nl.json"; | ||
import nl_BE from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/nl_BE.json"; | ||
import pl from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/pl.json"; | ||
import pt from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/pt.json"; | ||
import pt_PT from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/pt_PT.json"; | ||
import ro from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/ro.json"; | ||
import ru from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/ru.json"; | ||
import ru_UA from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/ru_UA.json"; | ||
import sk from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/sk.json"; | ||
import sl from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/sl.json"; | ||
import sr from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/sr.json"; | ||
import sv from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/sv.json"; | ||
import th from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/th.json"; | ||
import tr from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/tr.json"; | ||
import uk from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/uk.json"; | ||
import vi from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/vi.json"; | ||
import zh_CN from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/zh_CN.json"; | ||
import zh_HK from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/zh_HK.json"; | ||
import zh_SG from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/zh_SG.json"; | ||
import zh_TW from "@ui5/webcomponents-core/dist/sap/ui/core/cldr/zh_TW.json"; | ||
import { registerModuleContent } from "./ResourceLoaderOverrides.js"; | ||
import { fetchTextOnce } from "./util/FetchHelper.js"; | ||
const cldrData = { | ||
ar, | ||
ar_EG, | ||
ar_SA, | ||
bg, | ||
ca, | ||
cs, | ||
da, | ||
de, | ||
de_AT, | ||
de_CH, | ||
el, | ||
el_CY, | ||
en, | ||
en_AU, | ||
en_GB, | ||
en_HK, | ||
en_IE, | ||
en_IN, | ||
en_NZ, | ||
en_PG, | ||
en_SG, | ||
en_ZA, | ||
es, | ||
es_AR, | ||
es_BO, | ||
es_CL, | ||
es_CO, | ||
es_MX, | ||
es_PE, | ||
es_UY, | ||
es_VE, | ||
et, | ||
fa, | ||
fi, | ||
fr, | ||
fr_BE, | ||
fr_CA, | ||
fr_CH, | ||
fr_LU, | ||
he, | ||
hi, | ||
hr, | ||
hu, | ||
id, | ||
it, | ||
it_CH, | ||
ja, | ||
kk, | ||
ko, | ||
lt, | ||
lv, | ||
ms, | ||
nb, | ||
nl, | ||
nl_BE, | ||
pl, | ||
pt, | ||
pt_PT, | ||
ro, | ||
ru, | ||
ru_UA, | ||
sk, | ||
sl, | ||
sr, | ||
sv, | ||
th, | ||
tr, | ||
uk, | ||
vi, | ||
zh_CN, | ||
zh_HK, | ||
zh_SG, | ||
zh_TW, | ||
}; | ||
const supportedLocales = ["ar", "ar_EG", "ar_SA", "bg", "ca", "cs", "da", "de", "de_AT", "de_CH", "el", "el_CY", "en", "en_AU", "en_GB", "en_HK", "en_IE", "en_IN", "en_NZ", "en_PG", "en_SG", "en_ZA", "es", "es_AR", "es_BO", "es_CL", "es_CO", "es_MX", "es_PE", "es_UY", "es_VE", "et", "fa", "fi", "fr", "fr_BE", "fr_CA", "fr_CH", "fr_LU", "he", "hi", "hr", "hu", "id", "it", "it_CH", "ja", "kk", "ko", "lt", "lv", "ms", "nb", "nl", "nl_BE", "pl", "pt", "pt_PT", "ro", "ru", "ru_UA", "sk", "sl", "sr", "sv", "th", "tr", "uk", "vi", "zh_CN", "zh_HK", "zh_SG", "zh_TW"]; | ||
const allEntriesInlined = Object.entries(cldrData).every(([_key, value]) => typeof (value) === "object"); | ||
/* eslint-disable */ | ||
if (allEntriesInlined) { | ||
console.warn(`Inefficient bundling detected: consider bundling CLDR imports as URLs instead of inlining them. | ||
See rollup-plugin-url or webpack file-loader for more information. | ||
Suggested pattern: "cldr\\\/.*\\\.json"`); | ||
} | ||
/* eslint-enable */ | ||
const cldrData = {}; | ||
const cldrUrls = {}; | ||
// externally configurable mapping function for resolving (localeId -> URL) | ||
// default implementation - ui5 CDN | ||
let cldrMappingFn = locale => `https://ui5.sap.com/1.60.2/resources/sap/ui/core/cldr/${locale}.json`; | ||
@@ -190,7 +38,7 @@ const M_ISO639_OLD_TO_NEW = { | ||
let localeId = `${language}_${region}`; | ||
if (!cldrData[localeId]) { | ||
if (!supportedLocales.includes(localeId)) { | ||
// fallback to language only | ||
localeId = language; | ||
} | ||
if (!cldrData[localeId]) { | ||
if (!supportedLocales.includes(localeId)) { | ||
// fallback to english | ||
@@ -203,22 +51,45 @@ localeId = "en"; | ||
const resolveMissingMappings = () => { | ||
if (!cldrMappingFn) { | ||
return; | ||
} | ||
const missingLocales = supportedLocales.filter(locale => !cldrData[locale] && !cldrUrls[locale]); | ||
missingLocales.forEach(locale => { | ||
cldrUrls[locale] = cldrMappingFn(locale); | ||
}); | ||
}; | ||
const fetchCldrData = async (language, region, script) => { | ||
resolveMissingMappings(); | ||
const localeId = calcLocale(language, region, script); | ||
if (typeof (cldrData[localeId]) === "object") { | ||
// inlined from build | ||
registerModuleContent(`sap/ui/core/cldr/${localeId}.json`, JSON.stringify(cldrData[localeId])); | ||
return cldrData[localeId]; | ||
const cldrObj = cldrData[localeId]; | ||
const url = cldrUrls[localeId]; | ||
if (cldrObj) { | ||
// inlined from build or fetched independently | ||
registerModuleContent(`sap/ui/core/cldr/${localeId}.json`, JSON.stringify(cldrObj)); | ||
} else if (url) { | ||
// fetch it | ||
const cldrText = await fetchTextOnce(url); | ||
registerModuleContent(`sap/ui/core/cldr/${localeId}.json`, cldrText); | ||
} | ||
}; | ||
const localeUrl = cldrData[localeId]; | ||
const registerCldrUrl = (locale, url) => { | ||
cldrUrls[locale] = url; | ||
}; | ||
const cldrContent = await fetchTextOnce(localeUrl); | ||
registerModuleContent(`sap/ui/core/cldr/${localeId}.json`, cldrContent); | ||
const registerCldrData = (locale, data) => { | ||
cldrData[locale] = data; | ||
}; | ||
const registerCldrUrl = (locale, url) => { | ||
cldrData[locale] = url; | ||
const _registerMappingFunction = mappingFn => { | ||
cldrMappingFn = mappingFn; | ||
}; | ||
export { fetchCldrData, registerCldrUrl }; | ||
/* eslint-enable camelcase */ | ||
export { | ||
fetchCldrData, registerCldrUrl, registerCldrData, _registerMappingFunction, | ||
}; |
@@ -40,2 +40,6 @@ import CalendarType from "@ui5/webcomponents-core/dist/sap/ui/core/CalendarType.js"; | ||
const _setWCNoConflict = value => { | ||
CONFIGURATION["xx-wc-no-conflict"] = value; | ||
}; | ||
/* Calendar stuff */ | ||
@@ -129,4 +133,5 @@ const getCalendarType = () => { | ||
_setTheme, | ||
_setWCNoConflict, | ||
getSupportedLanguages, | ||
getOriginInfo, | ||
}; |
@@ -172,2 +172,6 @@ import { | ||
if (!items.length) { | ||
return null; | ||
} | ||
// normalize the index | ||
@@ -174,0 +178,0 @@ while (this.currentIndex >= items.length) { |
@@ -25,2 +25,14 @@ import KeyCodes from "@ui5/webcomponents-core/dist/sap/ui/events/KeyCodes.js"; | ||
const isBackSpace = event => (event.key ? (event.key === "Backspace" || event.key === "Backspace") : event.keyCode === KeyCodes.BACKSPACE) && !hasModifierKeys(event); | ||
const isDelete = event => (event.key ? (event.key === "Delete" || event.key === "Delete") : event.keyCode === KeyCodes.DELETE) && !hasModifierKeys(event); | ||
const isShow = event => { | ||
if (event.key) { | ||
return (event.key === "F4" && !hasModifierKeys(event)) || ((event.key === "ArrowDown" || event.key === "Down") && checkModifierKeys(event, /* Ctrl */ false, /* Alt */ true, /* Shift */ false)); | ||
} | ||
return (event.keyCode === KeyCodes.F4 && !hasModifierKeys(event)) || (event.keyCode === KeyCodes.ARROW_DOWN && checkModifierKeys(event, /* Ctrl */ false, /* Alt */ true, /* Shift */ false)); | ||
}; | ||
const hasModifierKeys = event => event.shiftKey || event.altKey || getCtrlKey(event); | ||
@@ -44,2 +56,5 @@ | ||
isTabPrevious, | ||
isBackSpace, | ||
isDelete, | ||
isShow, | ||
}; |
@@ -116,6 +116,24 @@ import RenderQueue from "./RenderQueue.js"; | ||
static getNotDefinedComponents() { | ||
return Array.from(document.querySelectorAll(":not(:defined)")).filter(el => el.localName.startsWith("ui5-")); | ||
} | ||
/** | ||
* return a promise that will be resolved once all ui5 webcomponents on the page have their shadow root ready | ||
*/ | ||
static whenShadowDOMReady() { | ||
static async whenShadowDOMReady() { | ||
const undefinedElements = this.getNotDefinedComponents(); | ||
const definedPromises = undefinedElements.map( | ||
el => customElements.whenDefined(el.localName) | ||
); | ||
const timeoutPromise = new Promise(resolve => setTimeout(resolve, 5000)); | ||
await Promise.race([Promise.all(definedPromises), timeoutPromise]); | ||
const stillUndefined = this.getNotDefinedComponents(); | ||
if (stillUndefined.length) { | ||
// eslint-disable-next-line | ||
console.warn("undefined elements after 5 seconds: ", [...stillUndefined].map(el => el.localName)); | ||
} | ||
// TODO: track promises internally, the dom traversal is a POC only | ||
@@ -122,0 +140,0 @@ const ui5Components = Array.from(document.querySelectorAll("*")).filter(_ => _._shadowRootReadyPromise); |
@@ -25,2 +25,8 @@ /* global sap */ | ||
const missingModule = moduleName.match(/sap\/ui\/core\/cldr\/(\w+)\.json/); | ||
if (missingModule) { | ||
throw new Error(`CLDR data for locale ${missingModule[1]} is not loaded!`); | ||
} | ||
return ""; | ||
@@ -27,0 +33,0 @@ }; |
@@ -33,8 +33,13 @@ import Function from "./types/Function.js"; | ||
} | ||
if (propData.type === "boolean") { | ||
const propDefaultValue = propData.defaultValue; | ||
if (propData.type === Boolean) { | ||
return false; | ||
} else if (propData.type === String) { // eslint-disable-line | ||
return propDefaultValue || ""; | ||
} else if (propData.multiple) { // eslint-disable-line | ||
return []; | ||
} else { | ||
return propData.defaultValue; | ||
return propDefaultValue; | ||
} | ||
@@ -120,12 +125,2 @@ }, | ||
} | ||
Object.defineProperty(proto, "_nodeText", { | ||
get() { | ||
return this._data._nodeText; | ||
}, | ||
set(value) { | ||
this._data._nodeText = value; | ||
this._control._invalidate("_nodeText", value); | ||
}, | ||
}); | ||
} | ||
@@ -139,10 +134,19 @@ | ||
for (const propName in props) { // eslint-disable-line | ||
if (props[propName].type === "boolean") { | ||
const propType = props[propName].type; | ||
const propDefaultValue = props[propName].defaultValue; | ||
if (propType === Boolean) { | ||
defaultState[propName] = false; | ||
if (propDefaultValue !== undefined) { | ||
console.warn("The 'defaultValue' metadata key is ignored for all booleans properties, they would be initialized with 'false' by default"); // eslint-disable-line | ||
} | ||
} else if (props[propName].multiple) { | ||
defaultState[propName] = []; | ||
} else if (props[propName].type === Object) { | ||
} else if (propType === Object) { | ||
defaultState[propName] = "defaultValue" in props[propName] ? props[propName].defaultValue : {}; | ||
} else if (propType === String) { | ||
defaultState[propName] = propDefaultValue || ""; | ||
} else { | ||
defaultState[propName] = props[propName].defaultValue; | ||
defaultState[propName] = propDefaultValue; | ||
} | ||
@@ -149,0 +153,0 @@ } |
@@ -25,3 +25,3 @@ const _convertClasses = (classes, customStyleClasses) => { | ||
if (!styles) { | ||
return; | ||
return ""; | ||
} | ||
@@ -38,6 +38,6 @@ | ||
}); | ||
styles[i] = result.length ? result.join("; ") : undefined; | ||
styles[i] = result.length ? result.join("; ") : ""; | ||
} | ||
return styles; | ||
return styles || ""; | ||
}; | ||
@@ -44,0 +44,0 @@ |
@@ -44,5 +44,4 @@ import { getTheme, _setTheme } from "./Configuration.js"; | ||
const getEffectiveStyle = ElementClass => { | ||
const theme = getTheme(); | ||
const tag = ElementClass.getMetadata().getTag(); | ||
const customStyle = getCustomCSS(theme, tag) || ""; | ||
const customStyle = getCustomCSS(tag) || ""; | ||
let componentStyles = ElementClass.styles; | ||
@@ -49,0 +48,0 @@ |
@@ -1,23 +0,20 @@ | ||
const customCSSMap = new Map(); | ||
const customCSSFor = {}; | ||
const addCustomCSS = (tag, theme, css) => { | ||
let themeCustomCSS = customCSSMap.get(theme); | ||
if (!themeCustomCSS) { | ||
customCSSMap.set(theme, {}); | ||
themeCustomCSS = customCSSMap.get(theme); | ||
const addCustomCSS = (tag, css, ...rest) => { | ||
// TODO remove deprecation error after 1 release | ||
if (rest.length) { | ||
throw new Error("addCustomCSS no longer accepts theme specific CSS. new signature is `addCustomCSS(tag, css)`"); | ||
} | ||
if (!themeCustomCSS[tag]) { | ||
themeCustomCSS[tag] = []; | ||
if (!customCSSFor[tag]) { | ||
customCSSFor[tag] = []; | ||
} | ||
themeCustomCSS[tag].push(css); | ||
customCSSFor[tag].push(css); | ||
}; | ||
const getCustomCSS = (theme, tag) => { | ||
const themeCustomCSS = customCSSMap.get(theme); | ||
return themeCustomCSS && themeCustomCSS[tag] ? themeCustomCSS[tag].join("") : ""; | ||
const getCustomCSS = tag => { | ||
return customCSSFor[tag] ? customCSSFor[tag].join("") : ""; | ||
}; | ||
export { addCustomCSS, getCustomCSS }; |
@@ -1,2 +0,2 @@ | ||
import { getWCNoConflict } from "./Configuration.js"; | ||
import { getWCNoConflict, getCompactSize } from "./Configuration.js"; | ||
import DOMObserver from "./compatibility/DOMObserver.js"; | ||
@@ -81,2 +81,8 @@ import ShadowDOM from "./compatibility/ShadowDOM.js"; | ||
async _initializeShadowRoot() { | ||
const isCompact = getCompactSize(); | ||
if (isCompact) { | ||
this.setAttribute("data-ui5-compact-size", ""); | ||
} | ||
if (this.constructor.getMetadata().getNoShadowDOM()) { | ||
@@ -124,4 +130,3 @@ return Promise.resolve(); | ||
const shouldObserveChildren = this.constructor.getMetadata().hasSlots(); | ||
const shouldObserveText = this.constructor.getMetadata().usesNodeText(); | ||
if (!shouldObserveChildren && !shouldObserveText) { | ||
if (!shouldObserveChildren) { | ||
return; | ||
@@ -131,4 +136,4 @@ } | ||
childList: true, | ||
subtree: shouldObserveText, | ||
characterData: shouldObserveText, | ||
subtree: true, | ||
characterData: true, | ||
}; | ||
@@ -146,7 +151,4 @@ DOMObserver.observeDOMNode(this, this._processChildren.bind(this), mutationObserverOptions); | ||
_processChildren(mutations) { | ||
const usesNodeText = this.constructor.getMetadata().usesNodeText(); | ||
const hasChildren = this.constructor.getMetadata().hasSlots(); | ||
if (usesNodeText) { | ||
this._updateNodeText(); | ||
} else if (hasChildren) { | ||
const hasSlots = this.constructor.getMetadata().hasSlots(); | ||
if (hasSlots) { | ||
this._updateSlots(); | ||
@@ -157,10 +159,15 @@ } | ||
_updateNodeText() { | ||
this._state._nodeText = this.textContent; | ||
} | ||
_updateSlots() { | ||
const domChildren = Array.from(this.children); | ||
const slotsMap = this.constructor.getMetadata().getSlots(); | ||
const defaultSlot = this.constructor.getMetadata().getDefaultSlot(); | ||
const canSlotText = slotsMap[defaultSlot] !== undefined && slotsMap[defaultSlot].type === Node; | ||
const slotsMap = this.constructor.getMetadata().getSlots(); | ||
let domChildren; | ||
if (canSlotText) { | ||
domChildren = Array.from(this.childNodes); | ||
} else { | ||
domChildren = Array.from(this.children); | ||
} | ||
// Init the _state object based on the supported slots | ||
for (const [prop, propData] of Object.entries(slotsMap)) { // eslint-disable-line | ||
@@ -173,23 +180,27 @@ if (propData.multiple) { | ||
} | ||
const autoIncrementMap = new Map(); | ||
domChildren.forEach(child => { | ||
const slot = child.getAttribute("data-ui5-slot") || this.constructor.getMetadata().getDefaultSlot(); | ||
if (slotsMap[slot] === undefined) { | ||
// Determine the type of the child (mainly by the slot attribute) | ||
const slotName = this.constructor._getSlotName(child); | ||
// Check if the slotName is supported | ||
if (slotsMap[slotName] === undefined) { | ||
const validValues = Object.keys(slotsMap).join(", "); | ||
console.warn(`Unknown data-ui5-slot value: ${slot}, ignoring`, child, `Valid data-ui5-slot values are: ${validValues}`); // eslint-disable-line | ||
console.warn(`Unknown slotName: ${slotName}, ignoring`, child, `Valid values are: ${validValues}`); // eslint-disable-line | ||
return; | ||
} | ||
let slotName; | ||
if (slotsMap[slot].multiple) { | ||
const nextId = (autoIncrementMap.get(slot) || 0) + 1; | ||
slotName = `${slot}-${nextId}`; | ||
autoIncrementMap.set(slot, nextId); | ||
} else { | ||
slotName = slot; | ||
// For children that need individual slots, calculate them | ||
if (slotsMap[slotName].individualSlots) { | ||
const nextId = (autoIncrementMap.get(slotName) || 0) + 1; | ||
autoIncrementMap.set(slotName, nextId); | ||
child._individualSlot = `${slotName}-${nextId}`; | ||
} | ||
child._slot = slotName; | ||
if (slotsMap[slot].multiple) { | ||
this._state[slot] = [...this._state[slot], child]; | ||
// Distribute the child in the _state object | ||
if (slotsMap[slotName].multiple) { | ||
this._state[slotName] = [...this._state[slotName], child]; | ||
} else { | ||
this._state[slot] = child; | ||
this._state[slotName] = child; | ||
} | ||
@@ -336,3 +347,3 @@ }); | ||
childMetadata = child.constructor.getMetadata(), | ||
childType = child.getAttribute("data-ui5-slot"), // all slotted children have the same configuration | ||
slotName = this.constructor._getSlotName(child), // all slotted children have the same configuration | ||
childProperties = childMetadata.getProperties(); | ||
@@ -354,19 +365,22 @@ | ||
if (!this._monitoredChildProps.has(childType)) { | ||
this._monitoredChildProps.set(childType, { observedProps, notObservedProps }); | ||
if (!this._monitoredChildProps.has(slotName)) { | ||
this._monitoredChildProps.set(slotName, { observedProps, notObservedProps }); | ||
} | ||
child.addEventListener("_propertyChange", this._onChildPropertyUpdated); | ||
child.addEventListener("_propertyChange", this._invalidateParentOfPropertyUpdate); | ||
} | ||
_detachChildPropertyUpdated(child) { | ||
child.removeEventListener("_propertyChange", this._onChildPropertyUpdated); | ||
child.removeEventListener("_propertyChange", this._invalidateParentOfPropertyUpdate); | ||
} | ||
_onChildPropertyUpdated(prop) { | ||
if (!this.parentNode) { | ||
_invalidateParentOfPropertyUpdate(prop) { | ||
// The web component to be invalidated | ||
const parentNode = this.parentNode; | ||
if (!parentNode) { | ||
return; | ||
} | ||
const propsMetadata = this.parentNode._monitoredChildProps.get(this.getAttribute("data-ui5-slot")); | ||
const slotName = parentNode.constructor._getSlotName(this); | ||
const propsMetadata = parentNode._monitoredChildProps.get(slotName); | ||
@@ -379,3 +393,3 @@ if (!propsMetadata) { | ||
if (observedProps.includes(prop.detail.name) && !notObservedProps.includes(prop.detail.name)) { | ||
this.parentNode._invalidate("_parent_", this); | ||
parentNode._invalidate("_parent_", this); | ||
} | ||
@@ -423,5 +437,39 @@ } | ||
_assignSlotsToChildren() { | ||
const defaultSlot = this.constructor.getMetadata().getDefaultSlot(); | ||
const domChildren = Array.from(this.children); | ||
domChildren.filter(child => child._slot).forEach(child => { | ||
child.setAttribute("slot", child._slot); | ||
domChildren.forEach(child => { | ||
const slotName = this.constructor._getSlotName(child); | ||
const slot = child.getAttribute("slot"); | ||
const hasSlot = !!slot; | ||
// Assign individual slots, f.e. items => items-1 | ||
if (child._individualSlot) { | ||
child.setAttribute("slot", child._individualSlot); | ||
return; | ||
} | ||
// If the user set a slot equal to the default slot, f.e. slot="content", remove it | ||
// Otherwise, stop here | ||
if (slotName === defaultSlot) { | ||
if (hasSlot) { | ||
child.removeAttribute("slot"); | ||
} | ||
return; | ||
} | ||
// Compatibility - for the ones with "data-ui5-slot" | ||
// If they don't have a slot yet, and are not of the default child type, set slotName as slot | ||
if (!hasSlot) { | ||
child.setAttribute("slot", slotName); | ||
} | ||
}, this); | ||
domChildren.filter(child => child._compatibilitySlot).forEach(child => { | ||
const hasSlot = !!child.getAttribute("slot"); | ||
const needsSlot = child._compatibilitySlot !== defaultSlot; | ||
if (!hasSlot && needsSlot) { | ||
child.setAttribute("slot", child._compatibilitySlot); | ||
} | ||
}); | ||
@@ -509,4 +557,5 @@ } | ||
let compatEventResult = true; // Initialized to true, because if the event is not fired at all, it should be considered "not-prevented" | ||
const noConflict = getWCNoConflict(); | ||
let customEvent = new CustomEvent(name, { | ||
const noConflictEvent = new CustomEvent(`ui5-${name}`, { | ||
detail: data, | ||
@@ -518,17 +567,19 @@ composed: false, | ||
// This will be false if the compat event is prevented | ||
compatEventResult = this.dispatchEvent(noConflictEvent); | ||
if (noConflict === true || (noConflict.events && noConflict.events.includes && noConflict.events.includes(name))) { | ||
return compatEventResult; | ||
} | ||
const customEvent = new CustomEvent(name, { | ||
detail: data, | ||
composed: false, | ||
bubbles: true, | ||
cancelable, | ||
}); | ||
// This will be false if the normal event is prevented | ||
const normalEventResult = this.dispatchEvent(customEvent); | ||
if (UI5Element.noConflictEvents.includes(name)) { | ||
customEvent = new CustomEvent(`ui5-${name}`, { | ||
detail: data, | ||
composed: false, | ||
bubbles: true, | ||
cancelable, | ||
}); | ||
// This will be false if the compat event is prevented | ||
compatEventResult = this.dispatchEvent(customEvent); | ||
} | ||
// Return false if any of the two events was prevented (its result was false). | ||
@@ -539,15 +590,10 @@ return normalEventResult && compatEventResult; | ||
getSlottedNodes(slotName) { | ||
const getSlottedElement = el => { | ||
if (el.tagName.toUpperCase() !== "SLOT") { | ||
return el; | ||
const reducer = (acc, curr) => { | ||
if (curr.tagName.toUpperCase() !== "SLOT") { | ||
return acc.concat([curr]); | ||
} | ||
const nodes = el.assignedNodes(); | ||
if (nodes.length) { | ||
return getSlottedElement(nodes[0]); | ||
} | ||
return acc.concat(curr.assignedElements({ flatten: true })); | ||
}; | ||
return this[slotName].map(getSlottedElement); | ||
return this[slotName].reduce(reducer, []); | ||
} | ||
@@ -569,2 +615,27 @@ | ||
static _getSlotName(child) { | ||
const defaultSlot = this.getMetadata().getDefaultSlot(); | ||
// Text nodes can only go to the default slot | ||
if (!(child instanceof HTMLElement)) { | ||
return defaultSlot; | ||
} | ||
// Check for explicitly given logical slot | ||
const ui5Slot = child.getAttribute("data-ui5-slot"); | ||
if (ui5Slot) { | ||
return ui5Slot; | ||
} | ||
// Discover the slot based on the real slot name (f.e. footer => footer, or content-32 => content) | ||
const slot = child.getAttribute("slot"); | ||
if (slot) { | ||
const match = slot.match(/^(.+?)-\d+$/); | ||
return match ? match[1] : slot; | ||
} | ||
// Use default slot as a fallback | ||
return defaultSlot; | ||
} | ||
static generateAccessors() { | ||
@@ -610,25 +681,3 @@ const proto = this.prototype; | ||
} | ||
// Node Text | ||
Object.defineProperty(proto, "_nodeText", { | ||
get() { | ||
return this._state._nodeText; | ||
}, | ||
set() { | ||
throw new Error("Cannot set node text directly, use the DOM APIs"); | ||
}, | ||
}); | ||
} | ||
static get noConflictEvents() { | ||
if (!this._noConflictEvents) { | ||
const noConflictConfig = getWCNoConflict(); | ||
this._noConflictEvents = []; | ||
if (typeof noConflictConfig === "object" && typeof noConflictConfig.events === "string") { | ||
this._noConflictEvents = noConflictConfig.events.split(",").map(evtName => evtName.trim()); | ||
} | ||
} | ||
return this._noConflictEvents; | ||
} | ||
} | ||
@@ -635,0 +684,0 @@ const kebabToCamelCase = string => toCamelCase(string.split("-")); |
@@ -17,6 +17,2 @@ import DataType from "./types/DataType.js"; | ||
usesNodeText() { | ||
return !!this.metadata.usesNodeText; | ||
} | ||
getDefaultSlot() { | ||
@@ -96,10 +92,24 @@ return this.metadata.defaultSlot || "content"; | ||
const validateSingleSlot = (value, propData) => { | ||
const getSlottedElement = el => { | ||
return el.tagName.toUpperCase() !== "SLOT" ? el : getSlottedElement(el.assignedNodes()[0]); | ||
if (value === null) { | ||
return value; | ||
} | ||
const getSlottedNodes = el => { | ||
const isTag = el instanceof HTMLElement; | ||
const isSlot = isTag && el.tagName.toUpperCase() === "SLOT"; | ||
if (isSlot) { | ||
return el.assignedElements({ flatten: true }); | ||
} | ||
return [el]; | ||
}; | ||
const propertyType = propData.type; | ||
if (value !== null && !(getSlottedElement(value) instanceof propertyType)) { | ||
throw new Error(`${value} is not of type ${propertyType}`); | ||
} | ||
const slottedNodes = getSlottedNodes(value); | ||
slottedNodes.forEach(el => { | ||
if (!(el instanceof propertyType)) { | ||
throw new Error(`${el} is not of type ${propertyType}`); | ||
} | ||
}); | ||
@@ -106,0 +116,0 @@ return value; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
688489
101
12544
2
+ Added@ui5/webcomponents-core@0.11.0(transitive)
- Removed@ui5/webcomponents-core@0.10.1(transitive)