@ui5/webcomponents-base
Advanced tools
Comparing version 0.0.0-389bdbabc to 0.0.0-39bd3067f
import { registerThemeProperties } from "./dist/AssetRegistry.js"; | ||
import "./dist/features/calendar/Buddhist.js"; | ||
import "./dist/features/calendar/Islamic.js"; | ||
import "./dist/features/calendar/Japanese.js"; | ||
import "./dist/features/calendar/Persian.js"; | ||
// ESM bundle targets Edge + browsers with native support | ||
import "./dist/features/browsersupport/Edge.js"; | ||
import "./dist/features/OpenUI5Support.js"; | ||
@@ -16,2 +12,3 @@ // Test components | ||
import "./dist/test-resources/elements/Child.js"; | ||
import "./dist/test-resources/elements/WithStaticArea.js"; | ||
import "./dist/test-resources/elements/GenericExt.js"; | ||
@@ -18,0 +15,0 @@ |
@@ -6,2 +6,40 @@ # Change Log | ||
# [0.19.0](https://github.com/SAP/ui5-webcomponents/compare/v0.18.0...v0.19.0) (2020-03-27) | ||
### Bug Fixes | ||
* **framework:** fix travis build ([#1212](https://github.com/SAP/ui5-webcomponents/issues/1212)) ([7f30cf3](https://github.com/SAP/ui5-webcomponents/commit/7f30cf3)) | ||
* **framework:** openUI5 cldr support re-added ([#1207](https://github.com/SAP/ui5-webcomponents/issues/1207)) ([6bf40a2](https://github.com/SAP/ui5-webcomponents/commit/6bf40a2)) | ||
* **framework:** Provide a workaround for Firefox 74 shadow root bug ([#1347](https://github.com/SAP/ui5-webcomponents/issues/1347)) ([7cc67a7](https://github.com/SAP/ui5-webcomponents/commit/7cc67a7)) | ||
* **framework:** StaticArea and StaticAreaElement identify as UI5Element ([#1168](https://github.com/SAP/ui5-webcomponents/issues/1168)) ([28f827a](https://github.com/SAP/ui5-webcomponents/commit/28f827a)) | ||
* **framework:** prevent infinite loop when fetching i18n bundles ([#1333](https://github.com/SAP/ui5-webcomponents/issues/1333)) ([f605566](https://github.com/SAP/ui5-webcomponents/commit/f605566)) | ||
* **framework:** prevent error when deleting static area item ([#1335](https://github.com/SAP/ui5-webcomponents/issues/1335)) ([5a99536](https://github.com/SAP/ui5-webcomponents/commit/5a99536)) | ||
* **framework:** apply size "compact" for StaticArea items ([#1204](https://github.com/SAP/ui5-webcomponents/issues/1204)) ([c411774](https://github.com/SAP/ui5-webcomponents/commit/c411774)) | ||
* **framework:** merge metadata properly ([#1092](https://github.com/SAP/ui5-webcomponents/issues/1092)) ([6a29872](https://github.com/SAP/ui5-webcomponents/commit/6a29872)) | ||
* **framework:** create font face style tag only once ([#1090](https://github.com/SAP/ui5-webcomponents/issues/1090)) ([1a09e13](https://github.com/SAP/ui5-webcomponents/commit/1a09e13)) | ||
### Code Refactoring | ||
* **framework:** propagate compact size when ui5-content-density-compact class is set ([#1136](https://github.com/SAP/ui5-webcomponents/issues/1136)) ([2db62ba](https://github.com/SAP/ui5-webcomponents/commit/2db62ba)) | ||
### Features | ||
* **framework:** Allow the registration of custom themes ([#1109](https://github.com/SAP/ui5-webcomponents/issues/1109)) ([6a69521](https://github.com/SAP/ui5-webcomponents/commit/6a69521)) | ||
* **framework:** create getLocaleData API ([#1269](https://github.com/SAP/ui5-webcomponents/issues/1269)) ([c9253a6](https://github.com/SAP/ui5-webcomponents/commit/c9253a6)) | ||
* **framework:** OpenUI5 integration ([#1138](https://github.com/SAP/ui5-webcomponents/issues/1138)) ([5527990](https://github.com/SAP/ui5-webcomponents/commit/5527990)) | ||
* **Itemnavigation:** add paging behaviour ([#1116](https://github.com/SAP/ui5-webcomponents/issues/1116)) ([1cb0832](https://github.com/SAP/ui5-webcomponents/commit/1cb0832)) | ||
* **ScrollEnablement:** enhance implementation to work on desktop ([#1374](https://github.com/SAP/ui5-webcomponents/issues/1374)) ([2567bea](https://github.com/SAP/ui5-webcomponents/commit/2567bea)) | ||
### BREAKING CHANGES | ||
* **framework:** remove `set/get` for compact size, use CSS class `ui5-content-density-compact` as a replacement. | ||
# [0.18.0](https://github.com/SAP/ui5-webcomponents/compare/v0.17.0...v0.18.0) (2019-12-02) | ||
@@ -8,0 +46,0 @@ |
@@ -1,6 +0,6 @@ | ||
import "../shims/jquery-shim.js"; | ||
import "../shims/Core-shim.js"; | ||
import { getLanguage } from "../LocaleProvider.js"; | ||
import getLocale from "../locale/getLocale.js"; | ||
import { fetchJsonOnce } from "../util/FetchHelper.js"; | ||
import { normalizeLocale, nextFallbackLocale } from "../util/normalizeLocale.js"; | ||
import normalizeLocale from "../locale/normalizeLocale.js"; | ||
import nextFallbackLocale from "../locale/nextFallbackLocale.js"; | ||
import { DEFAULT_LANGUAGE } from "../generated/AssetParameters.js"; | ||
@@ -52,3 +52,3 @@ const bundleData = new Map(); | ||
const language = getLanguage(); | ||
const language = getLocale().getLanguage(); | ||
@@ -60,2 +60,6 @@ let localeId = normalizeLocale(language); | ||
if (localeId === DEFAULT_LANGUAGE) { | ||
return; | ||
} | ||
const bundleURL = bundlesForPackage[localeId]; | ||
@@ -65,3 +69,3 @@ | ||
setI18nBundleData(packageName, bundleURL); | ||
return bundleURL; | ||
return; | ||
} | ||
@@ -68,0 +72,0 @@ |
@@ -1,6 +0,6 @@ | ||
import { registerModuleContent } from "../ResourceLoaderOverrides.js"; | ||
import { fetchJsonOnce } from "../util/FetchHelper.js"; | ||
import { getFeature } from "../FeaturesRegistry.js"; | ||
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from "../generated/AssetParameters.js"; | ||
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 resources = new Map(); | ||
const cldrData = {}; | ||
@@ -38,9 +38,9 @@ const cldrUrls = {}; | ||
let localeId = `${language}_${region}`; | ||
if (!supportedLocales.includes(localeId)) { | ||
if (!SUPPORTED_LOCALES.includes(localeId)) { | ||
// fallback to language only | ||
localeId = language; | ||
} | ||
if (!supportedLocales.includes(localeId)) { | ||
if (!SUPPORTED_LOCALES.includes(localeId)) { | ||
// fallback to english | ||
localeId = "en"; | ||
localeId = DEFAULT_LOCALE; | ||
} | ||
@@ -57,3 +57,3 @@ | ||
const missingLocales = supportedLocales.filter(locale => !cldrData[locale] && !cldrUrls[locale]); | ||
const missingLocales = SUPPORTED_LOCALES.filter(locale => !cldrData[locale] && !cldrUrls[locale]); | ||
missingLocales.forEach(locale => { | ||
@@ -64,2 +64,20 @@ cldrUrls[locale] = cldrMappingFn(locale); | ||
const registerModuleContent = (moduleName, content) => { | ||
resources.set(moduleName, content); | ||
}; | ||
const getModuleContent = moduleName => { | ||
const moduleContent = resources.get(moduleName); | ||
if (moduleContent) { | ||
return moduleContent; | ||
} | ||
const missingModule = moduleName.match(/sap\/ui\/core\/cldr\/(\w+)\.json/); | ||
if (missingModule) { | ||
throw new Error(`CLDR data for locale ${missingModule[1]} is not loaded!`); | ||
} | ||
throw new Error(`Unknown module ${moduleName}`); | ||
}; | ||
const fetchCldr = async (language, region, script) => { | ||
@@ -69,5 +87,10 @@ resolveMissingMappings(); | ||
const cldrObj = cldrData[localeId]; | ||
let cldrObj = cldrData[localeId]; | ||
const url = cldrUrls[localeId]; | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
if (!cldrObj && OpenUI5Support) { | ||
cldrObj = OpenUI5Support.getLocaleDataObject(); | ||
} | ||
if (cldrObj) { | ||
@@ -104,3 +127,4 @@ // inlined from build or fetched independently | ||
getCldrData, | ||
getModuleContent, | ||
_registerMappingFunction, | ||
}; |
@@ -1,2 +0,4 @@ | ||
import { fetchJsonOnce } from "../util/FetchHelper.js"; | ||
import { fetchJsonOnce, fetchTextOnce } from "../util/FetchHelper.js"; | ||
import { DEFAULT_THEME } from "../generated/AssetParameters.js"; | ||
import getFileExtension from "../util/getFileExtension.js"; | ||
@@ -18,3 +20,5 @@ const themeURLs = new Map(); | ||
* registerThemeProperties("my-package", "my_theme", {"_": ":root{--var1: red;}"}); | ||
* 3) Pass a URL to a JSON file, containing the CSS Vars in its "_" property. Will be fetched on demand, not upon registration. | ||
* 3) Pass a URL to a CSS file, containing the CSS Vars. Will be fetched on demand, not upon registration. | ||
* registerThemeProperties("my-package", "my_theme", "http://url/to/my/theme.css"); | ||
* 4) Pass a URL to a JSON file, containing the CSS Vars in its "_" property. Will be fetched on demand, not upon registration. | ||
* registerThemeProperties("my-package", "my_theme", "http://url/to/my/theme.json"); | ||
@@ -25,3 +29,3 @@ * | ||
* @param themeName - the theme which the CSS Vars implement | ||
* @param style - can be one of three options: a string, an object with a "_" property or a URL to a JSON file with a "_" property | ||
* @param style - can be one of four options: a string, an object with a "_" property, URL to a CSS file, or URL to a JSON file with a "_" property | ||
*/ | ||
@@ -51,9 +55,11 @@ const registerThemeProperties = (packageName, themeName, style) => { | ||
const regThemesStr = [...registeredThemes.values()].join(", "); | ||
console.warn(`You have requested a non-registered theme - falling back to sap_fiori_3. Registered themes are: ${regThemesStr}`); /* eslint-disable-line */ | ||
return themeStyles.get(`${packageName}_sap_fiori_3`); | ||
console.warn(`You have requested a non-registered theme - falling back to ${DEFAULT_THEME}. Registered themes are: ${regThemesStr}`); /* eslint-disable-line */ | ||
return themeStyles.get(`${packageName}_${DEFAULT_THEME}`); | ||
} | ||
const data = await fetchThemeProperties(packageName, themeName); | ||
themeStyles.set(`${packageName}_${themeName}`, data._); | ||
return data._; | ||
const themeProps = data._ || data; | ||
themeStyles.set(`${packageName}_${themeName}`, themeProps); | ||
return themeProps; | ||
}; | ||
@@ -67,3 +73,4 @@ | ||
} | ||
return fetchJsonOnce(url); | ||
return getFileExtension(url) === ".css" ? fetchTextOnce(url) : fetchJsonOnce(url); | ||
}; | ||
@@ -75,2 +82,6 @@ | ||
const isThemeRegistered = theme => { | ||
return registeredThemes.has(theme); | ||
}; | ||
export { | ||
@@ -80,2 +91,3 @@ registerThemeProperties, | ||
getRegisteredPackages, | ||
isThemeRegistered, | ||
}; |
import whenDOMReady from "./util/whenDOMReady.js"; | ||
import insertFontFace from "./FontFace.js"; | ||
import { getTheme } from "./config/Theme.js"; | ||
import { _applyTheme } from "./Theming.js"; | ||
import applyTheme from "./theming/applyTheme.js"; | ||
import whenPolyfillLoaded from "./compatibility/whenPolyfillLoaded.js"; | ||
import { getFeature } from "./FeaturesRegistry.js"; | ||
@@ -15,4 +16,10 @@ let bootPromise; | ||
bootPromise = new Promise(async resolve => { | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
if (OpenUI5Support) { | ||
await OpenUI5Support.init(); | ||
} | ||
await whenDOMReady(); | ||
await _applyTheme(getTheme()); | ||
await applyTheme(getTheme()); | ||
OpenUI5Support && OpenUI5Support.attachListeners(); | ||
insertFontFace(); | ||
@@ -19,0 +26,0 @@ await whenPolyfillLoaded(); |
import { getAnimationMode as getConfiguredAnimationMode } from "../InitialConfiguration.js"; | ||
const animationMode = getConfiguredAnimationMode(); | ||
let animationMode; | ||
const getAnimationMode = () => { | ||
if (animationMode === undefined) { | ||
animationMode = getConfiguredAnimationMode(); | ||
} | ||
return animationMode; | ||
@@ -7,0 +11,0 @@ }; |
@@ -1,13 +0,13 @@ | ||
import CalendarType from "@ui5/webcomponents-utils/dist/sap/ui/core/CalendarType.js"; | ||
import CalendarType from "../types/CalendarType.js"; | ||
import { getCalendarType as getConfiguredCalendarType } from "../InitialConfiguration.js"; | ||
const calendarType = getConfiguredCalendarType(); | ||
let calendarType; | ||
const getCalendarType = () => { | ||
if (calendarType) { | ||
const type = Object.keys(CalendarType).find(calType => calType === calendarType); | ||
if (calendarType === undefined) { | ||
calendarType = getConfiguredCalendarType(); | ||
} | ||
if (type) { | ||
return type; | ||
} | ||
if (CalendarType.isValid(calendarType)) { | ||
return calendarType; | ||
} | ||
@@ -14,0 +14,0 @@ |
import { getFormatSettings } from "../InitialConfiguration.js"; | ||
const formatSettings = getFormatSettings(); | ||
let formatSettings; | ||
const getFirstDayOfWeek = () => { | ||
if (formatSettings === undefined) { | ||
formatSettings = getFormatSettings(); | ||
} | ||
return formatSettings.firstDayOfWeek; | ||
@@ -7,0 +11,0 @@ }; |
import { getLanguage as getConfiguredLanguage } from "../InitialConfiguration.js"; | ||
const language = getConfiguredLanguage(); | ||
let language; | ||
const getLanguage = () => { | ||
if (language === undefined) { | ||
language = getConfiguredLanguage(); | ||
} | ||
return language; | ||
@@ -7,0 +10,0 @@ }; |
@@ -12,9 +12,14 @@ import { getNoConflict as getConfiguredNoConflict } from "../InitialConfiguration.js"; | ||
let noConflict = getConfiguredNoConflict(); | ||
let noConflict; | ||
const shouldNotFireOriginalEvent = eventName => { | ||
return !(noConflict.events && noConflict.events.includes && noConflict.events.includes(eventName)); | ||
const nc = getNoConflict(); | ||
return !(nc.events && nc.events.includes && nc.events.includes(eventName)); | ||
}; | ||
const getNoConflict = () => { | ||
if (noConflict === undefined) { | ||
noConflict = getConfiguredNoConflict(); | ||
} | ||
return noConflict; | ||
@@ -24,2 +29,4 @@ }; | ||
const skipOriginalEvent = eventName => { | ||
const nc = getNoConflict(); | ||
// Always fire these events | ||
@@ -31,3 +38,3 @@ if (shouldFireOriginalEvent(eventName)) { | ||
// Read from the configuration | ||
if (noConflict === true) { | ||
if (nc === true) { | ||
return true; | ||
@@ -34,0 +41,0 @@ } |
import { getTheme as getConfiguredTheme } from "../InitialConfiguration.js"; | ||
import { _applyTheme } from "../Theming.js"; | ||
import applyTheme from "../theming/applyTheme.js"; | ||
let theme = getConfiguredTheme(); | ||
let theme; | ||
const getTheme = () => { | ||
if (theme === undefined) { | ||
theme = getConfiguredTheme(); | ||
} | ||
return theme; | ||
@@ -18,3 +22,3 @@ }; | ||
// Update CSS Custom Properties | ||
await _applyTheme(theme); | ||
await applyTheme(theme); | ||
}; | ||
@@ -21,0 +25,0 @@ |
@@ -9,3 +9,3 @@ import RenderScheduler from "../RenderScheduler.js"; | ||
isEnd, | ||
} from "../events/PseudoEvents.js"; | ||
} from "../Keys.js"; | ||
@@ -25,3 +25,4 @@ import EventProvider from "../EventProvider.js"; | ||
this.behavior = options.behavior || ItemNavigationBehavior.Static; | ||
this.hasNextPage = true; // used in Paging mode and controlled from the rootWebComponent | ||
this.hasPrevPage = true; // used in Paging mode and controlled from the rootWebComponent | ||
const navigationMode = options.navigationMode; | ||
@@ -218,4 +219,6 @@ const autoNavigation = !navigationMode || navigationMode === NavigationMode.Auto; | ||
const items = this._getItems(); | ||
const rowIndex = this.currentIndex - items.length; | ||
const offset = this.currentIndex - items.length; | ||
if (this.behavior === ItemNavigationBehavior.Cyclic) { | ||
this.currentIndex = 0; | ||
return; | ||
@@ -226,7 +229,7 @@ } | ||
this._handleNextPage(); | ||
} else { | ||
this.currentIndex = items.length - 1; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { | ||
start: false, end: true, offset: this.currentIndex, rowIndex, | ||
}); | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: false, end: true, offset }); | ||
} | ||
@@ -236,6 +239,6 @@ | ||
const items = this._getItems(); | ||
const rowIndex = this.currentIndex + this.rowSize; | ||
const offset = this.currentIndex + this.rowSize; | ||
if (this.behavior === ItemNavigationBehavior.Cyclic) { | ||
this.currentIndex = items.length + this.currentIndex; | ||
this.currentIndex = items.length - 1; | ||
return; | ||
@@ -246,7 +249,7 @@ } | ||
this._handlePrevPage(); | ||
} else { | ||
this.currentIndex = 0; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { | ||
start: true, end: false, offset: this.currentIndex, rowIndex, | ||
}); | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: true, end: false, offset }); | ||
} | ||
@@ -267,2 +270,3 @@ | ||
this.fireEvent(ItemNavigation.PAGE_TOP); | ||
const items = this._getItems(); | ||
@@ -272,3 +276,3 @@ if (!this.hasPrevPage) { | ||
} else { | ||
this.currentIndex = 41; | ||
this.currentIndex = (this.pageSize || items.length) - 1; | ||
} | ||
@@ -275,0 +279,0 @@ } |
@@ -0,1 +1,2 @@ | ||
import { isPhone } from "../Device.js"; | ||
import EventProvider from "../EventProvider.js"; | ||
@@ -5,2 +6,3 @@ import scroll from "../animations/scroll.js"; | ||
const scrollEventName = "scroll"; | ||
const touchEndEventName = isPhone() ? "touchend" : "mouseup"; | ||
@@ -10,4 +12,26 @@ class ScrollEnablement extends EventProvider { | ||
super(); | ||
containerComponent.addEventListener("touchstart", this.ontouchstart.bind(this), { passive: true }); | ||
containerComponent.addEventListener("touchmove", this.ontouchmove.bind(this), { passive: true }); | ||
this.containerComponent = containerComponent; | ||
this.mouseMove = this.ontouchmove.bind(this); | ||
this.mouseUp = this.ontouchend.bind(this); | ||
this.touchStart = this.ontouchstart.bind(this); | ||
this.isPhone = isPhone(); | ||
// On Android devices touchmove is thrown one more time than neccessary (together with touchend) | ||
// so we have to cache the previus coordinates in order to provide correct parameters in the | ||
// event for Android | ||
this.cachedValue = {}; | ||
// In components like Carousel you need to know if the user has clicked on something or swiped | ||
// in order to throw the needed event or not | ||
this.startX = 0; | ||
this.startY = 0; | ||
if (this.isPhone) { | ||
containerComponent.addEventListener("touchstart", this.touchStart, { passive: true }); | ||
containerComponent.addEventListener("touchmove", this.mouseMove, { passive: true }); | ||
containerComponent.addEventListener("touchend", this.mouseUp, { passive: true }); | ||
} else { | ||
containerComponent.addEventListener("mousedown", this.touchStart, { passive: true }); | ||
} | ||
} | ||
@@ -46,4 +70,4 @@ | ||
const rect = this._container.getBoundingClientRect(); | ||
const x = touch.clientX; | ||
const y = touch.clientY; | ||
const x = this.isPhone ? touch.clientX : touch.x; | ||
const y = this.isPhone ? touch.clientY : touch.y; | ||
@@ -55,7 +79,17 @@ return x >= rect.left && x <= rect.right | ||
ontouchstart(event) { | ||
const touch = event.touches[0]; | ||
this._prevDragX = touch.pageX; | ||
this._prevDragY = touch.pageY; | ||
const touch = this.isPhone ? event.touches[0] : null; | ||
this._canScroll = this._isTouchInside(touch); | ||
if (!this.isPhone) { | ||
document.addEventListener("mouseup", this.mouseUp, { passive: true }); | ||
document.addEventListener("mousemove", this.mouseMove, { passive: true }); | ||
} else { | ||
// Needed only on mobile | ||
this.startX = touch.pageX; | ||
this.startY = touch.pageY; | ||
} | ||
this._prevDragX = this.isPhone ? touch.pageX : event.x; | ||
this._prevDragY = this.isPhone ? touch.pageY : event.y; | ||
this._canScroll = this._isTouchInside(this.isPhone ? touch : event); | ||
} | ||
@@ -69,6 +103,6 @@ | ||
const container = this._container; | ||
const touch = event.touches[0]; | ||
const touch = this.isPhone ? event.touches[0] : null; | ||
const dragX = touch.pageX; | ||
const dragY = touch.pageY; | ||
const dragX = this.isPhone ? touch.pageX : event.x; | ||
const dragY = this.isPhone ? touch.pageY : event.y; | ||
@@ -78,9 +112,54 @@ container.scrollLeft += this._prevDragX - dragX; | ||
this.fireEvent(scrollEventName, {}); | ||
this.fireEvent(scrollEventName, { | ||
isLeft: dragX > this._prevDragX, | ||
isRight: dragX < this._prevDragX, | ||
}); | ||
this.cachedValue.dragX = this._prevDragX; | ||
this.cachedValue.dragY = this._prevDragY; | ||
this._prevDragX = dragX; | ||
this._prevDragY = dragY; | ||
} | ||
ontouchend(event) { | ||
if (this.isPhone) { | ||
const deltaX = Math.abs(event.changedTouches[0].pageX - this.startX); | ||
const deltaY = Math.abs(event.changedTouches[0].pageY - this.startY); | ||
if (deltaX < 10 && deltaY < 10) { | ||
return; | ||
} | ||
} | ||
if (!this._canScroll) { | ||
return; | ||
} | ||
const container = this._container; | ||
const dragX = this.isPhone ? event.changedTouches[0].pageX : event.x; | ||
const dragY = this.isPhone ? event.changedTouches[0].pageY : event.y; | ||
container.scrollLeft += this._prevDragX - dragX; | ||
container.scrollTop += this._prevDragY - dragY; | ||
const useCachedValues = dragX === this._prevDragX; | ||
const _dragX = useCachedValues ? this.cachedValue.dragX : dragX; | ||
// const _dragY = useCachedValues ? this.cachedValue.dragY : dragY; add if needed | ||
this.fireEvent(touchEndEventName, { | ||
isLeft: _dragX < this._prevDragX, | ||
isRight: _dragX > this._prevDragX, | ||
}); | ||
this._prevDragX = dragX; | ||
this._prevDragY = dragY; | ||
if (!this.isPhone) { | ||
document.removeEventListener("mousemove", this.mouseMove, { passive: true }); | ||
document.removeEventListener("mouseup", this.mouseUp); | ||
} | ||
} | ||
} | ||
export default ScrollEnablement; |
@@ -5,3 +5,3 @@ // CSS Custom Properties | ||
// String | ||
import "@ui5/webcomponents-utils/dist/sap/ui/thirdparty/es6-string-methods.js"; | ||
import "../../thirdparty/es6-string-methods.js"; | ||
@@ -8,0 +8,0 @@ // Object |
@@ -5,2 +5,3 @@ /** | ||
import createStyleInHead from "./util/createStyleInHead.js"; | ||
import { getFeature } from "./FeaturesRegistry.js"; | ||
@@ -64,2 +65,8 @@ /* CDN Locations */ | ||
// If OpenUI5 is found, let it set the font | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
if (OpenUI5Support && OpenUI5Support.isLoaded()) { | ||
return; | ||
} | ||
createStyleInHead(fontFaceCSS, { "data-ui5-font-face": "" }); | ||
@@ -66,0 +73,0 @@ }; |
@@ -15,9 +15,7 @@ import { fetchI18nBundle, getI18nBundleData } from "./asset-registries/i18n.js"; | ||
} | ||
const bundle = getI18nBundleData(this.packageName); | ||
const messageText = bundle && bundle[textObj.key] ? bundle[textObj.key] : textObj.defaultText; | ||
if (!bundle || !bundle[textObj.key]) { | ||
return formatMessage(textObj.defaultText, params); // Fallback to "en" | ||
} | ||
return formatMessage(bundle[textObj.key], params); | ||
return formatMessage(messageText, params); | ||
} | ||
@@ -31,7 +29,7 @@ } | ||
const i18nBunle = new I18nBundle(packageName); | ||
I18nBundleInstances.set(packageName, i18nBunle); | ||
return i18nBunle; | ||
const i18nBundle = new I18nBundle(packageName); | ||
I18nBundleInstances.set(packageName, i18nBundle); | ||
return i18nBundle; | ||
}; | ||
export { fetchI18nBundle, getI18nBundle }; |
@@ -0,6 +1,10 @@ | ||
import merge from "./thirdparty/merge.js"; | ||
import { getFeature } from "./FeaturesRegistry.js"; | ||
import { DEFAULT_THEME } from "./generated/AssetParameters.js"; | ||
let initialized = false; | ||
const initialConfig = { | ||
let initialConfig = { | ||
animationMode: "full", | ||
theme: "sap_fiori_3", | ||
theme: DEFAULT_THEME, | ||
rtl: null, | ||
@@ -53,4 +57,2 @@ language: null, | ||
let runtimeConfig = {}; | ||
const parseConfigurationScript = () => { | ||
@@ -69,3 +71,3 @@ const configScript = document.querySelector("[data-ui5-config]") || document.querySelector("[data-id='sap-ui-config']"); // for backward compatibility | ||
if (configJSON) { | ||
runtimeConfig = Object.assign({}, configJSON); | ||
initialConfig = merge(initialConfig, configJSON); | ||
} | ||
@@ -91,12 +93,17 @@ } | ||
runtimeConfig[param] = value; | ||
initialConfig[param] = value; | ||
}); | ||
}; | ||
const applyConfigurations = () => { | ||
Object.keys(runtimeConfig).forEach(key => { | ||
initialConfig[key] = runtimeConfig[key]; | ||
}); | ||
const applyOpenUI5Configuration = () => { | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
if (!OpenUI5Support || !OpenUI5Support.isLoaded()) { | ||
return; | ||
} | ||
const OpenUI5Config = OpenUI5Support.getConfigurationSettingsObject(); | ||
initialConfig = merge(initialConfig, OpenUI5Config); | ||
}; | ||
const initConfiguration = () => { | ||
@@ -107,6 +114,11 @@ if (initialized) { | ||
// 1. Lowest priority - configuration script | ||
parseConfigurationScript(); | ||
// 2. URL parameters overwrite configuration script parameters | ||
parseURLParameters(); | ||
applyConfigurations(); | ||
// 3. If OpenUI5 is detected, it has the highest priority | ||
applyOpenUI5Configuration(); | ||
initialized = true; | ||
@@ -113,0 +125,0 @@ }; |
import RenderQueue from "./RenderQueue.js"; | ||
import { getAllRegisteredTags } from "./CustomElementsRegistry.js"; | ||
@@ -121,29 +122,9 @@ const MAX_RERENDER_COUNT = 10; | ||
static getNotDefinedComponents() { | ||
return Array.from(document.querySelectorAll("*")).filter(el => el.localName.startsWith("ui5-") && !el.isUI5Element); | ||
static whenAllCustomElementsAreDefined() { | ||
const definedPromises = getAllRegisteredTags().map(tag => customElements.whenDefined(tag)); | ||
return Promise.all(definedPromises); | ||
} | ||
/** | ||
* return a promise that will be resolved once all ui5 webcomponents on the page have their shadow root ready | ||
*/ | ||
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 are: " + [...stillUndefined].map(el => el.localName).join(" ; ")); | ||
} | ||
return Promise.resolve(); | ||
} | ||
static async whenFinished() { | ||
await RenderScheduler.whenShadowDOMReady(); | ||
await RenderScheduler.whenAllCustomElementsAreDefined(); | ||
await RenderScheduler.whenDOMUpdated(); | ||
@@ -150,0 +131,0 @@ } |
@@ -24,2 +24,6 @@ const getStaticAreaInstance = () => { | ||
get isUI5Element() { | ||
return true; | ||
} | ||
destroy() { | ||
@@ -31,3 +35,5 @@ const staticAreaDomRef = document.querySelector(this.tagName.toLowerCase()); | ||
customElements.define("ui5-static-area", StaticAreaElement); | ||
if (!customElements.get("ui5-static-area")) { | ||
customElements.define("ui5-static-area", StaticAreaElement); | ||
} | ||
@@ -34,0 +40,0 @@ export { |
import { getStaticAreaInstance, removeStaticArea } from "./StaticArea.js"; | ||
import RenderScheduler from "./RenderScheduler.js"; | ||
@@ -12,4 +13,9 @@ /** | ||
this.ui5ElementContext = _ui5ElementContext; | ||
this._rendered = false; | ||
} | ||
isRendered() { | ||
return this._rendered; | ||
} | ||
/** | ||
@@ -20,3 +26,3 @@ * @protected | ||
const renderResult = this.ui5ElementContext.constructor.staticAreaTemplate(this.ui5ElementContext), | ||
stylesToAdd = this.ui5ElementContext.constructor.staticAreaStyles || false; | ||
stylesToAdd = window.ShadyDOM ? false : this.ui5ElementContext.constructor.staticAreaStyles; | ||
@@ -31,2 +37,3 @@ if (!this.staticAreaItemDomRef) { | ||
getStaticAreaInstance().appendChild(this.staticAreaItemDomRef); | ||
this._rendered = true; | ||
} | ||
@@ -41,2 +48,6 @@ | ||
_removeFragmentFromStaticArea() { | ||
if (!this.staticAreaItemDomRef) { | ||
return; | ||
} | ||
const staticArea = getStaticAreaInstance(); | ||
@@ -56,5 +67,26 @@ | ||
* @protected | ||
*/ | ||
_updateContentDensity(isCompact) { | ||
if (!this.staticAreaItemDomRef) { | ||
return; | ||
} | ||
if (isCompact) { | ||
this.staticAreaItemDomRef.classList.add("sapUiSizeCompact"); | ||
this.staticAreaItemDomRef.classList.add("ui5-content-density-compact"); | ||
} else { | ||
this.staticAreaItemDomRef.classList.remove("sapUiSizeCompact"); | ||
this.staticAreaItemDomRef.classList.remove("ui5-content-density-compact"); | ||
} | ||
} | ||
/** | ||
* @protected | ||
* Returns reference to the DOM element where the current fragment is added. | ||
*/ | ||
getDomRef() { | ||
async getDomRef() { | ||
if (!this._rendered || !this.staticAreaItemDomRef) { | ||
this._updateFragment(); | ||
} | ||
await RenderScheduler.whenDOMUpdated(); // Wait for the content of the ui5-static-area-item to be rendered | ||
return this.staticAreaItemDomRef.shadowRoot; | ||
@@ -68,6 +100,12 @@ } | ||
} | ||
get isUI5Element() { | ||
return true; | ||
} | ||
} | ||
customElements.define("ui5-static-area-item", StaticAreaItemElement); | ||
if (!customElements.get("ui5-static-area-item")) { | ||
customElements.define("ui5-static-area-item", StaticAreaItemElement); | ||
} | ||
export default StaticAreaItem; |
const registry = new Map(); | ||
const iconCollectionPromises = new Map(); | ||
const ICON_NOT_FOUND = "ICON_NOT_FOUND"; | ||
const DEFAULT_COLLECTION = "SAP-icons"; | ||
@@ -30,6 +31,11 @@ | ||
if (!iconCollectionPromises.has(collection)) { | ||
iconCollectionPromises.set(collection, Promise.reject()); | ||
iconCollectionPromises.set(collection, Promise.resolve(ICON_NOT_FOUND)); | ||
} | ||
await iconCollectionPromises.get(collection); | ||
const iconData = await iconCollectionPromises.get(collection); | ||
if (iconData === ICON_NOT_FOUND) { | ||
return iconData; | ||
} | ||
return registry.get(key); | ||
@@ -36,0 +42,0 @@ }; |
@@ -7,2 +7,3 @@ import { registerThemeProperties } from "../../asset-registries/Themes.js"; | ||
const belizeHcb = `:root{ --var1: orange; }`; | ||
const belizeHcw = `:root{ --var1: orange; }`; | ||
@@ -13,1 +14,2 @@ registerThemeProperties("@ui5/webcomponents-base-test", "sap_fiori_3", fiori3); | ||
registerThemeProperties("@ui5/webcomponents-base-test", "sap_belize_hcb", belizeHcb); | ||
registerThemeProperties("@ui5/webcomponents-base-test", "sap_belize_hcw", belizeHcw); |
@@ -29,2 +29,3 @@ import UI5Element from "../../UI5Element.js"; | ||
}, | ||
managedSlots: true, | ||
slots: { | ||
@@ -31,0 +32,0 @@ default: { |
@@ -6,2 +6,3 @@ import UI5Element from "../../UI5Element.js"; | ||
tag: "ui5-test-parent", | ||
managedSlots: true, | ||
slots: { | ||
@@ -8,0 +9,0 @@ default: { |
@@ -1,45 +0,3 @@ | ||
import { addCustomCSS, getCustomCSS } from "./theming/CustomStyle.js"; | ||
import { getThemeProperties, getRegisteredPackages } from "./asset-registries/Themes.js"; | ||
import { injectThemeProperties } from "./theming/StyleInjection.js"; | ||
import { addCustomCSS } from "./theming/CustomStyle.js"; | ||
const themeChangeCallbacks = []; | ||
const attachThemeChange = function attachThemeChange(callback) { | ||
if (themeChangeCallbacks.indexOf(callback) === -1) { | ||
themeChangeCallbacks.push(callback); | ||
} | ||
}; | ||
const _applyTheme = async theme => { | ||
let cssText = ""; | ||
const registeredPackages = getRegisteredPackages(); | ||
registeredPackages.forEach(async packageName => { | ||
cssText = await getThemeProperties(packageName, theme); | ||
injectThemeProperties(cssText, packageName); | ||
}); | ||
_executeThemeChangeCallbacks(theme); | ||
}; | ||
const _executeThemeChangeCallbacks = theme => { | ||
themeChangeCallbacks.forEach(callback => callback(theme)); | ||
}; | ||
const getEffectiveStyle = ElementClass => { | ||
const tag = ElementClass.getMetadata().getTag(); | ||
const customStyle = getCustomCSS(tag) || ""; | ||
let componentStyles = ElementClass.styles; | ||
if (Array.isArray(componentStyles)) { | ||
componentStyles = componentStyles.join(" "); | ||
} | ||
return `${componentStyles} ${customStyle}`; | ||
}; | ||
export { | ||
attachThemeChange, | ||
_applyTheme, | ||
getEffectiveStyle, | ||
addCustomCSS, | ||
}; | ||
export { addCustomCSS }; // eslint-disable-line |
@@ -11,2 +11,3 @@ import DataType from "./DataType.js"; | ||
Error: "Error", | ||
Information: "Information", | ||
}; | ||
@@ -13,0 +14,0 @@ |
@@ -1,11 +0,13 @@ | ||
import merge from "@ui5/webcomponents-utils/dist/sap/base/util/merge.js"; | ||
import merge from "./thirdparty/merge.js"; | ||
import boot from "./boot.js"; | ||
import { skipOriginalEvent } from "./config/NoConflict.js"; | ||
import DOMObserver from "./compatibility/DOMObserver.js"; | ||
import UI5ElementMetadata from "./UI5ElementMetadata.js"; | ||
import StaticAreaItem from "./StaticAreaItem.js"; | ||
import RenderScheduler from "./RenderScheduler.js"; | ||
import { registerTag, isTagRegistered } from "./CustomElementsRegistry.js"; | ||
import DOMObserver from "./compatibility/DOMObserver.js"; | ||
import { skipOriginalEvent } from "./config/NoConflict.js"; | ||
import getConstructableStyle from "./theming/getConstructableStyle.js"; | ||
import createComponentStyleTag from "./theming/createComponentStyleTag.js"; | ||
import getEffectiveStyle from "./theming/getEffectiveStyle.js"; | ||
import Integer from "./types/Integer.js"; | ||
import RenderScheduler from "./RenderScheduler.js"; | ||
import { getConstructableStyle, createHeadStyle } from "./CSS.js"; | ||
import { getEffectiveStyle } from "./Theming.js"; | ||
import { kebabToCamelCase, camelToKebabCase } from "./util/StringHelper.js"; | ||
@@ -20,7 +22,7 @@ import isValidPropertyName from "./util/isValidPropertyName.js"; | ||
const DefinitionsSet = new Set(); | ||
const IDMap = new Map(); | ||
let autoId = 0; | ||
const elementTimeouts = new Map(); | ||
const GLOBAL_CONTENT_DENSITY_CSS_VAR = "--_ui5_content_density"; | ||
/** | ||
@@ -43,2 +45,3 @@ * Base class for all UI5 Web Components | ||
this._initializeContainers(); | ||
this._upToDate = false; | ||
@@ -52,2 +55,3 @@ let deferredResolve; | ||
this._monitoredChildProps = new Map(); | ||
this._firePropertyChange = false; | ||
} | ||
@@ -59,3 +63,3 @@ | ||
_generateId() { | ||
this._id = this.constructor._nextID(); | ||
this._id = `ui5wc_${++autoId}`; | ||
} | ||
@@ -67,4 +71,7 @@ | ||
_initializeContainers() { | ||
const needsShadowDOM = this.constructor._needsShadowDOM(); | ||
const needsStaticArea = this.constructor._needsStaticArea(); | ||
// Init Shadow Root | ||
if (this.constructor._needsShadowDOM()) { | ||
if (needsShadowDOM) { | ||
this.attachShadow({ mode: "open" }); | ||
@@ -74,3 +81,3 @@ | ||
if (window.ShadyDOM) { | ||
createHeadStyle(this.constructor); | ||
createComponentStyleTag(this.constructor); | ||
} | ||
@@ -86,3 +93,3 @@ | ||
// Init StaticAreaItem only if needed | ||
if (this.constructor._needsStaticArea()) { | ||
if (needsStaticArea) { | ||
this.staticAreaItem = new StaticAreaItem(this); | ||
@@ -97,8 +104,17 @@ } | ||
async connectedCallback() { | ||
const needsShadowDOM = this.constructor._needsShadowDOM(); | ||
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged(); | ||
// Render the Shadow DOM | ||
if (this.constructor._needsShadowDOM()) { | ||
// always register the observer before yielding control to the main thread (await) | ||
this._startObservingDOMChildren(); | ||
if (needsShadowDOM) { | ||
if (slotsAreManaged) { | ||
// always register the observer before yielding control to the main thread (await) | ||
this._startObservingDOMChildren(); | ||
await this._processChildren(); | ||
} | ||
await this._processChildren(); | ||
if (!this.shadowRoot) { // Workaround for Firefox74 bug | ||
await Promise.resolve(); | ||
} | ||
await RenderScheduler.renderImmediately(this); | ||
@@ -110,7 +126,2 @@ this._domRefReadyPromise._deferredResolve(); | ||
} | ||
// Render Fragment if neccessary | ||
if (this.constructor._needsStaticArea()) { | ||
this.staticAreaItem._updateFragment(this); | ||
} | ||
} | ||
@@ -123,4 +134,11 @@ | ||
disconnectedCallback() { | ||
if (this.constructor._needsShadowDOM()) { | ||
this._stopObservingDOMChildren(); | ||
const needsShadowDOM = this.constructor._needsShadowDOM(); | ||
const needsStaticArea = this.constructor._needsStaticArea(); | ||
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged(); | ||
if (needsShadowDOM) { | ||
if (slotsAreManaged) { | ||
this._stopObservingDOMChildren(); | ||
} | ||
if (typeof this.onExitDOM === "function") { | ||
@@ -131,3 +149,3 @@ this.onExitDOM(); | ||
if (this.constructor._needsStaticArea()) { | ||
if (needsStaticArea) { | ||
this.staticAreaItem._removeFragmentFromStaticArea(); | ||
@@ -145,5 +163,7 @@ } | ||
} | ||
const canSlotText = this.constructor.getMetadata().canSlotText(); | ||
const mutationObserverOptions = { | ||
childList: true, | ||
subtree: true, | ||
subtree: canSlotText, | ||
characterData: true, | ||
@@ -177,3 +197,3 @@ }; | ||
const slotsMap = this.constructor.getMetadata().getSlots(); | ||
const canSlotText = slotsMap.default && slotsMap.default.type === Node; | ||
const canSlotText = this.constructor.getMetadata().canSlotText(); | ||
const domChildren = Array.from(canSlotText ? this.childNodes : this.children); | ||
@@ -183,3 +203,3 @@ | ||
for (const [slotName, slotData] of Object.entries(slotsMap)) { // eslint-disable-line | ||
this._clearSlot(slotName); | ||
this._clearSlot(slotName, slotData); | ||
} | ||
@@ -204,5 +224,5 @@ | ||
if (slotData.individualSlots) { | ||
const nextId = (autoIncrementMap.get(slotName) || 0) + 1; | ||
autoIncrementMap.set(slotName, nextId); | ||
child._individualSlot = `${slotName}-${nextId}`; | ||
const nextIndex = (autoIncrementMap.get(slotName) || 0) + 1; | ||
autoIncrementMap.set(slotName, nextIndex); | ||
child._individualSlot = `${slotName}-${nextIndex}`; | ||
} | ||
@@ -231,4 +251,4 @@ | ||
if (child.isUI5Element) { | ||
this._attachChildPropertyUpdated(child, slotData); | ||
if (child.isUI5Element && slotData.listenFor) { | ||
this._attachChildPropertyUpdated(child, slotData.listenFor); | ||
} | ||
@@ -252,3 +272,3 @@ | ||
}); | ||
this._invalidate(); | ||
this._invalidate("slots"); | ||
} | ||
@@ -260,4 +280,3 @@ | ||
*/ | ||
_clearSlot(slotName) { | ||
const slotData = this.constructor.getMetadata().getSlots()[slotName]; | ||
_clearSlot(slotName, slotData) { | ||
const propertyName = slotData.propertyName || slotName; | ||
@@ -355,5 +374,4 @@ | ||
*/ | ||
_attachChildPropertyUpdated(child, propData) { | ||
const listenFor = propData.listenFor, | ||
childMetadata = child.constructor.getMetadata(), | ||
_attachChildPropertyUpdated(child, listenFor) { | ||
const childMetadata = child.constructor.getMetadata(), | ||
slotName = this.constructor._getSlotName(child), // all slotted children have the same configuration | ||
@@ -365,6 +383,2 @@ childProperties = childMetadata.getProperties(); | ||
if (!listenFor) { | ||
return; | ||
} | ||
if (Array.isArray(listenFor)) { | ||
@@ -382,2 +396,3 @@ observedProps = listenFor; | ||
child.addEventListener("_propertyChange", this._invalidateParentOnPropertyUpdate); | ||
child._firePropertyChange = true; | ||
} | ||
@@ -390,2 +405,3 @@ | ||
child.removeEventListener("_propertyChange", this._invalidateParentOnPropertyUpdate); | ||
child._firePropertyChange = false; | ||
} | ||
@@ -399,9 +415,9 @@ | ||
const customEvent = new CustomEvent("_propertyChange", { | ||
detail: { name, newValue: value }, | ||
composed: false, | ||
bubbles: true, | ||
}); | ||
this.dispatchEvent(customEvent); | ||
if (this._firePropertyChange) { | ||
this.dispatchEvent(new CustomEvent("_propertyChange", { | ||
detail: { name, newValue: value }, | ||
composed: false, | ||
bubbles: true, | ||
})); | ||
} | ||
} | ||
@@ -437,3 +453,3 @@ | ||
_invalidate() { | ||
if (this._invalidated) { | ||
if (!this._upToDate) { | ||
// console.log("already invalidated", this, ...arguments); | ||
@@ -444,3 +460,3 @@ return; | ||
if (this.getDomRef() && !this._suppressInvalidation) { | ||
this._invalidated = true; | ||
this._upToDate = false; | ||
// console.log("INVAL", this, ...arguments); | ||
@@ -456,2 +472,4 @@ RenderScheduler.renderDeferred(this); | ||
_render() { | ||
const hasIndividualSlots = this.constructor.getMetadata().hasIndividualSlots(); | ||
// suppress invalidation to prevent state changes scheduling another rendering | ||
@@ -474,6 +492,6 @@ this._suppressInvalidation = true; | ||
// console.log(this.getDomRef() ? "RE-RENDER" : "FIRST RENDER", this); | ||
delete this._invalidated; | ||
this._upToDate = true; | ||
this._updateShadowRoot(); | ||
if (this.constructor._needsStaticArea()) { | ||
if (this._shouldUpdateFragment()) { | ||
this.staticAreaItem._updateFragment(this); | ||
@@ -483,3 +501,5 @@ } | ||
// Safari requires that children get the slot attribute only after the slot tags have been rendered in the shadow DOM | ||
this._assignIndividualSlotsToChildren(); | ||
if (hasIndividualSlots) { | ||
this._assignIndividualSlotsToChildren(); | ||
} | ||
@@ -496,2 +516,6 @@ // Call the onAfterRendering hook | ||
_updateShadowRoot() { | ||
if (!this.constructor._needsShadowDOM()) { | ||
return; | ||
} | ||
let styleToPrepend; | ||
@@ -622,2 +646,12 @@ const renderResult = this.constructor.template(this); | ||
get isCompact() { | ||
return getComputedStyle(this).getPropertyValue(GLOBAL_CONTENT_DENSITY_CSS_VAR) === "compact"; | ||
} | ||
updateStaticAreaItemContentDensity() { | ||
if (this.staticAreaItem) { | ||
this.staticAreaItem._updateContentDensity(this.isCompact); | ||
} | ||
} | ||
/** | ||
@@ -641,17 +675,4 @@ * Used to duck-type UI5 elements without using instanceof | ||
/** | ||
* Used to generate the next auto-increment id for the current class | ||
* @returns {string} | ||
* @private | ||
*/ | ||
static _nextID() { | ||
const className = kebabToCamelCase(this.getMetadata().getTag()); | ||
const lastNumber = IDMap.get(className); | ||
const nextNumber = lastNumber !== undefined ? lastNumber + 1 : 1; | ||
IDMap.set(className, nextNumber); | ||
return `__${className}${nextNumber}`; | ||
} | ||
/** | ||
* @private | ||
*/ | ||
static _getSlotName(child) { | ||
@@ -681,2 +702,6 @@ // Text nodes can only go to the default slot | ||
_shouldUpdateFragment() { | ||
return this.constructor._needsStaticArea() && this.staticAreaItem.isRendered(); | ||
} | ||
/** | ||
@@ -706,2 +731,3 @@ * @private | ||
const defaultState = {}; | ||
const slotsAreManaged = MetadataClass.slotsAreManaged(); | ||
@@ -732,6 +758,8 @@ // Initialize properties | ||
// Initialize slots | ||
const slots = MetadataClass.getSlots(); | ||
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line | ||
const propertyName = slotData.propertyName || slotName; | ||
defaultState[propertyName] = []; | ||
if (slotsAreManaged) { | ||
const slots = MetadataClass.getSlots(); | ||
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line | ||
const propertyName = slotData.propertyName || slotName; | ||
defaultState[propertyName] = []; | ||
} | ||
} | ||
@@ -748,2 +776,3 @@ | ||
const proto = this.prototype; | ||
const slotsAreManaged = this.getMetadata().slotsAreManaged(); | ||
@@ -757,6 +786,18 @@ // Properties | ||
if (propData.type === "boolean" && propData.defaultValue) { | ||
if (propData.type === Boolean && propData.defaultValue) { | ||
throw new Error(`Cannot set a default value for property "${prop}". All booleans are false by default.`); | ||
} | ||
if (propData.type === Array) { | ||
throw new Error(`Wrong type for property "${prop}". Properties cannot be of type Array - use "multiple: true" and set "type" to the single value type, such as "String", "Object", etc...`); | ||
} | ||
if (propData.type === Object && propData.defaultValue) { | ||
throw new Error(`Cannot set a default value for property "${prop}". All properties of type "Object" are empty objects by default.`); | ||
} | ||
if (propData.multiple && propData.defaultValue) { | ||
throw new Error(`Cannot set a default value for property "${prop}". All multiple properties are empty arrays by default.`); | ||
} | ||
Object.defineProperty(proto, prop, { | ||
@@ -795,20 +836,22 @@ get() { | ||
// Slots | ||
const slots = this.getMetadata().getSlots(); | ||
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line | ||
if (!isValidPropertyName(slotName)) { | ||
throw new Error(`"${slotName}" is not a valid property name. Use a name that does not collide with DOM APIs`); | ||
if (slotsAreManaged) { | ||
const slots = this.getMetadata().getSlots(); | ||
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line | ||
if (!isValidPropertyName(slotName)) { | ||
throw new Error(`"${slotName}" is not a valid property name. Use a name that does not collide with DOM APIs`); | ||
} | ||
const propertyName = slotData.propertyName || slotName; | ||
Object.defineProperty(proto, propertyName, { | ||
get() { | ||
if (this._state[propertyName] !== undefined) { | ||
return this._state[propertyName]; | ||
} | ||
return []; | ||
}, | ||
set() { | ||
throw new Error("Cannot set slots directly, use the DOM APIs"); | ||
}, | ||
}); | ||
} | ||
const propertyName = slotData.propertyName || slotName; | ||
Object.defineProperty(proto, propertyName, { | ||
get() { | ||
if (this._state[propertyName] !== undefined) { | ||
return this._state[propertyName]; | ||
} | ||
return []; | ||
}, | ||
set() { | ||
throw new Error("Cannot set slots directly, use the DOM APIs"); | ||
}, | ||
}); | ||
} | ||
@@ -834,2 +877,10 @@ } | ||
/** | ||
* Returns the Static Area CSS for this UI5 Web Component Class | ||
* @protected | ||
*/ | ||
static get staticAreaStyles() { | ||
return ""; | ||
} | ||
/** | ||
* Registers a UI5 Web Component in the browser window object | ||
@@ -841,5 +892,10 @@ * @public | ||
await boot(); | ||
if (this.onDefine) { | ||
await this.onDefine(); | ||
} | ||
const tag = this.getMetadata().getTag(); | ||
const definedLocally = DefinitionsSet.has(tag); | ||
const definedLocally = isTagRegistered(tag); | ||
const definedGlobally = customElements.get(tag); | ||
@@ -851,3 +907,3 @@ | ||
this._generateAccessors(); | ||
DefinitionsSet.add(tag); | ||
registerTag(tag); | ||
window.customElements.define(tag, this); | ||
@@ -854,0 +910,0 @@ } |
@@ -81,2 +81,11 @@ import DataType from "./types/DataType.js"; | ||
/** | ||
* Determines whether this UI5 Element has a default slot of type Node, therefore can slot text | ||
* @returns {boolean} | ||
*/ | ||
canSlotText() { | ||
const defaultSlot = this.getSlots().default; | ||
return defaultSlot && defaultSlot.type === Node; | ||
} | ||
/** | ||
* Determines whether this UI5 Element supports any slots | ||
@@ -90,2 +99,18 @@ * @public | ||
/** | ||
* Determines whether this UI5 Element supports any slots with "individualSlots: true" | ||
* @public | ||
*/ | ||
hasIndividualSlots() { | ||
return this.slotsAreManaged() && Object.entries(this.getSlots()).some(([_slotName, slotData]) => slotData.individualSlots); | ||
} | ||
/** | ||
* Determines whether this UI5 Element needs to invalidate if children are added/removed/changed | ||
* @public | ||
*/ | ||
slotsAreManaged() { | ||
return !!this.metadata.managedSlots; | ||
} | ||
/** | ||
* Returns an object with key-value pairs of properties and their metadata definitions | ||
@@ -92,0 +117,0 @@ * @public |
@@ -0,1 +1,3 @@ | ||
import { DEFAULT_LANGUAGE } from "../generated/AssetParameters.js"; | ||
export default () => { | ||
@@ -10,3 +12,3 @@ const browserLanguages = navigator.languages; | ||
return rawLocale || "en"; | ||
return rawLocale || DEFAULT_LANGUAGE; | ||
}; |
@@ -0,4 +1,7 @@ | ||
// Note: disabled is present in IE so we explicitly allow it here. | ||
// Others, such as ariaLabel, we explicitly override, so valid too | ||
const whitelist = ["disabled", "ariaLabel"]; | ||
/** | ||
* Checks whether a property name is valid (does not collide with existing DOM API properties) | ||
* Note: disabled is present in IE so we explicitly allow it here. | ||
* | ||
@@ -9,3 +12,3 @@ * @param name | ||
const isValidPropertyName = name => { | ||
if (name === "disabled") { | ||
if (whitelist.includes(name)) { | ||
return true; | ||
@@ -12,0 +15,0 @@ } |
@@ -1,5 +0,20 @@ | ||
const kebabToCamelCase = string => toCamelCase(string.split("-")); | ||
const kebabToCamelMap = new Map(); | ||
const camelToKebabMap = new Map(); | ||
const camelToKebabCase = string => string.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); | ||
const kebabToCamelCase = string => { | ||
if (!kebabToCamelMap.has(string)) { | ||
const result = toCamelCase(string.split("-")); | ||
kebabToCamelMap.set(string, result); | ||
} | ||
return kebabToCamelMap.get(string); | ||
}; | ||
const camelToKebabCase = string => { | ||
if (!camelToKebabMap.has(string)) { | ||
const result = string.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); | ||
camelToKebabMap.set(string, result); | ||
} | ||
return camelToKebabMap.get(string); | ||
}; | ||
const toCamelCase = parts => { | ||
@@ -6,0 +21,0 @@ return parts.map((string, index) => { |
@@ -1,2 +0,1 @@ | ||
import isNodeTabbable from "./isNodeTabbable.js"; | ||
@@ -3,0 +2,0 @@ |
@@ -0,8 +1,13 @@ | ||
const path = require("path"); | ||
const resolve = require("resolve"); | ||
const serveConfig = `../tools/components-package/serve.json`; | ||
const port = `9191`; | ||
const assetParametersScript = resolve.sync("@ui5/webcomponents-base/lib/generate-asset-parameters/index.js"); | ||
const scripts = { | ||
clean: "rimraf dist", | ||
lint: "eslint . --config config/.eslintrc.js", | ||
prepare: "nps clean copy", | ||
prepare: "nps clean copy generateAssetParameters", | ||
build: { | ||
@@ -13,4 +18,3 @@ default: "nps lint prepare build.bundle", | ||
copy: { | ||
default: "nps copy.cldr copy.src copy.test copy.webcomponents-polyfill", | ||
cldr: 'copy-and-watch "../../node_modules/@ui5/webcomponents-utils/dist/**/cldr/*.json" dist/generated/assets/cldr/', | ||
default: "nps copy.src copy.test copy.webcomponents-polyfill", | ||
src: "copy-and-watch \"src/**/*.js\" dist/", | ||
@@ -20,2 +24,3 @@ test: "copy-and-watch \"test/**/*.*\" dist/test-resources", | ||
}, | ||
generateAssetParameters: `node "${assetParametersScript}"`, | ||
watch: { | ||
@@ -22,0 +27,0 @@ default: 'concurrently "nps watch.test" "nps watch.src" "nps watch.bundle"', |
{ | ||
"name": "@ui5/webcomponents-base", | ||
"version": "0.0.0-389bdbabc", | ||
"version": "0.0.0-39bd3067f", | ||
"description": "UI5 Web Components: webcomponents.base", | ||
@@ -23,6 +23,6 @@ "author": "SAP SE (https://www.sap.com)", | ||
"build": "nps build", | ||
"test": "nps test" | ||
"test": "nps test", | ||
"prepublishOnly": "npm run clean && npm run build" | ||
}, | ||
"dependencies": { | ||
"@ui5/webcomponents-utils": "0.0.0-389bdbabc", | ||
"css-vars-ponyfill": "^2.1.2", | ||
@@ -34,3 +34,3 @@ "lit-html": "^1.0.0", | ||
"devDependencies": { | ||
"@ui5/webcomponents-tools": "0.0.0-389bdbabc", | ||
"@ui5/webcomponents-tools": "0.0.0-39bd3067f", | ||
"array-uniq": "^2.0.0", | ||
@@ -37,0 +37,0 @@ "copy-and-watch": "^0.1.4", |
@@ -1,6 +0,6 @@ | ||
import "../shims/jquery-shim.js"; | ||
import "../shims/Core-shim.js"; | ||
import { getLanguage } from "../LocaleProvider.js"; | ||
import getLocale from "../locale/getLocale.js"; | ||
import { fetchJsonOnce } from "../util/FetchHelper.js"; | ||
import { normalizeLocale, nextFallbackLocale } from "../util/normalizeLocale.js"; | ||
import normalizeLocale from "../locale/normalizeLocale.js"; | ||
import nextFallbackLocale from "../locale/nextFallbackLocale.js"; | ||
import { DEFAULT_LANGUAGE } from "../generated/AssetParameters.js"; | ||
@@ -52,3 +52,3 @@ const bundleData = new Map(); | ||
const language = getLanguage(); | ||
const language = getLocale().getLanguage(); | ||
@@ -60,2 +60,6 @@ let localeId = normalizeLocale(language); | ||
if (localeId === DEFAULT_LANGUAGE) { | ||
return; | ||
} | ||
const bundleURL = bundlesForPackage[localeId]; | ||
@@ -65,3 +69,3 @@ | ||
setI18nBundleData(packageName, bundleURL); | ||
return bundleURL; | ||
return; | ||
} | ||
@@ -68,0 +72,0 @@ |
@@ -1,6 +0,6 @@ | ||
import { registerModuleContent } from "../ResourceLoaderOverrides.js"; | ||
import { fetchJsonOnce } from "../util/FetchHelper.js"; | ||
import { getFeature } from "../FeaturesRegistry.js"; | ||
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from "../generated/AssetParameters.js"; | ||
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 resources = new Map(); | ||
const cldrData = {}; | ||
@@ -38,9 +38,9 @@ const cldrUrls = {}; | ||
let localeId = `${language}_${region}`; | ||
if (!supportedLocales.includes(localeId)) { | ||
if (!SUPPORTED_LOCALES.includes(localeId)) { | ||
// fallback to language only | ||
localeId = language; | ||
} | ||
if (!supportedLocales.includes(localeId)) { | ||
if (!SUPPORTED_LOCALES.includes(localeId)) { | ||
// fallback to english | ||
localeId = "en"; | ||
localeId = DEFAULT_LOCALE; | ||
} | ||
@@ -57,3 +57,3 @@ | ||
const missingLocales = supportedLocales.filter(locale => !cldrData[locale] && !cldrUrls[locale]); | ||
const missingLocales = SUPPORTED_LOCALES.filter(locale => !cldrData[locale] && !cldrUrls[locale]); | ||
missingLocales.forEach(locale => { | ||
@@ -64,2 +64,20 @@ cldrUrls[locale] = cldrMappingFn(locale); | ||
const registerModuleContent = (moduleName, content) => { | ||
resources.set(moduleName, content); | ||
}; | ||
const getModuleContent = moduleName => { | ||
const moduleContent = resources.get(moduleName); | ||
if (moduleContent) { | ||
return moduleContent; | ||
} | ||
const missingModule = moduleName.match(/sap\/ui\/core\/cldr\/(\w+)\.json/); | ||
if (missingModule) { | ||
throw new Error(`CLDR data for locale ${missingModule[1]} is not loaded!`); | ||
} | ||
throw new Error(`Unknown module ${moduleName}`); | ||
}; | ||
const fetchCldr = async (language, region, script) => { | ||
@@ -69,5 +87,10 @@ resolveMissingMappings(); | ||
const cldrObj = cldrData[localeId]; | ||
let cldrObj = cldrData[localeId]; | ||
const url = cldrUrls[localeId]; | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
if (!cldrObj && OpenUI5Support) { | ||
cldrObj = OpenUI5Support.getLocaleDataObject(); | ||
} | ||
if (cldrObj) { | ||
@@ -104,3 +127,4 @@ // inlined from build or fetched independently | ||
getCldrData, | ||
getModuleContent, | ||
_registerMappingFunction, | ||
}; |
@@ -1,2 +0,4 @@ | ||
import { fetchJsonOnce } from "../util/FetchHelper.js"; | ||
import { fetchJsonOnce, fetchTextOnce } from "../util/FetchHelper.js"; | ||
import { DEFAULT_THEME } from "../generated/AssetParameters.js"; | ||
import getFileExtension from "../util/getFileExtension.js"; | ||
@@ -18,3 +20,5 @@ const themeURLs = new Map(); | ||
* registerThemeProperties("my-package", "my_theme", {"_": ":root{--var1: red;}"}); | ||
* 3) Pass a URL to a JSON file, containing the CSS Vars in its "_" property. Will be fetched on demand, not upon registration. | ||
* 3) Pass a URL to a CSS file, containing the CSS Vars. Will be fetched on demand, not upon registration. | ||
* registerThemeProperties("my-package", "my_theme", "http://url/to/my/theme.css"); | ||
* 4) Pass a URL to a JSON file, containing the CSS Vars in its "_" property. Will be fetched on demand, not upon registration. | ||
* registerThemeProperties("my-package", "my_theme", "http://url/to/my/theme.json"); | ||
@@ -25,3 +29,3 @@ * | ||
* @param themeName - the theme which the CSS Vars implement | ||
* @param style - can be one of three options: a string, an object with a "_" property or a URL to a JSON file with a "_" property | ||
* @param style - can be one of four options: a string, an object with a "_" property, URL to a CSS file, or URL to a JSON file with a "_" property | ||
*/ | ||
@@ -51,9 +55,11 @@ const registerThemeProperties = (packageName, themeName, style) => { | ||
const regThemesStr = [...registeredThemes.values()].join(", "); | ||
console.warn(`You have requested a non-registered theme - falling back to sap_fiori_3. Registered themes are: ${regThemesStr}`); /* eslint-disable-line */ | ||
return themeStyles.get(`${packageName}_sap_fiori_3`); | ||
console.warn(`You have requested a non-registered theme - falling back to ${DEFAULT_THEME}. Registered themes are: ${regThemesStr}`); /* eslint-disable-line */ | ||
return themeStyles.get(`${packageName}_${DEFAULT_THEME}`); | ||
} | ||
const data = await fetchThemeProperties(packageName, themeName); | ||
themeStyles.set(`${packageName}_${themeName}`, data._); | ||
return data._; | ||
const themeProps = data._ || data; | ||
themeStyles.set(`${packageName}_${themeName}`, themeProps); | ||
return themeProps; | ||
}; | ||
@@ -67,3 +73,4 @@ | ||
} | ||
return fetchJsonOnce(url); | ||
return getFileExtension(url) === ".css" ? fetchTextOnce(url) : fetchJsonOnce(url); | ||
}; | ||
@@ -75,2 +82,6 @@ | ||
const isThemeRegistered = theme => { | ||
return registeredThemes.has(theme); | ||
}; | ||
export { | ||
@@ -80,2 +91,3 @@ registerThemeProperties, | ||
getRegisteredPackages, | ||
isThemeRegistered, | ||
}; |
import whenDOMReady from "./util/whenDOMReady.js"; | ||
import insertFontFace from "./FontFace.js"; | ||
import { getTheme } from "./config/Theme.js"; | ||
import { _applyTheme } from "./Theming.js"; | ||
import applyTheme from "./theming/applyTheme.js"; | ||
import whenPolyfillLoaded from "./compatibility/whenPolyfillLoaded.js"; | ||
import { getFeature } from "./FeaturesRegistry.js"; | ||
@@ -15,4 +16,10 @@ let bootPromise; | ||
bootPromise = new Promise(async resolve => { | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
if (OpenUI5Support) { | ||
await OpenUI5Support.init(); | ||
} | ||
await whenDOMReady(); | ||
await _applyTheme(getTheme()); | ||
await applyTheme(getTheme()); | ||
OpenUI5Support && OpenUI5Support.attachListeners(); | ||
insertFontFace(); | ||
@@ -19,0 +26,0 @@ await whenPolyfillLoaded(); |
import { getAnimationMode as getConfiguredAnimationMode } from "../InitialConfiguration.js"; | ||
const animationMode = getConfiguredAnimationMode(); | ||
let animationMode; | ||
const getAnimationMode = () => { | ||
if (animationMode === undefined) { | ||
animationMode = getConfiguredAnimationMode(); | ||
} | ||
return animationMode; | ||
@@ -7,0 +11,0 @@ }; |
@@ -1,13 +0,13 @@ | ||
import CalendarType from "@ui5/webcomponents-utils/dist/sap/ui/core/CalendarType.js"; | ||
import CalendarType from "../types/CalendarType.js"; | ||
import { getCalendarType as getConfiguredCalendarType } from "../InitialConfiguration.js"; | ||
const calendarType = getConfiguredCalendarType(); | ||
let calendarType; | ||
const getCalendarType = () => { | ||
if (calendarType) { | ||
const type = Object.keys(CalendarType).find(calType => calType === calendarType); | ||
if (calendarType === undefined) { | ||
calendarType = getConfiguredCalendarType(); | ||
} | ||
if (type) { | ||
return type; | ||
} | ||
if (CalendarType.isValid(calendarType)) { | ||
return calendarType; | ||
} | ||
@@ -14,0 +14,0 @@ |
import { getFormatSettings } from "../InitialConfiguration.js"; | ||
const formatSettings = getFormatSettings(); | ||
let formatSettings; | ||
const getFirstDayOfWeek = () => { | ||
if (formatSettings === undefined) { | ||
formatSettings = getFormatSettings(); | ||
} | ||
return formatSettings.firstDayOfWeek; | ||
@@ -7,0 +11,0 @@ }; |
import { getLanguage as getConfiguredLanguage } from "../InitialConfiguration.js"; | ||
const language = getConfiguredLanguage(); | ||
let language; | ||
const getLanguage = () => { | ||
if (language === undefined) { | ||
language = getConfiguredLanguage(); | ||
} | ||
return language; | ||
@@ -7,0 +10,0 @@ }; |
@@ -12,9 +12,14 @@ import { getNoConflict as getConfiguredNoConflict } from "../InitialConfiguration.js"; | ||
let noConflict = getConfiguredNoConflict(); | ||
let noConflict; | ||
const shouldNotFireOriginalEvent = eventName => { | ||
return !(noConflict.events && noConflict.events.includes && noConflict.events.includes(eventName)); | ||
const nc = getNoConflict(); | ||
return !(nc.events && nc.events.includes && nc.events.includes(eventName)); | ||
}; | ||
const getNoConflict = () => { | ||
if (noConflict === undefined) { | ||
noConflict = getConfiguredNoConflict(); | ||
} | ||
return noConflict; | ||
@@ -24,2 +29,4 @@ }; | ||
const skipOriginalEvent = eventName => { | ||
const nc = getNoConflict(); | ||
// Always fire these events | ||
@@ -31,3 +38,3 @@ if (shouldFireOriginalEvent(eventName)) { | ||
// Read from the configuration | ||
if (noConflict === true) { | ||
if (nc === true) { | ||
return true; | ||
@@ -34,0 +41,0 @@ } |
import { getTheme as getConfiguredTheme } from "../InitialConfiguration.js"; | ||
import { _applyTheme } from "../Theming.js"; | ||
import applyTheme from "../theming/applyTheme.js"; | ||
let theme = getConfiguredTheme(); | ||
let theme; | ||
const getTheme = () => { | ||
if (theme === undefined) { | ||
theme = getConfiguredTheme(); | ||
} | ||
return theme; | ||
@@ -18,3 +22,3 @@ }; | ||
// Update CSS Custom Properties | ||
await _applyTheme(theme); | ||
await applyTheme(theme); | ||
}; | ||
@@ -21,0 +25,0 @@ |
@@ -9,3 +9,3 @@ import RenderScheduler from "../RenderScheduler.js"; | ||
isEnd, | ||
} from "../events/PseudoEvents.js"; | ||
} from "../Keys.js"; | ||
@@ -25,3 +25,4 @@ import EventProvider from "../EventProvider.js"; | ||
this.behavior = options.behavior || ItemNavigationBehavior.Static; | ||
this.hasNextPage = true; // used in Paging mode and controlled from the rootWebComponent | ||
this.hasPrevPage = true; // used in Paging mode and controlled from the rootWebComponent | ||
const navigationMode = options.navigationMode; | ||
@@ -218,4 +219,6 @@ const autoNavigation = !navigationMode || navigationMode === NavigationMode.Auto; | ||
const items = this._getItems(); | ||
const rowIndex = this.currentIndex - items.length; | ||
const offset = this.currentIndex - items.length; | ||
if (this.behavior === ItemNavigationBehavior.Cyclic) { | ||
this.currentIndex = 0; | ||
return; | ||
@@ -226,7 +229,7 @@ } | ||
this._handleNextPage(); | ||
} else { | ||
this.currentIndex = items.length - 1; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { | ||
start: false, end: true, offset: this.currentIndex, rowIndex, | ||
}); | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: false, end: true, offset }); | ||
} | ||
@@ -236,6 +239,6 @@ | ||
const items = this._getItems(); | ||
const rowIndex = this.currentIndex + this.rowSize; | ||
const offset = this.currentIndex + this.rowSize; | ||
if (this.behavior === ItemNavigationBehavior.Cyclic) { | ||
this.currentIndex = items.length + this.currentIndex; | ||
this.currentIndex = items.length - 1; | ||
return; | ||
@@ -246,7 +249,7 @@ } | ||
this._handlePrevPage(); | ||
} else { | ||
this.currentIndex = 0; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { | ||
start: true, end: false, offset: this.currentIndex, rowIndex, | ||
}); | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: true, end: false, offset }); | ||
} | ||
@@ -267,2 +270,3 @@ | ||
this.fireEvent(ItemNavigation.PAGE_TOP); | ||
const items = this._getItems(); | ||
@@ -272,3 +276,3 @@ if (!this.hasPrevPage) { | ||
} else { | ||
this.currentIndex = 41; | ||
this.currentIndex = (this.pageSize || items.length) - 1; | ||
} | ||
@@ -275,0 +279,0 @@ } |
@@ -0,1 +1,2 @@ | ||
import { isPhone } from "../Device.js"; | ||
import EventProvider from "../EventProvider.js"; | ||
@@ -5,2 +6,3 @@ import scroll from "../animations/scroll.js"; | ||
const scrollEventName = "scroll"; | ||
const touchEndEventName = isPhone() ? "touchend" : "mouseup"; | ||
@@ -10,4 +12,26 @@ class ScrollEnablement extends EventProvider { | ||
super(); | ||
containerComponent.addEventListener("touchstart", this.ontouchstart.bind(this), { passive: true }); | ||
containerComponent.addEventListener("touchmove", this.ontouchmove.bind(this), { passive: true }); | ||
this.containerComponent = containerComponent; | ||
this.mouseMove = this.ontouchmove.bind(this); | ||
this.mouseUp = this.ontouchend.bind(this); | ||
this.touchStart = this.ontouchstart.bind(this); | ||
this.isPhone = isPhone(); | ||
// On Android devices touchmove is thrown one more time than neccessary (together with touchend) | ||
// so we have to cache the previus coordinates in order to provide correct parameters in the | ||
// event for Android | ||
this.cachedValue = {}; | ||
// In components like Carousel you need to know if the user has clicked on something or swiped | ||
// in order to throw the needed event or not | ||
this.startX = 0; | ||
this.startY = 0; | ||
if (this.isPhone) { | ||
containerComponent.addEventListener("touchstart", this.touchStart, { passive: true }); | ||
containerComponent.addEventListener("touchmove", this.mouseMove, { passive: true }); | ||
containerComponent.addEventListener("touchend", this.mouseUp, { passive: true }); | ||
} else { | ||
containerComponent.addEventListener("mousedown", this.touchStart, { passive: true }); | ||
} | ||
} | ||
@@ -46,4 +70,4 @@ | ||
const rect = this._container.getBoundingClientRect(); | ||
const x = touch.clientX; | ||
const y = touch.clientY; | ||
const x = this.isPhone ? touch.clientX : touch.x; | ||
const y = this.isPhone ? touch.clientY : touch.y; | ||
@@ -55,7 +79,17 @@ return x >= rect.left && x <= rect.right | ||
ontouchstart(event) { | ||
const touch = event.touches[0]; | ||
this._prevDragX = touch.pageX; | ||
this._prevDragY = touch.pageY; | ||
const touch = this.isPhone ? event.touches[0] : null; | ||
this._canScroll = this._isTouchInside(touch); | ||
if (!this.isPhone) { | ||
document.addEventListener("mouseup", this.mouseUp, { passive: true }); | ||
document.addEventListener("mousemove", this.mouseMove, { passive: true }); | ||
} else { | ||
// Needed only on mobile | ||
this.startX = touch.pageX; | ||
this.startY = touch.pageY; | ||
} | ||
this._prevDragX = this.isPhone ? touch.pageX : event.x; | ||
this._prevDragY = this.isPhone ? touch.pageY : event.y; | ||
this._canScroll = this._isTouchInside(this.isPhone ? touch : event); | ||
} | ||
@@ -69,6 +103,6 @@ | ||
const container = this._container; | ||
const touch = event.touches[0]; | ||
const touch = this.isPhone ? event.touches[0] : null; | ||
const dragX = touch.pageX; | ||
const dragY = touch.pageY; | ||
const dragX = this.isPhone ? touch.pageX : event.x; | ||
const dragY = this.isPhone ? touch.pageY : event.y; | ||
@@ -78,9 +112,54 @@ container.scrollLeft += this._prevDragX - dragX; | ||
this.fireEvent(scrollEventName, {}); | ||
this.fireEvent(scrollEventName, { | ||
isLeft: dragX > this._prevDragX, | ||
isRight: dragX < this._prevDragX, | ||
}); | ||
this.cachedValue.dragX = this._prevDragX; | ||
this.cachedValue.dragY = this._prevDragY; | ||
this._prevDragX = dragX; | ||
this._prevDragY = dragY; | ||
} | ||
ontouchend(event) { | ||
if (this.isPhone) { | ||
const deltaX = Math.abs(event.changedTouches[0].pageX - this.startX); | ||
const deltaY = Math.abs(event.changedTouches[0].pageY - this.startY); | ||
if (deltaX < 10 && deltaY < 10) { | ||
return; | ||
} | ||
} | ||
if (!this._canScroll) { | ||
return; | ||
} | ||
const container = this._container; | ||
const dragX = this.isPhone ? event.changedTouches[0].pageX : event.x; | ||
const dragY = this.isPhone ? event.changedTouches[0].pageY : event.y; | ||
container.scrollLeft += this._prevDragX - dragX; | ||
container.scrollTop += this._prevDragY - dragY; | ||
const useCachedValues = dragX === this._prevDragX; | ||
const _dragX = useCachedValues ? this.cachedValue.dragX : dragX; | ||
// const _dragY = useCachedValues ? this.cachedValue.dragY : dragY; add if needed | ||
this.fireEvent(touchEndEventName, { | ||
isLeft: _dragX < this._prevDragX, | ||
isRight: _dragX > this._prevDragX, | ||
}); | ||
this._prevDragX = dragX; | ||
this._prevDragY = dragY; | ||
if (!this.isPhone) { | ||
document.removeEventListener("mousemove", this.mouseMove, { passive: true }); | ||
document.removeEventListener("mouseup", this.mouseUp); | ||
} | ||
} | ||
} | ||
export default ScrollEnablement; |
@@ -5,3 +5,3 @@ // CSS Custom Properties | ||
// String | ||
import "@ui5/webcomponents-utils/dist/sap/ui/thirdparty/es6-string-methods.js"; | ||
import "../../thirdparty/es6-string-methods.js"; | ||
@@ -8,0 +8,0 @@ // Object |
@@ -5,2 +5,3 @@ /** | ||
import createStyleInHead from "./util/createStyleInHead.js"; | ||
import { getFeature } from "./FeaturesRegistry.js"; | ||
@@ -64,2 +65,8 @@ /* CDN Locations */ | ||
// If OpenUI5 is found, let it set the font | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
if (OpenUI5Support && OpenUI5Support.isLoaded()) { | ||
return; | ||
} | ||
createStyleInHead(fontFaceCSS, { "data-ui5-font-face": "" }); | ||
@@ -66,0 +73,0 @@ }; |
@@ -15,9 +15,7 @@ import { fetchI18nBundle, getI18nBundleData } from "./asset-registries/i18n.js"; | ||
} | ||
const bundle = getI18nBundleData(this.packageName); | ||
const messageText = bundle && bundle[textObj.key] ? bundle[textObj.key] : textObj.defaultText; | ||
if (!bundle || !bundle[textObj.key]) { | ||
return formatMessage(textObj.defaultText, params); // Fallback to "en" | ||
} | ||
return formatMessage(bundle[textObj.key], params); | ||
return formatMessage(messageText, params); | ||
} | ||
@@ -31,7 +29,7 @@ } | ||
const i18nBunle = new I18nBundle(packageName); | ||
I18nBundleInstances.set(packageName, i18nBunle); | ||
return i18nBunle; | ||
const i18nBundle = new I18nBundle(packageName); | ||
I18nBundleInstances.set(packageName, i18nBundle); | ||
return i18nBundle; | ||
}; | ||
export { fetchI18nBundle, getI18nBundle }; |
@@ -0,6 +1,10 @@ | ||
import merge from "./thirdparty/merge.js"; | ||
import { getFeature } from "./FeaturesRegistry.js"; | ||
import { DEFAULT_THEME } from "./generated/AssetParameters.js"; | ||
let initialized = false; | ||
const initialConfig = { | ||
let initialConfig = { | ||
animationMode: "full", | ||
theme: "sap_fiori_3", | ||
theme: DEFAULT_THEME, | ||
rtl: null, | ||
@@ -53,4 +57,2 @@ language: null, | ||
let runtimeConfig = {}; | ||
const parseConfigurationScript = () => { | ||
@@ -69,3 +71,3 @@ const configScript = document.querySelector("[data-ui5-config]") || document.querySelector("[data-id='sap-ui-config']"); // for backward compatibility | ||
if (configJSON) { | ||
runtimeConfig = Object.assign({}, configJSON); | ||
initialConfig = merge(initialConfig, configJSON); | ||
} | ||
@@ -91,12 +93,17 @@ } | ||
runtimeConfig[param] = value; | ||
initialConfig[param] = value; | ||
}); | ||
}; | ||
const applyConfigurations = () => { | ||
Object.keys(runtimeConfig).forEach(key => { | ||
initialConfig[key] = runtimeConfig[key]; | ||
}); | ||
const applyOpenUI5Configuration = () => { | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
if (!OpenUI5Support || !OpenUI5Support.isLoaded()) { | ||
return; | ||
} | ||
const OpenUI5Config = OpenUI5Support.getConfigurationSettingsObject(); | ||
initialConfig = merge(initialConfig, OpenUI5Config); | ||
}; | ||
const initConfiguration = () => { | ||
@@ -107,6 +114,11 @@ if (initialized) { | ||
// 1. Lowest priority - configuration script | ||
parseConfigurationScript(); | ||
// 2. URL parameters overwrite configuration script parameters | ||
parseURLParameters(); | ||
applyConfigurations(); | ||
// 3. If OpenUI5 is detected, it has the highest priority | ||
applyOpenUI5Configuration(); | ||
initialized = true; | ||
@@ -113,0 +125,0 @@ }; |
import RenderQueue from "./RenderQueue.js"; | ||
import { getAllRegisteredTags } from "./CustomElementsRegistry.js"; | ||
@@ -121,29 +122,9 @@ const MAX_RERENDER_COUNT = 10; | ||
static getNotDefinedComponents() { | ||
return Array.from(document.querySelectorAll("*")).filter(el => el.localName.startsWith("ui5-") && !el.isUI5Element); | ||
static whenAllCustomElementsAreDefined() { | ||
const definedPromises = getAllRegisteredTags().map(tag => customElements.whenDefined(tag)); | ||
return Promise.all(definedPromises); | ||
} | ||
/** | ||
* return a promise that will be resolved once all ui5 webcomponents on the page have their shadow root ready | ||
*/ | ||
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 are: " + [...stillUndefined].map(el => el.localName).join(" ; ")); | ||
} | ||
return Promise.resolve(); | ||
} | ||
static async whenFinished() { | ||
await RenderScheduler.whenShadowDOMReady(); | ||
await RenderScheduler.whenAllCustomElementsAreDefined(); | ||
await RenderScheduler.whenDOMUpdated(); | ||
@@ -150,0 +131,0 @@ } |
import { getStaticAreaInstance, removeStaticArea } from "./StaticArea.js"; | ||
import RenderScheduler from "./RenderScheduler.js"; | ||
@@ -12,4 +13,9 @@ /** | ||
this.ui5ElementContext = _ui5ElementContext; | ||
this._rendered = false; | ||
} | ||
isRendered() { | ||
return this._rendered; | ||
} | ||
/** | ||
@@ -20,3 +26,3 @@ * @protected | ||
const renderResult = this.ui5ElementContext.constructor.staticAreaTemplate(this.ui5ElementContext), | ||
stylesToAdd = this.ui5ElementContext.constructor.staticAreaStyles || false; | ||
stylesToAdd = window.ShadyDOM ? false : this.ui5ElementContext.constructor.staticAreaStyles; | ||
@@ -31,2 +37,3 @@ if (!this.staticAreaItemDomRef) { | ||
getStaticAreaInstance().appendChild(this.staticAreaItemDomRef); | ||
this._rendered = true; | ||
} | ||
@@ -41,2 +48,6 @@ | ||
_removeFragmentFromStaticArea() { | ||
if (!this.staticAreaItemDomRef) { | ||
return; | ||
} | ||
const staticArea = getStaticAreaInstance(); | ||
@@ -56,5 +67,26 @@ | ||
* @protected | ||
*/ | ||
_updateContentDensity(isCompact) { | ||
if (!this.staticAreaItemDomRef) { | ||
return; | ||
} | ||
if (isCompact) { | ||
this.staticAreaItemDomRef.classList.add("sapUiSizeCompact"); | ||
this.staticAreaItemDomRef.classList.add("ui5-content-density-compact"); | ||
} else { | ||
this.staticAreaItemDomRef.classList.remove("sapUiSizeCompact"); | ||
this.staticAreaItemDomRef.classList.remove("ui5-content-density-compact"); | ||
} | ||
} | ||
/** | ||
* @protected | ||
* Returns reference to the DOM element where the current fragment is added. | ||
*/ | ||
getDomRef() { | ||
async getDomRef() { | ||
if (!this._rendered || !this.staticAreaItemDomRef) { | ||
this._updateFragment(); | ||
} | ||
await RenderScheduler.whenDOMUpdated(); // Wait for the content of the ui5-static-area-item to be rendered | ||
return this.staticAreaItemDomRef.shadowRoot; | ||
@@ -61,0 +93,0 @@ } |
const registry = new Map(); | ||
const iconCollectionPromises = new Map(); | ||
const ICON_NOT_FOUND = "ICON_NOT_FOUND"; | ||
const DEFAULT_COLLECTION = "SAP-icons"; | ||
@@ -30,6 +31,11 @@ | ||
if (!iconCollectionPromises.has(collection)) { | ||
iconCollectionPromises.set(collection, Promise.reject()); | ||
iconCollectionPromises.set(collection, Promise.resolve(ICON_NOT_FOUND)); | ||
} | ||
await iconCollectionPromises.get(collection); | ||
const iconData = await iconCollectionPromises.get(collection); | ||
if (iconData === ICON_NOT_FOUND) { | ||
return iconData; | ||
} | ||
return registry.get(key); | ||
@@ -36,0 +42,0 @@ }; |
@@ -1,45 +0,3 @@ | ||
import { addCustomCSS, getCustomCSS } from "./theming/CustomStyle.js"; | ||
import { getThemeProperties, getRegisteredPackages } from "./asset-registries/Themes.js"; | ||
import { injectThemeProperties } from "./theming/StyleInjection.js"; | ||
import { addCustomCSS } from "./theming/CustomStyle.js"; | ||
const themeChangeCallbacks = []; | ||
const attachThemeChange = function attachThemeChange(callback) { | ||
if (themeChangeCallbacks.indexOf(callback) === -1) { | ||
themeChangeCallbacks.push(callback); | ||
} | ||
}; | ||
const _applyTheme = async theme => { | ||
let cssText = ""; | ||
const registeredPackages = getRegisteredPackages(); | ||
registeredPackages.forEach(async packageName => { | ||
cssText = await getThemeProperties(packageName, theme); | ||
injectThemeProperties(cssText, packageName); | ||
}); | ||
_executeThemeChangeCallbacks(theme); | ||
}; | ||
const _executeThemeChangeCallbacks = theme => { | ||
themeChangeCallbacks.forEach(callback => callback(theme)); | ||
}; | ||
const getEffectiveStyle = ElementClass => { | ||
const tag = ElementClass.getMetadata().getTag(); | ||
const customStyle = getCustomCSS(tag) || ""; | ||
let componentStyles = ElementClass.styles; | ||
if (Array.isArray(componentStyles)) { | ||
componentStyles = componentStyles.join(" "); | ||
} | ||
return `${componentStyles} ${customStyle}`; | ||
}; | ||
export { | ||
attachThemeChange, | ||
_applyTheme, | ||
getEffectiveStyle, | ||
addCustomCSS, | ||
}; | ||
export { addCustomCSS }; // eslint-disable-line |
@@ -11,2 +11,3 @@ import DataType from "./DataType.js"; | ||
Error: "Error", | ||
Information: "Information", | ||
}; | ||
@@ -13,0 +14,0 @@ |
@@ -1,11 +0,13 @@ | ||
import merge from "@ui5/webcomponents-utils/dist/sap/base/util/merge.js"; | ||
import merge from "./thirdparty/merge.js"; | ||
import boot from "./boot.js"; | ||
import { skipOriginalEvent } from "./config/NoConflict.js"; | ||
import DOMObserver from "./compatibility/DOMObserver.js"; | ||
import UI5ElementMetadata from "./UI5ElementMetadata.js"; | ||
import StaticAreaItem from "./StaticAreaItem.js"; | ||
import RenderScheduler from "./RenderScheduler.js"; | ||
import { registerTag, isTagRegistered } from "./CustomElementsRegistry.js"; | ||
import DOMObserver from "./compatibility/DOMObserver.js"; | ||
import { skipOriginalEvent } from "./config/NoConflict.js"; | ||
import getConstructableStyle from "./theming/getConstructableStyle.js"; | ||
import createComponentStyleTag from "./theming/createComponentStyleTag.js"; | ||
import getEffectiveStyle from "./theming/getEffectiveStyle.js"; | ||
import Integer from "./types/Integer.js"; | ||
import RenderScheduler from "./RenderScheduler.js"; | ||
import { getConstructableStyle, createHeadStyle } from "./CSS.js"; | ||
import { getEffectiveStyle } from "./Theming.js"; | ||
import { kebabToCamelCase, camelToKebabCase } from "./util/StringHelper.js"; | ||
@@ -20,7 +22,7 @@ import isValidPropertyName from "./util/isValidPropertyName.js"; | ||
const DefinitionsSet = new Set(); | ||
const IDMap = new Map(); | ||
let autoId = 0; | ||
const elementTimeouts = new Map(); | ||
const GLOBAL_CONTENT_DENSITY_CSS_VAR = "--_ui5_content_density"; | ||
/** | ||
@@ -43,2 +45,3 @@ * Base class for all UI5 Web Components | ||
this._initializeContainers(); | ||
this._upToDate = false; | ||
@@ -52,2 +55,3 @@ let deferredResolve; | ||
this._monitoredChildProps = new Map(); | ||
this._firePropertyChange = false; | ||
} | ||
@@ -59,3 +63,3 @@ | ||
_generateId() { | ||
this._id = this.constructor._nextID(); | ||
this._id = `ui5wc_${++autoId}`; | ||
} | ||
@@ -67,4 +71,7 @@ | ||
_initializeContainers() { | ||
const needsShadowDOM = this.constructor._needsShadowDOM(); | ||
const needsStaticArea = this.constructor._needsStaticArea(); | ||
// Init Shadow Root | ||
if (this.constructor._needsShadowDOM()) { | ||
if (needsShadowDOM) { | ||
this.attachShadow({ mode: "open" }); | ||
@@ -74,3 +81,3 @@ | ||
if (window.ShadyDOM) { | ||
createHeadStyle(this.constructor); | ||
createComponentStyleTag(this.constructor); | ||
} | ||
@@ -86,3 +93,3 @@ | ||
// Init StaticAreaItem only if needed | ||
if (this.constructor._needsStaticArea()) { | ||
if (needsStaticArea) { | ||
this.staticAreaItem = new StaticAreaItem(this); | ||
@@ -97,8 +104,17 @@ } | ||
async connectedCallback() { | ||
const needsShadowDOM = this.constructor._needsShadowDOM(); | ||
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged(); | ||
// Render the Shadow DOM | ||
if (this.constructor._needsShadowDOM()) { | ||
// always register the observer before yielding control to the main thread (await) | ||
this._startObservingDOMChildren(); | ||
if (needsShadowDOM) { | ||
if (slotsAreManaged) { | ||
// always register the observer before yielding control to the main thread (await) | ||
this._startObservingDOMChildren(); | ||
await this._processChildren(); | ||
} | ||
await this._processChildren(); | ||
if (!this.shadowRoot) { // Workaround for Firefox74 bug | ||
await Promise.resolve(); | ||
} | ||
await RenderScheduler.renderImmediately(this); | ||
@@ -110,7 +126,2 @@ this._domRefReadyPromise._deferredResolve(); | ||
} | ||
// Render Fragment if neccessary | ||
if (this.constructor._needsStaticArea()) { | ||
this.staticAreaItem._updateFragment(this); | ||
} | ||
} | ||
@@ -123,4 +134,11 @@ | ||
disconnectedCallback() { | ||
if (this.constructor._needsShadowDOM()) { | ||
this._stopObservingDOMChildren(); | ||
const needsShadowDOM = this.constructor._needsShadowDOM(); | ||
const needsStaticArea = this.constructor._needsStaticArea(); | ||
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged(); | ||
if (needsShadowDOM) { | ||
if (slotsAreManaged) { | ||
this._stopObservingDOMChildren(); | ||
} | ||
if (typeof this.onExitDOM === "function") { | ||
@@ -131,3 +149,3 @@ this.onExitDOM(); | ||
if (this.constructor._needsStaticArea()) { | ||
if (needsStaticArea) { | ||
this.staticAreaItem._removeFragmentFromStaticArea(); | ||
@@ -145,5 +163,7 @@ } | ||
} | ||
const canSlotText = this.constructor.getMetadata().canSlotText(); | ||
const mutationObserverOptions = { | ||
childList: true, | ||
subtree: true, | ||
subtree: canSlotText, | ||
characterData: true, | ||
@@ -177,3 +197,3 @@ }; | ||
const slotsMap = this.constructor.getMetadata().getSlots(); | ||
const canSlotText = slotsMap.default && slotsMap.default.type === Node; | ||
const canSlotText = this.constructor.getMetadata().canSlotText(); | ||
const domChildren = Array.from(canSlotText ? this.childNodes : this.children); | ||
@@ -183,3 +203,3 @@ | ||
for (const [slotName, slotData] of Object.entries(slotsMap)) { // eslint-disable-line | ||
this._clearSlot(slotName); | ||
this._clearSlot(slotName, slotData); | ||
} | ||
@@ -204,5 +224,5 @@ | ||
if (slotData.individualSlots) { | ||
const nextId = (autoIncrementMap.get(slotName) || 0) + 1; | ||
autoIncrementMap.set(slotName, nextId); | ||
child._individualSlot = `${slotName}-${nextId}`; | ||
const nextIndex = (autoIncrementMap.get(slotName) || 0) + 1; | ||
autoIncrementMap.set(slotName, nextIndex); | ||
child._individualSlot = `${slotName}-${nextIndex}`; | ||
} | ||
@@ -231,4 +251,4 @@ | ||
if (child.isUI5Element) { | ||
this._attachChildPropertyUpdated(child, slotData); | ||
if (child.isUI5Element && slotData.listenFor) { | ||
this._attachChildPropertyUpdated(child, slotData.listenFor); | ||
} | ||
@@ -252,3 +272,3 @@ | ||
}); | ||
this._invalidate(); | ||
this._invalidate("slots"); | ||
} | ||
@@ -260,4 +280,3 @@ | ||
*/ | ||
_clearSlot(slotName) { | ||
const slotData = this.constructor.getMetadata().getSlots()[slotName]; | ||
_clearSlot(slotName, slotData) { | ||
const propertyName = slotData.propertyName || slotName; | ||
@@ -355,5 +374,4 @@ | ||
*/ | ||
_attachChildPropertyUpdated(child, propData) { | ||
const listenFor = propData.listenFor, | ||
childMetadata = child.constructor.getMetadata(), | ||
_attachChildPropertyUpdated(child, listenFor) { | ||
const childMetadata = child.constructor.getMetadata(), | ||
slotName = this.constructor._getSlotName(child), // all slotted children have the same configuration | ||
@@ -365,6 +383,2 @@ childProperties = childMetadata.getProperties(); | ||
if (!listenFor) { | ||
return; | ||
} | ||
if (Array.isArray(listenFor)) { | ||
@@ -382,2 +396,3 @@ observedProps = listenFor; | ||
child.addEventListener("_propertyChange", this._invalidateParentOnPropertyUpdate); | ||
child._firePropertyChange = true; | ||
} | ||
@@ -390,2 +405,3 @@ | ||
child.removeEventListener("_propertyChange", this._invalidateParentOnPropertyUpdate); | ||
child._firePropertyChange = false; | ||
} | ||
@@ -399,9 +415,9 @@ | ||
const customEvent = new CustomEvent("_propertyChange", { | ||
detail: { name, newValue: value }, | ||
composed: false, | ||
bubbles: true, | ||
}); | ||
this.dispatchEvent(customEvent); | ||
if (this._firePropertyChange) { | ||
this.dispatchEvent(new CustomEvent("_propertyChange", { | ||
detail: { name, newValue: value }, | ||
composed: false, | ||
bubbles: true, | ||
})); | ||
} | ||
} | ||
@@ -437,3 +453,3 @@ | ||
_invalidate() { | ||
if (this._invalidated) { | ||
if (!this._upToDate) { | ||
// console.log("already invalidated", this, ...arguments); | ||
@@ -444,3 +460,3 @@ return; | ||
if (this.getDomRef() && !this._suppressInvalidation) { | ||
this._invalidated = true; | ||
this._upToDate = false; | ||
// console.log("INVAL", this, ...arguments); | ||
@@ -456,2 +472,4 @@ RenderScheduler.renderDeferred(this); | ||
_render() { | ||
const hasIndividualSlots = this.constructor.getMetadata().hasIndividualSlots(); | ||
// suppress invalidation to prevent state changes scheduling another rendering | ||
@@ -474,6 +492,6 @@ this._suppressInvalidation = true; | ||
// console.log(this.getDomRef() ? "RE-RENDER" : "FIRST RENDER", this); | ||
delete this._invalidated; | ||
this._upToDate = true; | ||
this._updateShadowRoot(); | ||
if (this.constructor._needsStaticArea()) { | ||
if (this._shouldUpdateFragment()) { | ||
this.staticAreaItem._updateFragment(this); | ||
@@ -483,3 +501,5 @@ } | ||
// Safari requires that children get the slot attribute only after the slot tags have been rendered in the shadow DOM | ||
this._assignIndividualSlotsToChildren(); | ||
if (hasIndividualSlots) { | ||
this._assignIndividualSlotsToChildren(); | ||
} | ||
@@ -496,2 +516,6 @@ // Call the onAfterRendering hook | ||
_updateShadowRoot() { | ||
if (!this.constructor._needsShadowDOM()) { | ||
return; | ||
} | ||
let styleToPrepend; | ||
@@ -622,2 +646,12 @@ const renderResult = this.constructor.template(this); | ||
get isCompact() { | ||
return getComputedStyle(this).getPropertyValue(GLOBAL_CONTENT_DENSITY_CSS_VAR) === "compact"; | ||
} | ||
updateStaticAreaItemContentDensity() { | ||
if (this.staticAreaItem) { | ||
this.staticAreaItem._updateContentDensity(this.isCompact); | ||
} | ||
} | ||
/** | ||
@@ -641,17 +675,4 @@ * Used to duck-type UI5 elements without using instanceof | ||
/** | ||
* Used to generate the next auto-increment id for the current class | ||
* @returns {string} | ||
* @private | ||
*/ | ||
static _nextID() { | ||
const className = kebabToCamelCase(this.getMetadata().getTag()); | ||
const lastNumber = IDMap.get(className); | ||
const nextNumber = lastNumber !== undefined ? lastNumber + 1 : 1; | ||
IDMap.set(className, nextNumber); | ||
return `__${className}${nextNumber}`; | ||
} | ||
/** | ||
* @private | ||
*/ | ||
static _getSlotName(child) { | ||
@@ -681,2 +702,6 @@ // Text nodes can only go to the default slot | ||
_shouldUpdateFragment() { | ||
return this.constructor._needsStaticArea() && this.staticAreaItem.isRendered(); | ||
} | ||
/** | ||
@@ -706,2 +731,3 @@ * @private | ||
const defaultState = {}; | ||
const slotsAreManaged = MetadataClass.slotsAreManaged(); | ||
@@ -732,6 +758,8 @@ // Initialize properties | ||
// Initialize slots | ||
const slots = MetadataClass.getSlots(); | ||
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line | ||
const propertyName = slotData.propertyName || slotName; | ||
defaultState[propertyName] = []; | ||
if (slotsAreManaged) { | ||
const slots = MetadataClass.getSlots(); | ||
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line | ||
const propertyName = slotData.propertyName || slotName; | ||
defaultState[propertyName] = []; | ||
} | ||
} | ||
@@ -748,2 +776,3 @@ | ||
const proto = this.prototype; | ||
const slotsAreManaged = this.getMetadata().slotsAreManaged(); | ||
@@ -757,6 +786,18 @@ // Properties | ||
if (propData.type === "boolean" && propData.defaultValue) { | ||
if (propData.type === Boolean && propData.defaultValue) { | ||
throw new Error(`Cannot set a default value for property "${prop}". All booleans are false by default.`); | ||
} | ||
if (propData.type === Array) { | ||
throw new Error(`Wrong type for property "${prop}". Properties cannot be of type Array - use "multiple: true" and set "type" to the single value type, such as "String", "Object", etc...`); | ||
} | ||
if (propData.type === Object && propData.defaultValue) { | ||
throw new Error(`Cannot set a default value for property "${prop}". All properties of type "Object" are empty objects by default.`); | ||
} | ||
if (propData.multiple && propData.defaultValue) { | ||
throw new Error(`Cannot set a default value for property "${prop}". All multiple properties are empty arrays by default.`); | ||
} | ||
Object.defineProperty(proto, prop, { | ||
@@ -795,20 +836,22 @@ get() { | ||
// Slots | ||
const slots = this.getMetadata().getSlots(); | ||
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line | ||
if (!isValidPropertyName(slotName)) { | ||
throw new Error(`"${slotName}" is not a valid property name. Use a name that does not collide with DOM APIs`); | ||
if (slotsAreManaged) { | ||
const slots = this.getMetadata().getSlots(); | ||
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line | ||
if (!isValidPropertyName(slotName)) { | ||
throw new Error(`"${slotName}" is not a valid property name. Use a name that does not collide with DOM APIs`); | ||
} | ||
const propertyName = slotData.propertyName || slotName; | ||
Object.defineProperty(proto, propertyName, { | ||
get() { | ||
if (this._state[propertyName] !== undefined) { | ||
return this._state[propertyName]; | ||
} | ||
return []; | ||
}, | ||
set() { | ||
throw new Error("Cannot set slots directly, use the DOM APIs"); | ||
}, | ||
}); | ||
} | ||
const propertyName = slotData.propertyName || slotName; | ||
Object.defineProperty(proto, propertyName, { | ||
get() { | ||
if (this._state[propertyName] !== undefined) { | ||
return this._state[propertyName]; | ||
} | ||
return []; | ||
}, | ||
set() { | ||
throw new Error("Cannot set slots directly, use the DOM APIs"); | ||
}, | ||
}); | ||
} | ||
@@ -834,2 +877,10 @@ } | ||
/** | ||
* Returns the Static Area CSS for this UI5 Web Component Class | ||
* @protected | ||
*/ | ||
static get staticAreaStyles() { | ||
return ""; | ||
} | ||
/** | ||
* Registers a UI5 Web Component in the browser window object | ||
@@ -841,5 +892,10 @@ * @public | ||
await boot(); | ||
if (this.onDefine) { | ||
await this.onDefine(); | ||
} | ||
const tag = this.getMetadata().getTag(); | ||
const definedLocally = DefinitionsSet.has(tag); | ||
const definedLocally = isTagRegistered(tag); | ||
const definedGlobally = customElements.get(tag); | ||
@@ -851,3 +907,3 @@ | ||
this._generateAccessors(); | ||
DefinitionsSet.add(tag); | ||
registerTag(tag); | ||
window.customElements.define(tag, this); | ||
@@ -854,0 +910,0 @@ } |
@@ -81,2 +81,11 @@ import DataType from "./types/DataType.js"; | ||
/** | ||
* Determines whether this UI5 Element has a default slot of type Node, therefore can slot text | ||
* @returns {boolean} | ||
*/ | ||
canSlotText() { | ||
const defaultSlot = this.getSlots().default; | ||
return defaultSlot && defaultSlot.type === Node; | ||
} | ||
/** | ||
* Determines whether this UI5 Element supports any slots | ||
@@ -90,2 +99,18 @@ * @public | ||
/** | ||
* Determines whether this UI5 Element supports any slots with "individualSlots: true" | ||
* @public | ||
*/ | ||
hasIndividualSlots() { | ||
return this.slotsAreManaged() && Object.entries(this.getSlots()).some(([_slotName, slotData]) => slotData.individualSlots); | ||
} | ||
/** | ||
* Determines whether this UI5 Element needs to invalidate if children are added/removed/changed | ||
* @public | ||
*/ | ||
slotsAreManaged() { | ||
return !!this.metadata.managedSlots; | ||
} | ||
/** | ||
* Returns an object with key-value pairs of properties and their metadata definitions | ||
@@ -92,0 +117,0 @@ * @public |
@@ -0,1 +1,3 @@ | ||
import { DEFAULT_LANGUAGE } from "../generated/AssetParameters.js"; | ||
export default () => { | ||
@@ -10,3 +12,3 @@ const browserLanguages = navigator.languages; | ||
return rawLocale || "en"; | ||
return rawLocale || DEFAULT_LANGUAGE; | ||
}; |
@@ -0,4 +1,7 @@ | ||
// Note: disabled is present in IE so we explicitly allow it here. | ||
// Others, such as ariaLabel, we explicitly override, so valid too | ||
const whitelist = ["disabled", "ariaLabel"]; | ||
/** | ||
* Checks whether a property name is valid (does not collide with existing DOM API properties) | ||
* Note: disabled is present in IE so we explicitly allow it here. | ||
* | ||
@@ -9,3 +12,3 @@ * @param name | ||
const isValidPropertyName = name => { | ||
if (name === "disabled") { | ||
if (whitelist.includes(name)) { | ||
return true; | ||
@@ -12,0 +15,0 @@ } |
@@ -1,5 +0,20 @@ | ||
const kebabToCamelCase = string => toCamelCase(string.split("-")); | ||
const kebabToCamelMap = new Map(); | ||
const camelToKebabMap = new Map(); | ||
const camelToKebabCase = string => string.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); | ||
const kebabToCamelCase = string => { | ||
if (!kebabToCamelMap.has(string)) { | ||
const result = toCamelCase(string.split("-")); | ||
kebabToCamelMap.set(string, result); | ||
} | ||
return kebabToCamelMap.get(string); | ||
}; | ||
const camelToKebabCase = string => { | ||
if (!camelToKebabMap.has(string)) { | ||
const result = string.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); | ||
camelToKebabMap.set(string, result); | ||
} | ||
return camelToKebabMap.get(string); | ||
}; | ||
const toCamelCase = parts => { | ||
@@ -6,0 +21,0 @@ return parts.map((string, index) => { |
@@ -1,2 +0,1 @@ | ||
import isNodeTabbable from "./isNodeTabbable.js"; | ||
@@ -3,0 +2,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
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
4
4372572
280
16945
1
9
- Removed@ui5/webcomponents-utils@0.0.0-389bdbabc(transitive)