@ui5/webcomponents-base
Advanced tools
Comparing version 0.0.0-04e3a6f74 to 0.0.0-07460127d
@@ -11,3 +11,2 @@ // ES5 bundle targets IE11 only | ||
import { getNoConflict, setNoConflict } from "./dist/config/NoConflict.js"; | ||
import { getCompactSize, setCompactSize } from "./dist/config/CompactSize.js"; | ||
import { getRTL } from "./dist/config/RTL.js"; | ||
@@ -23,4 +22,2 @@ import { getFirstDayOfWeek } from "./dist/config/FormatSettings.js"; | ||
setNoConflict, | ||
getCompactSize, | ||
setCompactSize, | ||
getCalendarType, | ||
@@ -27,0 +24,0 @@ getRTL, |
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,3 +12,2 @@ // Test components | ||
import "./dist/test-resources/elements/Child.js"; | ||
import "./dist/test-resources/elements/DensityAware.js"; | ||
import "./dist/test-resources/elements/GenericExt.js"; | ||
@@ -38,3 +33,2 @@ | ||
import { getNoConflict, setNoConflict } from "./dist/config/NoConflict.js"; | ||
import { getCompactSize, setCompactSize } from "./dist/config/CompactSize.js"; | ||
import { getRTL } from "./dist/config/RTL.js"; | ||
@@ -51,4 +45,2 @@ import { getFirstDayOfWeek } from "./dist/config/FormatSettings.js"; | ||
setNoConflict, | ||
getCompactSize, | ||
setCompactSize, | ||
getCalendarType, | ||
@@ -55,0 +47,0 @@ getRTL, |
@@ -1,6 +0,5 @@ | ||
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"; | ||
@@ -52,3 +51,3 @@ const bundleData = new Map(); | ||
const language = getLanguage(); | ||
const language = getLocale().getLanguage(); | ||
@@ -55,0 +54,0 @@ let localeId = normalizeLocale(language); |
@@ -1,6 +0,9 @@ | ||
import { registerModuleContent } from "../ResourceLoaderOverrides.js"; | ||
import { fetchJsonOnce } from "../util/FetchHelper.js"; | ||
import { getFeature } from "../FeaturesRegistry.js"; | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
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 = {}; | ||
@@ -62,2 +65,20 @@ const cldrUrls = {}; | ||
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) => { | ||
@@ -67,5 +88,9 @@ resolveMissingMappings(); | ||
const cldrObj = cldrData[localeId]; | ||
let cldrObj = cldrData[localeId]; | ||
const url = cldrUrls[localeId]; | ||
if (!cldrObj && OpenUI5Support) { | ||
cldrObj = OpenUI5Support.getLocaleDataObject(); | ||
} | ||
if (cldrObj) { | ||
@@ -102,3 +127,4 @@ // inlined from build or fetched independently | ||
getCldrData, | ||
getModuleContent, | ||
_registerMappingFunction, | ||
}; |
import whenDOMReady from "./util/whenDOMReady.js"; | ||
import EventEnrichment from "./events/EventEnrichment.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"; | ||
EventEnrichment.run(); | ||
let bootPromise; | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
@@ -18,4 +17,9 @@ const boot = () => { | ||
bootPromise = new Promise(async resolve => { | ||
if (OpenUI5Support) { | ||
await OpenUI5Support.init(); | ||
} | ||
await whenDOMReady(); | ||
await _applyTheme(getTheme()); | ||
await applyTheme(getTheme()); | ||
OpenUI5Support && OpenUI5Support.attachListeners(); | ||
insertFontFace(); | ||
@@ -22,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 @@ |
@@ -0,1 +1,2 @@ | ||
import RenderScheduler from "../RenderScheduler.js"; | ||
import { | ||
@@ -8,3 +9,3 @@ isDown, | ||
isEnd, | ||
} from "../events/PseudoEvents.js"; | ||
} from "../Keys.js"; | ||
@@ -23,5 +24,5 @@ import EventProvider from "../EventProvider.js"; | ||
this.rowSize = options.rowSize || 1; | ||
this.cyclic = options.cyclic || false; | ||
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; | ||
@@ -34,5 +35,5 @@ const autoNavigation = !navigationMode || navigationMode === NavigationMode.Auto; | ||
this.rootWebComponent.addEventListener("keydown", this.onkeydown.bind(this)); | ||
this.rootWebComponent.addEventListener("_componentStateFinalized", () => { | ||
this.rootWebComponent._onComponentStateFinalized = () => { | ||
this._init(); | ||
}); | ||
}; | ||
} | ||
@@ -54,33 +55,15 @@ | ||
_onKeyPress(event) { | ||
const items = this._getItems(); | ||
if (this.currentIndex >= items.length) { | ||
if (this.behavior !== ItemNavigationBehavior.Cyclic) { | ||
if (this.behavior === ItemNavigationBehavior.Paging) { | ||
this.currentIndex = this.currentIndex - items.length; | ||
} else { | ||
this.currentIndex = items.length - 1; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: false, end: true, offset: this.currentIndex }); | ||
} else { | ||
this.currentIndex = this.currentIndex - items.length; | ||
} | ||
async _onKeyPress(event) { | ||
if (this.currentIndex >= this._getItems().length) { | ||
this.onOverflowBottomEdge(); | ||
} else if (this.currentIndex < 0) { | ||
if (this.behavior !== ItemNavigationBehavior.Cyclic) { | ||
if (this.behavior === ItemNavigationBehavior.Paging) { | ||
this.currentIndex = items.length + this.currentIndex - this.rowSize + (this.rowSize - (this._getItems().length % this.rowSize)); | ||
} else { | ||
this.currentIndex = 0; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: true, end: false, offset: this.currentIndex }); | ||
} else { | ||
this.currentIndex = items.length + this.currentIndex; | ||
} | ||
this.onOverflowTopEdge(); | ||
} | ||
event.preventDefault(); | ||
await RenderScheduler.whenFinished(); | ||
this.update(); | ||
this.focusCurrent(); | ||
// stops browser scrolling with up/down keys | ||
event.preventDefault(); | ||
} | ||
@@ -235,6 +218,66 @@ | ||
} | ||
onOverflowBottomEdge() { | ||
const items = this._getItems(); | ||
const offset = this.currentIndex - items.length; | ||
if (this.behavior === ItemNavigationBehavior.Cyclic) { | ||
this.currentIndex = 0; | ||
return; | ||
} | ||
if (this.behavior === ItemNavigationBehavior.Paging) { | ||
this._handleNextPage(); | ||
} else { | ||
this.currentIndex = items.length - 1; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: false, end: true, offset }); | ||
} | ||
onOverflowTopEdge() { | ||
const items = this._getItems(); | ||
const offset = this.currentIndex + this.rowSize; | ||
if (this.behavior === ItemNavigationBehavior.Cyclic) { | ||
this.currentIndex = items.length - 1; | ||
return; | ||
} | ||
if (this.behavior === ItemNavigationBehavior.Paging) { | ||
this._handlePrevPage(); | ||
} else { | ||
this.currentIndex = 0; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: true, end: false, offset }); | ||
} | ||
_handleNextPage() { | ||
this.fireEvent(ItemNavigation.PAGE_BOTTOM); | ||
const items = this._getItems(); | ||
if (!this.hasNextPage) { | ||
this.currentIndex = items.length - 1; | ||
} else { | ||
this.currentIndex = 0; | ||
} | ||
} | ||
_handlePrevPage() { | ||
this.fireEvent(ItemNavigation.PAGE_TOP); | ||
const items = this._getItems(); | ||
if (!this.hasPrevPage) { | ||
this.currentIndex = 0; | ||
} else { | ||
this.currentIndex = (this.pageSize || items.length) - 1; | ||
} | ||
} | ||
} | ||
ItemNavigation.PAGE_TOP = "PageTop"; | ||
ItemNavigation.PAGE_BOTTOM = "PageBottom"; | ||
ItemNavigation.BORDER_REACH = "_borderReach"; | ||
export default ItemNavigation; |
@@ -5,2 +5,3 @@ import EventProvider from "../EventProvider.js"; | ||
const scrollEventName = "scroll"; | ||
const touchEndEventName = "touchend"; | ||
@@ -12,2 +13,3 @@ class ScrollEnablement extends EventProvider { | ||
containerComponent.addEventListener("touchmove", this.ontouchmove.bind(this), { passive: true }); | ||
containerComponent.addEventListener("touchend", this.ontouchend.bind(this), { passive: true }); | ||
} | ||
@@ -75,3 +77,6 @@ | ||
this.fireEvent(scrollEventName, {}); | ||
this.fireEvent(scrollEventName, { | ||
isLeft: dragX > this._prevDragX, | ||
isRight: dragX < this._prevDragX, | ||
}); | ||
@@ -81,4 +86,25 @@ this._prevDragX = dragX; | ||
} | ||
ontouchend(event) { | ||
if (!this._canScroll) { | ||
return; | ||
} | ||
const container = this._container; | ||
const dragX = event.pageX; | ||
const dragY = event.pageY; | ||
container.scrollLeft += this._prevDragX - dragX; | ||
container.scrollTop += this._prevDragY - dragY; | ||
this.fireEvent(touchEndEventName, { | ||
isLeft: dragX > this._prevDragX, | ||
isRight: dragX < this._prevDragX, | ||
}); | ||
this._prevDragX = dragX; | ||
this._prevDragY = dragY; | ||
} | ||
} | ||
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 @@ }; |
@@ -30,7 +30,7 @@ import { fetchI18nBundle, getI18nBundleData } from "./asset-registries/i18n.js"; | ||
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,4 +1,7 @@ | ||
import merge from "./thirdparty/merge.js"; | ||
import { getFeature } from "./FeaturesRegistry.js"; | ||
let initialized = false; | ||
const initialConfig = { | ||
let initialConfig = { | ||
animationMode: "full", | ||
@@ -8,3 +11,2 @@ theme: "sap_fiori_3", | ||
language: null, | ||
compactSize: false, | ||
calendarType: null, | ||
@@ -36,7 +38,2 @@ noConflict: false, // no URL | ||
const getCompactSize = () => { | ||
initConfiguration(); | ||
return initialConfig.compactSize; | ||
}; | ||
const getNoConflict = () => { | ||
@@ -61,4 +58,2 @@ initConfiguration(); | ||
let runtimeConfig = {}; | ||
const parseConfigurationScript = () => { | ||
@@ -77,3 +72,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); | ||
} | ||
@@ -99,12 +94,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 = () => { | ||
@@ -115,6 +115,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; | ||
@@ -128,3 +133,2 @@ }; | ||
getLanguage, | ||
getCompactSize, | ||
getNoConflict, | ||
@@ -131,0 +135,0 @@ getCalendarType, |
@@ -15,2 +15,4 @@ import RenderQueue from "./RenderQueue.js"; | ||
let mutationObserverTimer; | ||
/** | ||
@@ -87,7 +89,10 @@ * Class that manages the rendering/re-rendering of web components | ||
// wait for Mutation observer just in case | ||
setTimeout(() => { | ||
if (invalidatedWebComponents.getList().length === 0) { | ||
RenderScheduler._resolveTaskPromise(); | ||
} | ||
}, 200); | ||
if (!mutationObserverTimer) { | ||
mutationObserverTimer = setTimeout(() => { | ||
mutationObserverTimer = undefined; | ||
if (invalidatedWebComponents.getList().length === 0) { | ||
RenderScheduler._resolveTaskPromise(); | ||
} | ||
}, 200); | ||
} | ||
@@ -94,0 +99,0 @@ renderTaskId = undefined; |
@@ -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: { |
@@ -6,11 +6,2 @@ const assert = require("chai").assert; | ||
it("Tests that compactSize can be changed", () => { | ||
const res = browser.execute( () => { | ||
const config = window['sap-ui-webcomponents-bundle'].configuration; | ||
config.setCompactSize(true); | ||
return config.getCompactSize(); | ||
}); | ||
assert.strictEqual(res, true, "compactSize changed to true"); | ||
}); | ||
it("Tests that theme can be changed", () => { | ||
@@ -17,0 +8,0 @@ const newTheme = 'sap_belize_hcb'; |
@@ -14,10 +14,2 @@ const assert = require("chai").assert; | ||
it("Tests that compactSize is applied", () => { | ||
const res = browser.execute( () => { | ||
const config = window['sap-ui-webcomponents-bundle'].configuration; | ||
return config.getCompactSize(); | ||
}); | ||
assert.strictEqual(res, true, "compactSize is true"); | ||
}); | ||
it("Tests that language is applied", () => { | ||
@@ -24,0 +16,0 @@ const res = browser.execute( () => { |
const assert = require("chai").assert; | ||
describe("Some settings can be set via URL params", () => { | ||
browser.url("http://localhost:9191/test-resources/pages/Configuration.html?sap-ui-rtl=true&sap-ui-compactSize=true&sap-ui-language=ja&sap-ui-calendarType=Japanese&sap-ui-theme=sap_belize_hcb&sap-ui-animationMode=basic"); | ||
browser.url("http://localhost:9191/test-resources/pages/Configuration.html?sap-ui-rtl=true&sap-ui-language=ja&sap-ui-calendarType=Japanese&sap-ui-theme=sap_belize_hcb&sap-ui-animationMode=basic"); | ||
@@ -14,10 +14,2 @@ it("Tests that RTL is applied", () => { | ||
it("Tests that compactSize is applied", () => { | ||
const res = browser.execute( () => { | ||
const config = window['sap-ui-webcomponents-bundle'].configuration; | ||
return config.getCompactSize(); | ||
}); | ||
assert.strictEqual(res, true, "compactSize is true"); | ||
}); | ||
it("Tests that language is applied", () => { | ||
@@ -24,0 +16,0 @@ const res = browser.execute( () => { |
@@ -1,45 +0,7 @@ | ||
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"; | ||
import { setExternalThemePresent } from "./theming/ExternalThemePresent.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, | ||
setExternalThemePresent, | ||
}; |
@@ -11,2 +11,3 @@ import DataType from "./DataType.js"; | ||
Error: "Error", | ||
Information: "Information", | ||
}; | ||
@@ -13,0 +14,0 @@ |
@@ -1,13 +0,12 @@ | ||
import merge from "@ui5/webcomponents-utils/dist/sap/base/util/merge.js"; | ||
import merge from "./thirdparty/merge.js"; | ||
import boot from "./boot.js"; | ||
import UI5ElementMetadata from "./UI5ElementMetadata.js"; | ||
import StaticAreaItem from "./StaticAreaItem.js"; | ||
import RenderScheduler from "./RenderScheduler.js"; | ||
import DOMObserver from "./compatibility/DOMObserver.js"; | ||
import { skipOriginalEvent } from "./config/NoConflict.js"; | ||
import { getCompactSize } from "./config/CompactSize.js"; | ||
import DOMObserver from "./compatibility/DOMObserver.js"; | ||
import UI5ElementMetadata from "./UI5ElementMetadata.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 { attachContentDensityChange } from "./ContentDensity.js"; | ||
import { kebabToCamelCase, camelToKebabCase } from "./util/StringHelper.js"; | ||
@@ -23,4 +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"; | ||
/** | ||
@@ -42,6 +44,5 @@ * Base class for all UI5 Web Components | ||
this._upgradeAllProperties(); | ||
this._initializeShadowRoot(); | ||
this._initializeContainers(); | ||
this._upToDate = false; | ||
attachContentDensityChange(this._onContentDensityChanged.bind(this)); | ||
let deferredResolve; | ||
@@ -54,2 +55,3 @@ this._domRefReadyPromise = new Promise(resolve => { | ||
this._monitoredChildProps = new Map(); | ||
this._firePropertyChange = false; | ||
} | ||
@@ -60,7 +62,4 @@ | ||
*/ | ||
_onContentDensityChanged() { | ||
this._syncContentDensity(); | ||
if (this.constructor.getMetadata().getInvalidateOnContentDensityChange()) { | ||
this._invalidate(); | ||
} | ||
_generateId() { | ||
this._id = `ui5wc_${++autoId}`; | ||
} | ||
@@ -71,37 +70,25 @@ | ||
*/ | ||
_syncContentDensity() { | ||
const isCompact = getCompactSize(); | ||
if (isCompact) { | ||
this.setAttribute("data-ui5-compact-size", ""); | ||
} else { | ||
this.removeAttribute("data-ui5-compact-size"); | ||
} | ||
} | ||
_initializeContainers() { | ||
const needsShadowDOM = this.constructor._needsShadowDOM(); | ||
const needsStaticArea = this.constructor._needsStaticArea(); | ||
/** | ||
* @private | ||
*/ | ||
_generateId() { | ||
this._id = this.constructor._nextID(); | ||
} | ||
// Init Shadow Root | ||
if (needsShadowDOM) { | ||
this.attachShadow({ mode: "open" }); | ||
/** | ||
* @private | ||
*/ | ||
_initializeShadowRoot() { | ||
if (!this.constructor._needsShadowDOM()) { | ||
return; | ||
} | ||
// IE11, Edge | ||
if (window.ShadyDOM) { | ||
createComponentStyleTag(this.constructor); | ||
} | ||
this.attachShadow({ mode: "open" }); | ||
// IE11, Edge | ||
if (window.ShadyDOM) { | ||
createHeadStyle(this.constructor); | ||
// Chrome | ||
if (document.adoptedStyleSheets) { | ||
const style = getConstructableStyle(this.constructor); | ||
this.shadowRoot.adoptedStyleSheets = [style]; | ||
} | ||
} | ||
// Chrome | ||
if (document.adoptedStyleSheets) { | ||
const style = getConstructableStyle(this.constructor); | ||
this.shadowRoot.adoptedStyleSheets = [style]; | ||
// Init StaticAreaItem only if needed | ||
if (needsStaticArea) { | ||
this.staticAreaItem = new StaticAreaItem(this); | ||
} | ||
@@ -115,16 +102,24 @@ } | ||
async connectedCallback() { | ||
this._syncContentDensity(); | ||
const needsShadowDOM = this.constructor._needsShadowDOM(); | ||
const needsStaticArea = this.constructor._needsStaticArea(); | ||
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged(); | ||
if (!this.constructor._needsShadowDOM()) { | ||
return; | ||
// Render the Shadow DOM | ||
if (needsShadowDOM) { | ||
if (slotsAreManaged) { | ||
// always register the observer before yielding control to the main thread (await) | ||
this._startObservingDOMChildren(); | ||
await this._processChildren(); | ||
} | ||
await RenderScheduler.renderImmediately(this); | ||
this._domRefReadyPromise._deferredResolve(); | ||
if (typeof this.onEnterDOM === "function") { | ||
this.onEnterDOM(); | ||
} | ||
} | ||
// always register the observer before yielding control to the main thread (await) | ||
this._startObservingDOMChildren(); | ||
await this._processChildren(); | ||
await RenderScheduler.renderImmediately(this); | ||
this._domRefReadyPromise._deferredResolve(); | ||
if (typeof this.onEnterDOM === "function") { | ||
this.onEnterDOM(); | ||
// Render Fragment if neccessary | ||
if (needsStaticArea) { | ||
this.staticAreaItem._updateFragment(this); | ||
} | ||
@@ -138,9 +133,18 @@ } | ||
disconnectedCallback() { | ||
if (!this.constructor._needsShadowDOM()) { | ||
return; | ||
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") { | ||
this.onExitDOM(); | ||
} | ||
} | ||
this._stopObservingDOMChildren(); | ||
if (typeof this.onExitDOM === "function") { | ||
this.onExitDOM(); | ||
if (needsStaticArea) { | ||
this.staticAreaItem._removeFragmentFromStaticArea(); | ||
} | ||
@@ -157,5 +161,7 @@ } | ||
} | ||
const canSlotText = this.constructor.getMetadata().canSlotText(); | ||
const mutationObserverOptions = { | ||
childList: true, | ||
subtree: true, | ||
subtree: canSlotText, | ||
characterData: true, | ||
@@ -189,3 +195,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); | ||
@@ -195,3 +201,3 @@ | ||
for (const [slotName, slotData] of Object.entries(slotsMap)) { // eslint-disable-line | ||
this._clearSlot(slotName); | ||
this._clearSlot(slotName, slotData); | ||
} | ||
@@ -216,5 +222,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}`; | ||
} | ||
@@ -230,3 +236,7 @@ | ||
const whenDefinedPromise = window.customElements.whenDefined(localName); // Class registered, but instances not upgraded yet | ||
const timeoutPromise = new Promise(resolve => setTimeout(resolve, 1000)); | ||
let timeoutPromise = elementTimeouts.get(localName); | ||
if (!timeoutPromise) { | ||
timeoutPromise = new Promise(resolve => setTimeout(resolve, 1000)); | ||
elementTimeouts.set(localName, timeoutPromise); | ||
} | ||
await Promise.race([whenDefinedPromise, timeoutPromise]); | ||
@@ -240,4 +250,4 @@ } | ||
if (child.isUI5Element) { | ||
this._attachChildPropertyUpdated(child, slotData); | ||
if (child.isUI5Element && slotData.listenFor) { | ||
this._attachChildPropertyUpdated(child, slotData.listenFor); | ||
} | ||
@@ -261,3 +271,3 @@ | ||
}); | ||
this._invalidate(); | ||
this._invalidate("slots"); | ||
} | ||
@@ -269,4 +279,3 @@ | ||
*/ | ||
_clearSlot(slotName) { | ||
const slotData = this.constructor.getMetadata().getSlots()[slotName]; | ||
_clearSlot(slotName, slotData) { | ||
const propertyName = slotData.propertyName || slotName; | ||
@@ -364,5 +373,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 | ||
@@ -374,6 +382,2 @@ childProperties = childMetadata.getProperties(); | ||
if (!listenFor) { | ||
return; | ||
} | ||
if (Array.isArray(listenFor)) { | ||
@@ -391,2 +395,3 @@ observedProps = listenFor; | ||
child.addEventListener("_propertyChange", this._invalidateParentOnPropertyUpdate); | ||
child._firePropertyChange = true; | ||
} | ||
@@ -399,2 +404,3 @@ | ||
child.removeEventListener("_propertyChange", this._invalidateParentOnPropertyUpdate); | ||
child._firePropertyChange = false; | ||
} | ||
@@ -408,9 +414,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, | ||
})); | ||
} | ||
} | ||
@@ -446,3 +452,3 @@ | ||
_invalidate() { | ||
if (this._invalidated) { | ||
if (!this._upToDate) { | ||
// console.log("already invalidated", this, ...arguments); | ||
@@ -453,3 +459,3 @@ return; | ||
if (this.getDomRef() && !this._suppressInvalidation) { | ||
this._invalidated = true; | ||
this._upToDate = false; | ||
// console.log("INVAL", this, ...arguments); | ||
@@ -465,2 +471,4 @@ RenderScheduler.renderDeferred(this); | ||
_render() { | ||
const hasIndividualSlots = this.constructor.getMetadata().hasIndividualSlots(); | ||
// suppress invalidation to prevent state changes scheduling another rendering | ||
@@ -474,3 +482,5 @@ this._suppressInvalidation = true; | ||
// Intended for framework usage only. Currently ItemNavigation updates tab indexes after the component has updated its state but before the template is rendered | ||
this.dispatchEvent(new CustomEvent("_componentStateFinalized")); | ||
if (this._onComponentStateFinalized) { | ||
this._onComponentStateFinalized(); | ||
} | ||
@@ -482,7 +492,13 @@ // resume normal invalidation handling | ||
// console.log(this.getDomRef() ? "RE-RENDER" : "FIRST RENDER", this); | ||
delete this._invalidated; | ||
this._upToDate = true; | ||
this._updateShadowRoot(); | ||
if (this.constructor._needsStaticArea()) { | ||
this.staticAreaItem._updateFragment(this); | ||
} | ||
// 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(); | ||
} | ||
@@ -624,2 +640,12 @@ // Call the onAfterRendering hook | ||
get isCompact() { | ||
return getComputedStyle(this).getPropertyValue(GLOBAL_CONTENT_DENSITY_CSS_VAR) === "compact"; | ||
} | ||
updateStaticAreaItemContentDensity() { | ||
if (this.staticAreaItem) { | ||
this.staticAreaItem._updateContentDensity(this.isCompact); | ||
} | ||
} | ||
/** | ||
@@ -643,17 +669,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) { | ||
@@ -686,2 +699,16 @@ // Text nodes can only go to the default slot | ||
*/ | ||
static _needsStaticArea() { | ||
return typeof this.staticAreaTemplate === "function"; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
getStaticAreaItemDomRef() { | ||
return this.staticAreaItem.getDomRef(); | ||
} | ||
/** | ||
* @private | ||
*/ | ||
static _getDefaultState() { | ||
@@ -694,2 +721,3 @@ if (this._defaultState) { | ||
const defaultState = {}; | ||
const slotsAreManaged = MetadataClass.slotsAreManaged(); | ||
@@ -720,6 +748,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] = []; | ||
} | ||
} | ||
@@ -736,2 +766,3 @@ | ||
const proto = this.prototype; | ||
const slotsAreManaged = this.getMetadata().slotsAreManaged(); | ||
@@ -782,20 +813,22 @@ // Properties | ||
// 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"); | ||
}, | ||
}); | ||
} | ||
@@ -827,2 +860,7 @@ } | ||
await boot(); | ||
if (this.onDefine) { | ||
await this.onDefine(); | ||
} | ||
const tag = this.getMetadata().getTag(); | ||
@@ -829,0 +867,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 | ||
@@ -105,10 +130,2 @@ * @public | ||
} | ||
/** | ||
* Determines whether this UI5 Element invalidates automatically when content density changes | ||
* @public | ||
*/ | ||
getInvalidateOnContentDensityChange() { | ||
return !!this.metadata.invalidateOnContentDensityChange; | ||
} | ||
} | ||
@@ -115,0 +132,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 @@ |
@@ -13,3 +13,3 @@ const serveConfig = `../tools/components-package/serve.json`; | ||
copy: { | ||
default: "nps copy.cldr copy.src copy.test copy.webcomponents-polyfill", | ||
default: "nps copy.src copy.test copy.webcomponents-polyfill", | ||
cldr: 'copy-and-watch "../../node_modules/@ui5/webcomponents-utils/dist/**/cldr/*.json" dist/generated/assets/cldr/', | ||
@@ -16,0 +16,0 @@ src: "copy-and-watch \"src/**/*.js\" dist/", |
{ | ||
"name": "@ui5/webcomponents-base", | ||
"version": "0.0.0-04e3a6f74", | ||
"version": "0.0.0-07460127d", | ||
"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-04e3a6f74", | ||
"css-vars-ponyfill": "^2.1.2", | ||
@@ -34,3 +34,3 @@ "lit-html": "^1.0.0", | ||
"devDependencies": { | ||
"@ui5/webcomponents-tools": "0.0.0-04e3a6f74", | ||
"@ui5/webcomponents-tools": "0.0.0-07460127d", | ||
"array-uniq": "^2.0.0", | ||
@@ -37,0 +37,0 @@ "copy-and-watch": "^0.1.4", |
@@ -1,6 +0,5 @@ | ||
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"; | ||
@@ -52,3 +51,3 @@ const bundleData = new Map(); | ||
const language = getLanguage(); | ||
const language = getLocale().getLanguage(); | ||
@@ -55,0 +54,0 @@ let localeId = normalizeLocale(language); |
@@ -1,6 +0,9 @@ | ||
import { registerModuleContent } from "../ResourceLoaderOverrides.js"; | ||
import { fetchJsonOnce } from "../util/FetchHelper.js"; | ||
import { getFeature } from "../FeaturesRegistry.js"; | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
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 = {}; | ||
@@ -62,2 +65,20 @@ const cldrUrls = {}; | ||
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) => { | ||
@@ -67,5 +88,9 @@ resolveMissingMappings(); | ||
const cldrObj = cldrData[localeId]; | ||
let cldrObj = cldrData[localeId]; | ||
const url = cldrUrls[localeId]; | ||
if (!cldrObj && OpenUI5Support) { | ||
cldrObj = OpenUI5Support.getLocaleDataObject(); | ||
} | ||
if (cldrObj) { | ||
@@ -102,3 +127,4 @@ // inlined from build or fetched independently | ||
getCldrData, | ||
getModuleContent, | ||
_registerMappingFunction, | ||
}; |
import whenDOMReady from "./util/whenDOMReady.js"; | ||
import EventEnrichment from "./events/EventEnrichment.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"; | ||
EventEnrichment.run(); | ||
let bootPromise; | ||
const OpenUI5Support = getFeature("OpenUI5Support"); | ||
@@ -18,4 +17,9 @@ const boot = () => { | ||
bootPromise = new Promise(async resolve => { | ||
if (OpenUI5Support) { | ||
await OpenUI5Support.init(); | ||
} | ||
await whenDOMReady(); | ||
await _applyTheme(getTheme()); | ||
await applyTheme(getTheme()); | ||
OpenUI5Support && OpenUI5Support.attachListeners(); | ||
insertFontFace(); | ||
@@ -22,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 @@ |
@@ -0,1 +1,2 @@ | ||
import RenderScheduler from "../RenderScheduler.js"; | ||
import { | ||
@@ -8,3 +9,3 @@ isDown, | ||
isEnd, | ||
} from "../events/PseudoEvents.js"; | ||
} from "../Keys.js"; | ||
@@ -24,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; | ||
@@ -33,5 +35,5 @@ const autoNavigation = !navigationMode || navigationMode === NavigationMode.Auto; | ||
this.rootWebComponent.addEventListener("keydown", this.onkeydown.bind(this)); | ||
this.rootWebComponent.addEventListener("_componentStateFinalized", () => { | ||
this.rootWebComponent._onComponentStateFinalized = () => { | ||
this._init(); | ||
}); | ||
}; | ||
} | ||
@@ -53,33 +55,15 @@ | ||
_onKeyPress(event) { | ||
const items = this._getItems(); | ||
if (this.currentIndex >= items.length) { | ||
if (this.behavior !== ItemNavigationBehavior.Cyclic) { | ||
if (this.behavior === ItemNavigationBehavior.Paging) { | ||
this.currentIndex = this.currentIndex - items.length; | ||
} else { | ||
this.currentIndex = items.length - 1; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: false, end: true, offset: this.currentIndex }); | ||
} else { | ||
this.currentIndex = this.currentIndex - items.length; | ||
} | ||
async _onKeyPress(event) { | ||
if (this.currentIndex >= this._getItems().length) { | ||
this.onOverflowBottomEdge(); | ||
} else if (this.currentIndex < 0) { | ||
if (this.behavior !== ItemNavigationBehavior.Cyclic) { | ||
if (this.behavior === ItemNavigationBehavior.Paging) { | ||
this.currentIndex = items.length + this.currentIndex - this.rowSize + (this.rowSize - (this._getItems().length % this.rowSize)); | ||
} else { | ||
this.currentIndex = 0; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: true, end: false, offset: this.currentIndex }); | ||
} else { | ||
this.currentIndex = items.length + this.currentIndex; | ||
} | ||
this.onOverflowTopEdge(); | ||
} | ||
event.preventDefault(); | ||
await RenderScheduler.whenFinished(); | ||
this.update(); | ||
this.focusCurrent(); | ||
// stops browser scrolling with up/down keys | ||
event.preventDefault(); | ||
} | ||
@@ -234,6 +218,66 @@ | ||
} | ||
onOverflowBottomEdge() { | ||
const items = this._getItems(); | ||
const offset = this.currentIndex - items.length; | ||
if (this.behavior === ItemNavigationBehavior.Cyclic) { | ||
this.currentIndex = 0; | ||
return; | ||
} | ||
if (this.behavior === ItemNavigationBehavior.Paging) { | ||
this._handleNextPage(); | ||
} else { | ||
this.currentIndex = items.length - 1; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: false, end: true, offset }); | ||
} | ||
onOverflowTopEdge() { | ||
const items = this._getItems(); | ||
const offset = this.currentIndex + this.rowSize; | ||
if (this.behavior === ItemNavigationBehavior.Cyclic) { | ||
this.currentIndex = items.length - 1; | ||
return; | ||
} | ||
if (this.behavior === ItemNavigationBehavior.Paging) { | ||
this._handlePrevPage(); | ||
} else { | ||
this.currentIndex = 0; | ||
} | ||
this.fireEvent(ItemNavigation.BORDER_REACH, { start: true, end: false, offset }); | ||
} | ||
_handleNextPage() { | ||
this.fireEvent(ItemNavigation.PAGE_BOTTOM); | ||
const items = this._getItems(); | ||
if (!this.hasNextPage) { | ||
this.currentIndex = items.length - 1; | ||
} else { | ||
this.currentIndex = 0; | ||
} | ||
} | ||
_handlePrevPage() { | ||
this.fireEvent(ItemNavigation.PAGE_TOP); | ||
const items = this._getItems(); | ||
if (!this.hasPrevPage) { | ||
this.currentIndex = 0; | ||
} else { | ||
this.currentIndex = (this.pageSize || items.length) - 1; | ||
} | ||
} | ||
} | ||
ItemNavigation.PAGE_TOP = "PageTop"; | ||
ItemNavigation.PAGE_BOTTOM = "PageBottom"; | ||
ItemNavigation.BORDER_REACH = "_borderReach"; | ||
export default ItemNavigation; |
@@ -5,2 +5,3 @@ import EventProvider from "../EventProvider.js"; | ||
const scrollEventName = "scroll"; | ||
const touchEndEventName = "touchend"; | ||
@@ -12,2 +13,3 @@ class ScrollEnablement extends EventProvider { | ||
containerComponent.addEventListener("touchmove", this.ontouchmove.bind(this), { passive: true }); | ||
containerComponent.addEventListener("touchend", this.ontouchend.bind(this), { passive: true }); | ||
} | ||
@@ -75,3 +77,6 @@ | ||
this.fireEvent(scrollEventName, {}); | ||
this.fireEvent(scrollEventName, { | ||
isLeft: dragX > this._prevDragX, | ||
isRight: dragX < this._prevDragX, | ||
}); | ||
@@ -81,4 +86,25 @@ this._prevDragX = dragX; | ||
} | ||
ontouchend(event) { | ||
if (!this._canScroll) { | ||
return; | ||
} | ||
const container = this._container; | ||
const dragX = event.pageX; | ||
const dragY = event.pageY; | ||
container.scrollLeft += this._prevDragX - dragX; | ||
container.scrollTop += this._prevDragY - dragY; | ||
this.fireEvent(touchEndEventName, { | ||
isLeft: dragX > this._prevDragX, | ||
isRight: dragX < this._prevDragX, | ||
}); | ||
this._prevDragX = dragX; | ||
this._prevDragY = dragY; | ||
} | ||
} | ||
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 @@ }; |
@@ -30,7 +30,7 @@ import { fetchI18nBundle, getI18nBundleData } from "./asset-registries/i18n.js"; | ||
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,4 +1,7 @@ | ||
import merge from "./thirdparty/merge.js"; | ||
import { getFeature } from "./FeaturesRegistry.js"; | ||
let initialized = false; | ||
const initialConfig = { | ||
let initialConfig = { | ||
animationMode: "full", | ||
@@ -8,3 +11,2 @@ theme: "sap_fiori_3", | ||
language: null, | ||
compactSize: false, | ||
calendarType: null, | ||
@@ -36,7 +38,2 @@ noConflict: false, // no URL | ||
const getCompactSize = () => { | ||
initConfiguration(); | ||
return initialConfig.compactSize; | ||
}; | ||
const getNoConflict = () => { | ||
@@ -61,4 +58,2 @@ initConfiguration(); | ||
let runtimeConfig = {}; | ||
const parseConfigurationScript = () => { | ||
@@ -77,3 +72,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); | ||
} | ||
@@ -99,12 +94,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 = () => { | ||
@@ -115,6 +115,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; | ||
@@ -128,3 +133,2 @@ }; | ||
getLanguage, | ||
getCompactSize, | ||
getNoConflict, | ||
@@ -131,0 +135,0 @@ getCalendarType, |
@@ -15,2 +15,4 @@ import RenderQueue from "./RenderQueue.js"; | ||
let mutationObserverTimer; | ||
/** | ||
@@ -87,7 +89,10 @@ * Class that manages the rendering/re-rendering of web components | ||
// wait for Mutation observer just in case | ||
setTimeout(() => { | ||
if (invalidatedWebComponents.getList().length === 0) { | ||
RenderScheduler._resolveTaskPromise(); | ||
} | ||
}, 200); | ||
if (!mutationObserverTimer) { | ||
mutationObserverTimer = setTimeout(() => { | ||
mutationObserverTimer = undefined; | ||
if (invalidatedWebComponents.getList().length === 0) { | ||
RenderScheduler._resolveTaskPromise(); | ||
} | ||
}, 200); | ||
} | ||
@@ -94,0 +99,0 @@ renderTaskId = undefined; |
@@ -1,45 +0,7 @@ | ||
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"; | ||
import { setExternalThemePresent } from "./theming/ExternalThemePresent.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, | ||
setExternalThemePresent, | ||
}; |
@@ -11,2 +11,3 @@ import DataType from "./DataType.js"; | ||
Error: "Error", | ||
Information: "Information", | ||
}; | ||
@@ -13,0 +14,0 @@ |
@@ -1,13 +0,12 @@ | ||
import merge from "@ui5/webcomponents-utils/dist/sap/base/util/merge.js"; | ||
import merge from "./thirdparty/merge.js"; | ||
import boot from "./boot.js"; | ||
import UI5ElementMetadata from "./UI5ElementMetadata.js"; | ||
import StaticAreaItem from "./StaticAreaItem.js"; | ||
import RenderScheduler from "./RenderScheduler.js"; | ||
import DOMObserver from "./compatibility/DOMObserver.js"; | ||
import { skipOriginalEvent } from "./config/NoConflict.js"; | ||
import { getCompactSize } from "./config/CompactSize.js"; | ||
import DOMObserver from "./compatibility/DOMObserver.js"; | ||
import UI5ElementMetadata from "./UI5ElementMetadata.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 { attachContentDensityChange } from "./ContentDensity.js"; | ||
import { kebabToCamelCase, camelToKebabCase } from "./util/StringHelper.js"; | ||
@@ -23,4 +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"; | ||
/** | ||
@@ -42,6 +44,5 @@ * Base class for all UI5 Web Components | ||
this._upgradeAllProperties(); | ||
this._initializeShadowRoot(); | ||
this._initializeContainers(); | ||
this._upToDate = false; | ||
attachContentDensityChange(this._onContentDensityChanged.bind(this)); | ||
let deferredResolve; | ||
@@ -54,2 +55,3 @@ this._domRefReadyPromise = new Promise(resolve => { | ||
this._monitoredChildProps = new Map(); | ||
this._firePropertyChange = false; | ||
} | ||
@@ -60,7 +62,4 @@ | ||
*/ | ||
_onContentDensityChanged() { | ||
this._syncContentDensity(); | ||
if (this.constructor.getMetadata().getInvalidateOnContentDensityChange()) { | ||
this._invalidate(); | ||
} | ||
_generateId() { | ||
this._id = `ui5wc_${++autoId}`; | ||
} | ||
@@ -71,37 +70,25 @@ | ||
*/ | ||
_syncContentDensity() { | ||
const isCompact = getCompactSize(); | ||
if (isCompact) { | ||
this.setAttribute("data-ui5-compact-size", ""); | ||
} else { | ||
this.removeAttribute("data-ui5-compact-size"); | ||
} | ||
} | ||
_initializeContainers() { | ||
const needsShadowDOM = this.constructor._needsShadowDOM(); | ||
const needsStaticArea = this.constructor._needsStaticArea(); | ||
/** | ||
* @private | ||
*/ | ||
_generateId() { | ||
this._id = this.constructor._nextID(); | ||
} | ||
// Init Shadow Root | ||
if (needsShadowDOM) { | ||
this.attachShadow({ mode: "open" }); | ||
/** | ||
* @private | ||
*/ | ||
_initializeShadowRoot() { | ||
if (!this.constructor._needsShadowDOM()) { | ||
return; | ||
} | ||
// IE11, Edge | ||
if (window.ShadyDOM) { | ||
createComponentStyleTag(this.constructor); | ||
} | ||
this.attachShadow({ mode: "open" }); | ||
// IE11, Edge | ||
if (window.ShadyDOM) { | ||
createHeadStyle(this.constructor); | ||
// Chrome | ||
if (document.adoptedStyleSheets) { | ||
const style = getConstructableStyle(this.constructor); | ||
this.shadowRoot.adoptedStyleSheets = [style]; | ||
} | ||
} | ||
// Chrome | ||
if (document.adoptedStyleSheets) { | ||
const style = getConstructableStyle(this.constructor); | ||
this.shadowRoot.adoptedStyleSheets = [style]; | ||
// Init StaticAreaItem only if needed | ||
if (needsStaticArea) { | ||
this.staticAreaItem = new StaticAreaItem(this); | ||
} | ||
@@ -115,16 +102,24 @@ } | ||
async connectedCallback() { | ||
this._syncContentDensity(); | ||
const needsShadowDOM = this.constructor._needsShadowDOM(); | ||
const needsStaticArea = this.constructor._needsStaticArea(); | ||
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged(); | ||
if (!this.constructor._needsShadowDOM()) { | ||
return; | ||
// Render the Shadow DOM | ||
if (needsShadowDOM) { | ||
if (slotsAreManaged) { | ||
// always register the observer before yielding control to the main thread (await) | ||
this._startObservingDOMChildren(); | ||
await this._processChildren(); | ||
} | ||
await RenderScheduler.renderImmediately(this); | ||
this._domRefReadyPromise._deferredResolve(); | ||
if (typeof this.onEnterDOM === "function") { | ||
this.onEnterDOM(); | ||
} | ||
} | ||
// always register the observer before yielding control to the main thread (await) | ||
this._startObservingDOMChildren(); | ||
await this._processChildren(); | ||
await RenderScheduler.renderImmediately(this); | ||
this._domRefReadyPromise._deferredResolve(); | ||
if (typeof this.onEnterDOM === "function") { | ||
this.onEnterDOM(); | ||
// Render Fragment if neccessary | ||
if (needsStaticArea) { | ||
this.staticAreaItem._updateFragment(this); | ||
} | ||
@@ -138,9 +133,18 @@ } | ||
disconnectedCallback() { | ||
if (!this.constructor._needsShadowDOM()) { | ||
return; | ||
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") { | ||
this.onExitDOM(); | ||
} | ||
} | ||
this._stopObservingDOMChildren(); | ||
if (typeof this.onExitDOM === "function") { | ||
this.onExitDOM(); | ||
if (needsStaticArea) { | ||
this.staticAreaItem._removeFragmentFromStaticArea(); | ||
} | ||
@@ -157,5 +161,7 @@ } | ||
} | ||
const canSlotText = this.constructor.getMetadata().canSlotText(); | ||
const mutationObserverOptions = { | ||
childList: true, | ||
subtree: true, | ||
subtree: canSlotText, | ||
characterData: true, | ||
@@ -189,3 +195,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); | ||
@@ -195,3 +201,3 @@ | ||
for (const [slotName, slotData] of Object.entries(slotsMap)) { // eslint-disable-line | ||
this._clearSlot(slotName); | ||
this._clearSlot(slotName, slotData); | ||
} | ||
@@ -216,5 +222,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}`; | ||
} | ||
@@ -230,3 +236,7 @@ | ||
const whenDefinedPromise = window.customElements.whenDefined(localName); // Class registered, but instances not upgraded yet | ||
const timeoutPromise = new Promise(resolve => setTimeout(resolve, 1000)); | ||
let timeoutPromise = elementTimeouts.get(localName); | ||
if (!timeoutPromise) { | ||
timeoutPromise = new Promise(resolve => setTimeout(resolve, 1000)); | ||
elementTimeouts.set(localName, timeoutPromise); | ||
} | ||
await Promise.race([whenDefinedPromise, timeoutPromise]); | ||
@@ -240,4 +250,4 @@ } | ||
if (child.isUI5Element) { | ||
this._attachChildPropertyUpdated(child, slotData); | ||
if (child.isUI5Element && slotData.listenFor) { | ||
this._attachChildPropertyUpdated(child, slotData.listenFor); | ||
} | ||
@@ -261,3 +271,3 @@ | ||
}); | ||
this._invalidate(); | ||
this._invalidate("slots"); | ||
} | ||
@@ -269,4 +279,3 @@ | ||
*/ | ||
_clearSlot(slotName) { | ||
const slotData = this.constructor.getMetadata().getSlots()[slotName]; | ||
_clearSlot(slotName, slotData) { | ||
const propertyName = slotData.propertyName || slotName; | ||
@@ -364,5 +373,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 | ||
@@ -374,6 +382,2 @@ childProperties = childMetadata.getProperties(); | ||
if (!listenFor) { | ||
return; | ||
} | ||
if (Array.isArray(listenFor)) { | ||
@@ -391,2 +395,3 @@ observedProps = listenFor; | ||
child.addEventListener("_propertyChange", this._invalidateParentOnPropertyUpdate); | ||
child._firePropertyChange = true; | ||
} | ||
@@ -399,2 +404,3 @@ | ||
child.removeEventListener("_propertyChange", this._invalidateParentOnPropertyUpdate); | ||
child._firePropertyChange = false; | ||
} | ||
@@ -408,9 +414,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, | ||
})); | ||
} | ||
} | ||
@@ -446,3 +452,3 @@ | ||
_invalidate() { | ||
if (this._invalidated) { | ||
if (!this._upToDate) { | ||
// console.log("already invalidated", this, ...arguments); | ||
@@ -453,3 +459,3 @@ return; | ||
if (this.getDomRef() && !this._suppressInvalidation) { | ||
this._invalidated = true; | ||
this._upToDate = false; | ||
// console.log("INVAL", this, ...arguments); | ||
@@ -465,2 +471,4 @@ RenderScheduler.renderDeferred(this); | ||
_render() { | ||
const hasIndividualSlots = this.constructor.getMetadata().hasIndividualSlots(); | ||
// suppress invalidation to prevent state changes scheduling another rendering | ||
@@ -474,3 +482,5 @@ this._suppressInvalidation = true; | ||
// Intended for framework usage only. Currently ItemNavigation updates tab indexes after the component has updated its state but before the template is rendered | ||
this.dispatchEvent(new CustomEvent("_componentStateFinalized")); | ||
if (this._onComponentStateFinalized) { | ||
this._onComponentStateFinalized(); | ||
} | ||
@@ -482,7 +492,13 @@ // resume normal invalidation handling | ||
// console.log(this.getDomRef() ? "RE-RENDER" : "FIRST RENDER", this); | ||
delete this._invalidated; | ||
this._upToDate = true; | ||
this._updateShadowRoot(); | ||
if (this.constructor._needsStaticArea()) { | ||
this.staticAreaItem._updateFragment(this); | ||
} | ||
// 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(); | ||
} | ||
@@ -624,2 +640,12 @@ // Call the onAfterRendering hook | ||
get isCompact() { | ||
return getComputedStyle(this).getPropertyValue(GLOBAL_CONTENT_DENSITY_CSS_VAR) === "compact"; | ||
} | ||
updateStaticAreaItemContentDensity() { | ||
if (this.staticAreaItem) { | ||
this.staticAreaItem._updateContentDensity(this.isCompact); | ||
} | ||
} | ||
/** | ||
@@ -643,17 +669,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) { | ||
@@ -686,2 +699,16 @@ // Text nodes can only go to the default slot | ||
*/ | ||
static _needsStaticArea() { | ||
return typeof this.staticAreaTemplate === "function"; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
getStaticAreaItemDomRef() { | ||
return this.staticAreaItem.getDomRef(); | ||
} | ||
/** | ||
* @private | ||
*/ | ||
static _getDefaultState() { | ||
@@ -694,2 +721,3 @@ if (this._defaultState) { | ||
const defaultState = {}; | ||
const slotsAreManaged = MetadataClass.slotsAreManaged(); | ||
@@ -720,6 +748,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] = []; | ||
} | ||
} | ||
@@ -736,2 +766,3 @@ | ||
const proto = this.prototype; | ||
const slotsAreManaged = this.getMetadata().slotsAreManaged(); | ||
@@ -782,20 +813,22 @@ // Properties | ||
// 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"); | ||
}, | ||
}); | ||
} | ||
@@ -827,2 +860,7 @@ } | ||
await boot(); | ||
if (this.onDefine) { | ||
await this.onDefine(); | ||
} | ||
const tag = this.getMetadata().getTag(); | ||
@@ -829,0 +867,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 | ||
@@ -105,10 +130,2 @@ * @public | ||
} | ||
/** | ||
* Determines whether this UI5 Element invalidates automatically when content density changes | ||
* @public | ||
*/ | ||
getInvalidateOnContentDensityChange() { | ||
return !!this.metadata.invalidateOnContentDensityChange; | ||
} | ||
} | ||
@@ -115,0 +132,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 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
Sorry, the diff of this file is not supported yet
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
4
44296
4082104
267
15067
7
13
2
110
- Removed@ui5/webcomponents-utils@0.0.0-04e3a6f74(transitive)