diff --git a/.tooling/eleventy/assets/css/style.css b/.tooling/eleventy/assets/css/style.css index c75599a7f..2c193df9e 100644 --- a/.tooling/eleventy/assets/css/style.css +++ b/.tooling/eleventy/assets/css/style.css @@ -425,6 +425,7 @@ header .header-version-select { --omni-select-control-padding: 0px 4px 0px 0px; --omni-form-clear-control-width: 0px; --omni-select-items-container-width: auto; + --omni-select-field-height: 100%; } .docs-select { @@ -598,6 +599,7 @@ h2 { .static-article code:not([class]), .story-description code:not([class]), +.component-tab#docs code:not([class]), .keyboard-showcase code:not([class]) { font-family: ui-monospace, monospace; font-size: 14px; @@ -605,6 +607,7 @@ h2 { .static-article code:not([class]), .story-description code:not([class]), +.component-tab#docs code:not([class]), .keyboard-showcase code:not([class]) { padding: 2px 6px; margin: 0; diff --git a/.tooling/eleventy/components.njk b/.tooling/eleventy/components.njk index 3bcc08a33..2857ec4fe 100644 --- a/.tooling/eleventy/components.njk +++ b/.tooling/eleventy/components.njk @@ -127,6 +127,66 @@ eleventyComputed: {% endif %} + {% set instanceFuncs = customElements | getInstanceFunctions(component.name) %} + {% if instanceFuncs.length > 0 %} +

Instance Functions

+ {#
+ +
#} +
+ + + + + + + + + + + {% for f in instanceFuncs %} + + + + + + + {% endfor %} + +
NameParametersReturnsDescription
{{f.name}}
{{ f.parameters }}
{{ f.returnType }}
{{ f.description | safe }}
+
+ {% endif %} + + {% set staticFuncs = customElements | getStaticFunctions(component.name) %} + {% if staticFuncs.length > 0 %} +

Static Functions

+ {#
+ +
#} +
+ + + + + + + + + + + {% for f in staticFuncs %} + + + + + + + {% endfor %} + +
NameParametersReturnsDescription
{{f.name}}
{{ f.parameters }}
{{ f.returnType }}
{{ f.description | safe }}
+
+ {% endif %} + {% set globalAttributes = customElements | getGlobalAttributes(component.name) %} {% if globalAttributes.length > 0 %}

Supported Global Attributes

diff --git a/.tooling/scripts/eleventy/filters.js b/.tooling/scripts/eleventy/filters.js index efacea1af..5cc132958 100644 --- a/.tooling/scripts/eleventy/filters.js +++ b/.tooling/scripts/eleventy/filters.js @@ -44,6 +44,61 @@ export function getProperties(value, componentName) { }); } +function convertToParameterString(parametersList) { + let parameters = ''; + + if (!parametersList || parametersList.length === 0) { + return parameters; + } + + parametersList.forEach(p => { + if (parameters) { + parameters += ',\r\n'; + } + if (!p.type) { + console.log(p); + } + + parameters += `${p.name} - ${p.type.text}` + }); + + return parameters; +} + +export function getInstanceFunctions(value, componentName) { + const declaration = getComponentDeclaration(value, componentName); + return declaration.members?.filter(m => m.kind === 'method' && + m.privacy !== 'private' && + m.privacy !== 'protected' && + m.description && + m.static?.toString() !== 'true' && + !m.name.startsWith('_'))?.map(a => { + return { + ...a, + parameters: convertToParameterString(a.parameters), + description: transformFromJsdoc(a.description), + returnType: a.return?.type?.text ?? '' + }; + }); +} + +export function getStaticFunctions(value, componentName) { + const declaration = getComponentDeclaration(value, componentName); + return declaration.members?.filter(m => m.kind === 'method' && + m.privacy !== 'private' && + m.privacy !== 'protected' && + m.description && + m.static?.toString() === 'true' && + !m.name.startsWith('_'))?.map(a => { + return { + ...a, + parameters: convertToParameterString(a.parameters), + description: transformFromJsdoc(a.description), + returnType: a.return?.type?.text ?? '' + }; + }); +} + export function getGlobalAttributes(value, componentName) { const declaration = getComponentDeclaration(value, componentName); return declaration.globalAttributes?.map(a => { @@ -110,8 +165,8 @@ export function getCSSProperties(value, componentName) { } export function splitPascalCase(word) { - var wordRe = /($[a-z])|[A-Z][^A-Z]+/g; - return word.match(wordRe).join(' '); + var wordRe = /($[a-z])|[A-Z][^A-Z]+/g; + return word.match(wordRe).join(' '); } function distinct(value, index, self) { diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..65e27327f Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..14cfb68f8 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..168154ea6 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..3467626a0 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..5ca9ea57e Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Center-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..daf0fe651 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..2c5930035 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..fb627d739 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..53b31435b Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..c1f750a86 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Left-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..06b6b5e5e Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..e36920abd Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..d783f23cd Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..dccc39022 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..3dc00a295 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Right-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..8a90d2a11 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..8f24547b0 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..493b9aa79 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..49fecfe01 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..10baca7c9 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Action-Align-Stretch-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..45466be68 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..060bd91ed Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..ac5222084 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..4def61080 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..7d879751a Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Body-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..17ad1eb2f Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..6aca33d85 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..2e31231b6 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..1d4d0cb15 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..e6de512b6 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Header-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..e1ebe0fb9 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..66bdc4a92 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..275deb16e Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..416a5f228 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..59bace9aa Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Primary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..a54470ae4 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..a8f4a9628 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..1ef0608df Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..5c563db10 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..6f639708b Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Secondary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..e1c6ccff5 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..800db3ec2 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..75fddcdf1 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..756cd5eaf Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..c023b770f Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Custom-Status-Indicator-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..5fbf68a42 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..5f3a93a99 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..84c10661f Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..4a8d90daa Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..3cdef2244 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Center-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..80ae0503d Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..5ebe33389 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..19fae69e3 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..33734962b Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..062fb4aef Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Left-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..73f8cdb1c Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..89244a5f4 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..ff0e38583 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..735963303 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..0864ab9ce Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Description-Align-Right-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..5ad408f62 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..95093eaf5 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..5717fb1ab Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..110e201c0 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..94ea08ff2 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Error-Status-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..093e0b397 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..3729ea461 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..5bf65483e Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..32acba706 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..143a5981a Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Center-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..f92ba02c5 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..1b3d1b241 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..5c161c344 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..101d9c752 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..e02b2473d Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Left-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..5ade225ff Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..1bdc796c8 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..dcc66b0fe Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..66dd63b18 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..4ae1706b6 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Header-Align-Right-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..99cebc917 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..b3e69fbf0 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..5891787cc Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..66016ca1c Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..05b90d0dd Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Info-Status-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..4a1bd4c27 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..8f14a7ea7 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..a2624da1f Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..60364f52b Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..09f9ecb07 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Primary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..a7adbb784 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..654715d33 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..721985cc1 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..4b3b2e7d1 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..7409afae4 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Secondary-Action-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..542019b32 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..20320caf0 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..83bf56124 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..76748d7f0 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..d2bb63bb8 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Auto-/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..542019b32 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..20320caf0 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..83bf56124 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..76748d7f0 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..d2bb63bb8 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Primary-/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..542019b32 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..20320caf0 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..83bf56124 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..76748d7f0 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..d2bb63bb8 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Async-Behaviour-Secondary-/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..d4065d54d Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..5c562ca1a Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..cbb47b63a Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..6351bde72 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..6945a4530 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Show-Behaviour/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..22179ca3f Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..17b59fa6d Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..a96e63aaa Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..afa4d0a09 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..9b63c6172 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Success-Status-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..093e0b397 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..3729ea461 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..5bf65483e Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..32acba706 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..143a5981a Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Visual-and-Behaviour/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png new file mode 100644 index 000000000..f226694cb Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/Mobile-Chrome/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png new file mode 100644 index 000000000..7ca590220 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/Mobile-Safari/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/chromium/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/chromium/alert-modal-dialog-open.png new file mode 100644 index 000000000..683e1af24 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/chromium/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/firefox/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/firefox/alert-modal-dialog-open.png new file mode 100644 index 000000000..1b77997b2 Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/firefox/alert-modal-dialog-open.png differ diff --git a/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/webkit/alert-modal-dialog-open.png b/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/webkit/alert-modal-dialog-open.png new file mode 100644 index 000000000..c47f05fab Binary files /dev/null and b/.tooling/tests/screenshots/Alert---Warning-Status-Visual/darwin/webkit/alert-modal-dialog-open.png differ diff --git a/.vscode/settings.json b/.vscode/settings.json index 1e6c35846..d1d050a7f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -44,6 +44,7 @@ "keyboard": true, "modal": true, "tab": true, - "toast": true + "toast": true, + "alert": true } } \ No newline at end of file diff --git a/README.md b/README.md index a4c649e9f..73e2ef4a8 100644 --- a/README.md +++ b/README.md @@ -183,175 +183,183 @@ This example shows how to import and use a few common components. Omni Component
Tag NameDescription
-[omni-button](src/button/README.md) +[omni-loading-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Control that allows an action to be executed. +Loading icon component.
-[omni-calendar](src/calendar/README.md) +[omni-render-element](/Users/runner/work/omni-components/omni-components/src/render-element/README.md) -Calendar component to set specific date. +Element that defers content rendering to a provided function / promise.
-[omni-check](src/check/README.md) +[omni-modal](/Users/runner/work/omni-components/omni-components/src/modal/README.md) -Control that allows a selection to be made. +Control to display modal content with optional header and footer content.
-[omni-chip](src/chip/README.md) +[omni-button](/Users/runner/work/omni-components/omni-components/src/button/README.md) -Control that can be used for input, setting attributes, or performing actions. +Control that allows an action to be executed.
-[omni-color-field](src/color-field/README.md) +[omni-alert](/Users/runner/work/omni-components/omni-components/src/alert/README.md) -Color input control. +Component that displays an alert.
-[omni-currency-field](src/currency-field/README.md) +[omni-clear-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Control to enter a formatted currency value. +Clear icon component.
-[omni-date-picker](src/date-picker/README.md) +[omni-search-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Control to get / set a specific date using a calendar. +Search icon component.
-[omni-email-field](src/email-field/README.md) +[omni-search-field](/Users/runner/work/omni-components/omni-components/src/search-field/README.md) -Email input control, used in forms for input validation and to display correct virtual keyboard on mobile. +Search input control.
-[omni-hyperlink](src/hyperlink/README.md) +[omni-chevron-down-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Control to indicate an action to be executed. Typically used for navigational purposes. +Chevron down icon component.
-[omni-icon](src/icon/README.md) +[omni-more-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Component that displays an icon. +More icon component.
-[omni-arrow-right-icon](src/icons/README.md) +[omni-select](/Users/runner/work/omni-components/omni-components/src/select/README.md) -Arrow right icon component. +Control to get / set a value within a list of options.
-[omni-backspace-icon](src/icons/README.md) +[omni-icon](/Users/runner/work/omni-components/omni-components/src/icon/README.md) -Backspace icon component. +Component that displays an icon.
-[omni-calendar-icon](src/icons/README.md) +[omni-color-field](/Users/runner/work/omni-components/omni-components/src/color-field/README.md) -A calendar icon component. +Color input control.
-[omni-caps-lock-icon](src/icons/README.md) +[omni-text-field](/Users/runner/work/omni-components/omni-components/src/text-field/README.md) -Caps lock icon component. +Control to input text.
-[omni-caps-off-icon](src/icons/README.md) +[omni-label](/Users/runner/work/omni-components/omni-components/src/label/README.md) -Caps off icon component. +Label component that renders styled text.
-[omni-caps-on-icon](src/icons/README.md) +[omni-switch](/Users/runner/work/omni-components/omni-components/src/switch/README.md) -Caps on icon component. +Control to switch a value on or off.
-[omni-check-icon](src/icons/README.md) +[omni-chevron-left-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Check icon component. +Chevron left icon component.
-[omni-chevron-down-icon](src/icons/README.md) +[omni-chevron-right-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Chevron down icon component. +Chevron right icon component.
-[omni-chevron-left-icon](src/icons/README.md) +[omni-calendar](/Users/runner/work/omni-components/omni-components/src/calendar/README.md) -Chevron left icon component. +Calendar component to set specific date.
-[omni-chevron-right-icon](src/icons/README.md) +[omni-indeterminate-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Chevron right icon component. +Indeterminate icon component.
-[omni-clear-icon](src/icons/README.md) +[omni-check-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Clear icon component. +Check icon component. + +
+ +[omni-check](/Users/runner/work/omni-components/omni-components/src/check/README.md) + + + +Control that allows a selection to be made.
-[omni-close-icon](src/icons/README.md) +[omni-close-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) @@ -359,231 +367,231 @@ Close icon component.
-[omni-eye-hidden-icon](src/icons/README.md) +[omni-chip](/Users/runner/work/omni-components/omni-components/src/chip/README.md) -Hidden eye icon component +Control that can be used for input, setting attributes, or performing actions.
-[omni-eye-visible-icon](src/icons/README.md) +[omni-arrow-right-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Visible eye icon component. +Arrow right icon component.
-[omni-indeterminate-icon](src/icons/README.md) +[omni-backspace-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Indeterminate icon component. +Backspace icon component.
-[omni-loading-icon](src/icons/README.md) +[omni-caps-off-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Loading icon component. +Caps off icon component.
-[omni-lock-closed-icon](src/icons/README.md) +[omni-caps-on-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Closed lock icon component. +Caps on icon component.
-[omni-lock-open-icon](src/icons/README.md) +[omni-caps-lock-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Open lock icon component. +Caps lock icon component.
-[omni-minus-icon](src/icons/README.md) +[omni-next-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Minus icon component. +Next icon component.
-[omni-more-icon](src/icons/README.md) +[omni-previous-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -More icon component. +Previous icon component.
-[omni-next-icon](src/icons/README.md) +[omni-send-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Next icon component. +Send icon component.
-[omni-plus-icon](src/icons/README.md) +[omni-keyboard-button](/Users/runner/work/omni-components/omni-components/src/keyboard/README.md) -Plus icon component. +An internal keyboard button control used in the keyboard component.
-[omni-previous-icon](src/icons/README.md) +[omni-keyboard](/Users/runner/work/omni-components/omni-components/src/keyboard/README.md) -Previous icon component. +A responsive on-screen keyboard control component.
-[omni-search-icon](src/icons/README.md) +[omni-currency-field](/Users/runner/work/omni-components/omni-components/src/currency-field/README.md) -Search icon component. +Control to enter a formatted currency value.
-[omni-send-icon](src/icons/README.md) +[omni-calendar-icon](/Users/runner/work/omni-components/omni-components/src/icons/README.md) -Send icon component. +A calendar icon component.
-[omni-keyboard](src/keyboard/README.md) +[omni-date-picker](/Users/runner/work/omni-components/omni-components/src/date-picker/README.md) -A responsive on-screen keyboard control component. +Control to get / set a specific date using a calendar.
-[omni-keyboard-button](src/keyboard/README.md) +[omni-email-field](/Users/runner/work/omni-components/omni-components/src/email-field/README.md) -An internal keyboard button control used in the keyboard component. +Email input control, used in forms for input validation and to display correct virtual keyboard on mobile.
-[omni-label](src/label/README.md) +[omni-hyperlink](/Users/runner/work/omni-components/omni-components/src/hyperlink/README.md) -Label component that renders styled text. +Control to indicate an action to be executed. Typically used for navigational purposes.
-[omni-modal](src/modal/README.md) +[omni-eye-hidden-icon](src/icons/README.md) -Control to display modal content with optional header and footer content. +Hidden eye icon component
-[omni-number-field](src/number-field/README.md) +[omni-eye-visible-icon](src/icons/README.md) -Input control to enter a single line of numbers. +Visible eye icon component.
-[omni-password-field](src/password-field/README.md) +[omni-lock-closed-icon](src/icons/README.md) -Password input control. +Closed lock icon component.
-[omni-pin-field](src/pin-field/README.md) +[omni-lock-open-icon](src/icons/README.md) -Input control to enter a masked numeric value. +Open lock icon component.
-[omni-radio](src/radio/README.md) +[omni-minus-icon](src/icons/README.md) -Control to select a single value from a group of values. +Minus icon component.
-[omni-radio-group](src/radio/README.md) +[omni-plus-icon](src/icons/README.md) -Control to group radio components for single selection +Plus icon component.
-[omni-render-element](src/render-element/README.md) +[omni-number-field](/Users/runner/work/omni-components/omni-components/src/number-field/README.md) -Element that defers content rendering to a provided function / promise. +Input control to enter a single line of numbers.
-[omni-search-field](src/search-field/README.md) +[omni-password-field](/Users/runner/work/omni-components/omni-components/src/password-field/README.md) -Search input control. +Password input control.
-[omni-select](src/select/README.md) +[omni-pin-field](/Users/runner/work/omni-components/omni-components/src/pin-field/README.md) -Control to get / set a value within a list of options. +Input control to enter a masked numeric value.
-[omni-switch](src/switch/README.md) +[omni-radio](/Users/runner/work/omni-components/omni-components/src/radio/README.md) -Control to switch a value on or off. +Control to select a single value from a group of values.
-[omni-tab](src/tab/README.md) +[omni-radio-group](/Users/runner/work/omni-components/omni-components/src/radio/README.md) -Control that can be used to display slotted content, for use within an Tab Group component. +Control to group radio components for single selection
-[omni-tab-group](src/tab/README.md) +[omni-tab](/Users/runner/work/omni-components/omni-components/src/tab/README.md) -Component that displays content in tabs. +Control that can be used to display slotted content, for use within an Tab Group component.
-[omni-tab-header](src/tab/README.md) +[omni-tab-header](/Users/runner/work/omni-components/omni-components/src/tab/README.md) @@ -591,27 +599,27 @@ Control that can be used to display custom slotted content, for use within Tab G
-[omni-text-field](src/text-field/README.md) +[omni-tab-group](/Users/runner/work/omni-components/omni-components/src/tab/README.md) -Control to input text. +Component that displays content in tabs.
-[omni-toast](src/toast/README.md) +[omni-toast-stack](/Users/runner/work/omni-components/omni-components/src/toast/README.md) -Component to visually notify a user of a message. +A toast container that animates in and stacks toast elements.
-[omni-toast-stack](src/toast/README.md) +[omni-toast](/Users/runner/work/omni-components/omni-components/src/toast/README.md) -A toast container that animates in and stacks toast elements. +Component to visually notify a user of a message.
diff --git a/custom-elements-manifest.config.js b/custom-elements-manifest.config.js index ba47ce265..ee95f3946 100644 --- a/custom-elements-manifest.config.js +++ b/custom-elements-manifest.config.js @@ -1,6 +1,21 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable no-case-declarations */ +import { readFileSync } from 'fs'; + +let typeChecker; const plugins = { + // Setup our own module creation in order to track a global type checker for documentation enrichment + overrideModuleCreation: ({ ts, globs }) => { + const tsconfig = JSON.parse(readFileSync('./tsconfig.json')); + const program = ts.createProgram(globs, { + ...tsconfig.compilerOptions, + moduleResolution: tsconfig.compilerOptions.moduleResolution === 'classic' ? ts.ModuleResolutionKind.Classic : ts.ModuleResolutionKind.NodeJs, + }); + + typeChecker = program.getTypeChecker(); + + return program.getSourceFiles().filter(sf => globs.find(glob => sf.fileName.includes(glob))); + }, plugins: [ function ignorePlugin() { return { @@ -362,6 +377,132 @@ const plugins = { } }; }(), + function inferMethodReturnTypesPlugin() { + return { + analyzePhase({ ts, node, moduleDoc }) { + switch (node.kind) { + // case ts.SyntaxKind.PropertyDeclaration: + // { + // if (node.initializer && node.initializer.kind === ts.SyntaxKind.ArrowFunction) { + // const funcName = node.name.getText(); + // const isStatic = Boolean(node.initializer.modifiers?.find(m => m.kind === ts.SyntaxKind.StaticKeyword)); + // const classNode = findParentClass(ts, node); + // if (classNode) { + // const className = classNode.name.getText(); + // const classDeclaration = moduleDoc.declarations.find(declaration => declaration.name === className); + + // const method = classDeclaration.members.find(m => m.name === funcName && m.kind === 'field' && ((m.static && isStatic) || (!m.static && !isStatic))); + // if (method && !method.return?.type?.text) { + // const ret = { + // ...(method.return || {}), + // type: { + // ...(method.return?.type || {}), + // // Use Typescript type checker to read inferred type as text. + // // https://stackoverflow.com/questions/75865839/extract-inferred-return-type-with-typescript-api + // // https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#using-the-type-checker + // text: typeChecker.typeToString(typeChecker.getSignatureFromDeclaration(node.initializer).getReturnType()) + // } + // }; + // method.return = ret; + // } + // } + // } + // } + // break; + case ts.SyntaxKind.MethodDeclaration: + { + const funcName = node.name.getText(); + const isStatic = Boolean(node.modifiers?.find(m => m.kind === ts.SyntaxKind.StaticKeyword)); + const classNode = findParentClass(ts, node); + if (classNode) { + const className = classNode.name.getText(); + const classDeclaration = moduleDoc.declarations.find(declaration => declaration.name === className); + + const method = classDeclaration.members.find(m => m.name === funcName && m.kind === 'method' && ((m.static && isStatic) || (!m.static && !isStatic))); + if (method && !method.return?.type?.text) { + const ret = { + ...(method.return || {}), + type: { + ...(method.return?.type || {}), + // Use Typescript type checker to read inferred type as text. + // https://stackoverflow.com/questions/75865839/extract-inferred-return-type-with-typescript-api + // https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#using-the-type-checker + text: typeChecker.typeToString(typeChecker.getSignatureFromDeclaration(node).getReturnType()) + } + }; + method.return = ret; + } + } + } + + break; + } + }, + moduleLinkPhase({ moduleDoc }) { + // console.log(moduleDoc); + }, + packageLinkPhase({ customElementsManifest }) { + // console.log(customElementsManifest); + } + }; + }(), + function inferFunctionReturnTypesPlugin() { + return { + analyzePhase({ ts, node, moduleDoc }) { + switch (node.kind) { + case ts.SyntaxKind.VariableDeclaration: + { + if (node.initializer && node.initializer.kind === ts.SyntaxKind.ArrowFunction) { + const funcName = node.name.getText(); + const isStatic = Boolean(node.initializer.modifiers?.find(m => m.kind === ts.SyntaxKind.StaticKeyword)); + const functionDeclaration = moduleDoc.declarations.find(m => m.name === funcName && m.kind === 'function' && ((m.static && isStatic) || (!m.static && !isStatic))); + if (functionDeclaration && !functionDeclaration.return?.type?.text) { + const ret = { + ...(functionDeclaration.return || {}), + type: { + ...(functionDeclaration.return?.type || {}), + // Use Typescript type checker to read inferred type as text. + // https://stackoverflow.com/questions/75865839/extract-inferred-return-type-with-typescript-api + // https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#using-the-type-checker + text: typeChecker.typeToString(typeChecker.getSignatureFromDeclaration(node.initializer).getReturnType()) + } + }; + functionDeclaration.return = ret; + } + } + } + break; + case ts.SyntaxKind.FunctionDeclaration: + { + const funcName = node.name.getText(); + const isStatic = Boolean(node.modifiers?.find(m => m.kind === ts.SyntaxKind.StaticKeyword)); + const functionDeclaration = moduleDoc.declarations.find(m => m.name === funcName && m.kind === 'function' && ((m.static && isStatic) || (!m.static && !isStatic))); + if (functionDeclaration && !functionDeclaration.return?.type?.text) { + const ret = { + ...(functionDeclaration.return || {}), + type: { + ...(functionDeclaration.return?.type || {}), + // Use Typescript type checker to read inferred type as text. + // https://stackoverflow.com/questions/75865839/extract-inferred-return-type-with-typescript-api + // https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#using-the-type-checker + text: typeChecker.typeToString(typeChecker.getSignatureFromDeclaration(node).getReturnType()) + } + }; + functionDeclaration.return = ret; + } + } + + break; + } + }, + moduleLinkPhase({ moduleDoc }) { + // console.log(moduleDoc); + }, + packageLinkPhase({ customElementsManifest }) { + // console.log(customElementsManifest); + } + }; + }(), function storyDescriptionPlugin() { return { // Runs for each module diff --git a/package-lock.json b/package-lock.json index fff6b7b5d..313769ca3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@capitec/omni-components", - "version": "0.8.2", + "version": "0.8.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@capitec/omni-components", - "version": "0.8.2", + "version": "0.8.3", "license": "MIT", "dependencies": { "lit": "^2.3.1", diff --git a/package.json b/package.json index a7f668148..170e78671 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@capitec/omni-components", - "version": "0.8.2", + "version": "0.8.3", "type": "module", "description": "Modern UI component library for mobile and web", "scripts": { @@ -72,7 +72,8 @@ "keyboard", "modal", "toast", - "tab" + "tab", + "alert" ], "exports": { "./*": "./dist/*/index.js" diff --git a/playwright.config.js b/playwright.config.js index fdf10a62d..14dbd44f7 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -55,7 +55,7 @@ const config = { // baseURL: 'http://localhost:3000', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', + trace: process.env.PW_TEST_FORCE_TRACE ? 'on' : 'on-first-retry', userAgent: 'Test Runner', baseURL: `http://${process.env.PLAYWRIGHT_HOST_ORIGIN ?? 'localhost'}:6006`, diff --git a/src/alert/Alert.spec.ts b/src/alert/Alert.spec.ts new file mode 100644 index 000000000..47e7caa28 --- /dev/null +++ b/src/alert/Alert.spec.ts @@ -0,0 +1,735 @@ +import { test, expect, mockEventListener, withCoverage, createWaitHandle } from '../utils/JestPlaywright.js'; +import { Alert } from './Alert.js'; + +test(`Alert - Visual and Behaviour`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + const primary = alert.locator('omni-button'); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + + const alertActionClickResponse = createWaitHandle(); + + const alertClose = await mockEventListener(alert, 'alert-close'); + const alertActionClick = await mockEventListener(alert, 'alert-action-click', (e) => { + const actionClickEvent = e as CustomEvent<{ secondary: boolean }>; + alertActionClickResponse.release(actionClickEvent.detail.secondary.toString()); + }); + + await primary.click({ + force: true + }); + + const secondary = await alertActionClickResponse.completed; + + await expect(alertActionClick).toHaveBeenCalled(); + await expect(alertClose).toHaveBeenCalled(); + await expect(secondary).toBe('false'); + }); +}); + +test(`Alert - Success Status Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.status = 'success'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Warning Status Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.status = 'warning'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Error Status Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.status = 'error'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Info Status Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.status = 'info'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Show Behaviour`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + await page.evaluate(async () => { + const AlertType = (await customElements.whenDefined('omni-alert')) as typeof Alert; + AlertType.show({ + id: 'test-show-alert', + status: 'success', + message: 'Success!', + description: 'It was successful.' + }); + }); + + const alert = page.locator('omni-alert#test-show-alert'); + + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + const primary = alert.locator('omni-button'); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + + const alertActionClickResponse = createWaitHandle(); + + const alertClose = await mockEventListener(alert, 'alert-close'); + const alertActionClick = await mockEventListener(alert, 'alert-action-click', (e) => { + const actionClickEvent = e as CustomEvent<{ secondary: boolean }>; + alertActionClickResponse.release(actionClickEvent.detail.secondary.toString()); + }); + + await primary.click({ + force: true + }); + + const secondary = await alertActionClickResponse.completed; + + await expect(alertActionClick).toHaveBeenCalled(); + await expect(alertClose).toHaveBeenCalled(); + await expect(secondary).toBe('false'); + }); +}); + +test(`Alert - Show Async Behaviour (Primary)`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const alertActionClickResponse = page.evaluate(async () => { + const AlertType = (await customElements.whenDefined('omni-alert')) as typeof Alert; + const response = await AlertType.showAsync({ + id: 'test-show-alert', + status: 'success', + message: 'Success!', + enableSecondary: true, + description: 'It was successful.' + }); + + return response; + }); + + const alert = page.locator('omni-alert#test-show-alert'); + + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + const primary = alert.locator('omni-button[type=primary]'); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + + await primary.click({ + force: true + }); + + const response = await alertActionClickResponse; + + await expect(response).toBe('primary'); + }); +}); + +test(`Alert - Show Async Behaviour (Secondary)`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const alertActionClickResponse = page.evaluate(async () => { + const AlertType = (await customElements.whenDefined('omni-alert')) as typeof Alert; + const response = await AlertType.showAsync({ + id: 'test-show-alert', + status: 'success', + message: 'Success!', + enableSecondary: true, + description: 'It was successful.' + }); + + return response; + }); + + const alert = page.locator('omni-alert#test-show-alert'); + + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + const secondary = alert.locator('omni-button[type=secondary]'); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + + await secondary.click({ + force: true + }); + + const response = await alertActionClickResponse; + + await expect(response).toBe('secondary'); + }); +}); + +test(`Alert - Show Async Behaviour (Auto)`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const alertActionClickResponse = page.evaluate(async () => { + const AlertType = (await customElements.whenDefined('omni-alert')) as typeof Alert; + const response = await AlertType.showAsync({ + id: 'test-show-alert', + status: 'success', + message: 'Success!', + enableSecondary: true, + description: 'It was successful.' + }); + + return response; + }); + + const alert = page.locator('omni-alert#test-show-alert'); + + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + + await alert.evaluate((a: Alert) => { + a.hide(); + }); + + const response = await alertActionClickResponse; + + await expect(response).toBe('auto'); + }); +}); + +test(`Alert - Header Align Left Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.headerAlign = 'left'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Header Align Center Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.headerAlign = 'center'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Header Align Right Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.headerAlign = 'right'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Description Align Left Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.descriptionAlign = 'left'; + element.description = `Additional context for the alert. +Aligned to the ${element.descriptionAlign}.`; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Description Align Center Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.descriptionAlign = 'center'; + element.description = `Additional context for the alert. +Aligned to the ${element.descriptionAlign}.`; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Description Align Right Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.descriptionAlign = 'right'; + element.description = `Additional context for the alert. +Aligned to the ${element.descriptionAlign}.`; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Primary Action Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.primaryAction = 'Acknowledge'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Secondary Action Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.enableSecondary = true; + element.secondaryAction = 'Discard'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Action Align Left Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.enableSecondary = true; + element.actionAlign = 'left'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Action Align Center Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.enableSecondary = true; + element.actionAlign = 'center'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Action Align Right Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.enableSecondary = true; + element.actionAlign = 'right'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Action Align Stretch Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Interactive'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await alert.evaluate(async (element: Alert) => { + element.enableSecondary = true; + element.actionAlign = 'stretch'; + await element.updateComplete; + }); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Custom Status Indicator Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Custom_Status_Indicator'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Custom Header Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Custom_Header'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Custom Body Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Custom_Body'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Custom Primary Action Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Custom_Primary_Action'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); + +test(`Alert - Custom Secondary Action Visual`, async ({ page }) => { + await withCoverage(page, async () => { + await page.goto('/components/alert/'); + + const container = page.locator('.Custom_Secondary_Action'); + const alert = container.getByTestId('test-alert'); + const modal = alert.locator('omni-modal'); + const dialog = modal.locator('dialog'); + const modalContainer = dialog.locator('.container').first(); + + const btn = container.getByTestId('test-alert-btn'); + await btn.click(); + + await expect(dialog).toBeVisible(); + await expect(modalContainer).toBeVisible(); + await expect(modal).not.toHaveAttribute('hide', ''); + + await expect(modalContainer).toHaveScreenshot('alert-modal-dialog-open.png'); + }); +}); diff --git a/src/alert/Alert.stories.ts b/src/alert/Alert.stories.ts new file mode 100644 index 000000000..73d5fa760 --- /dev/null +++ b/src/alert/Alert.stories.ts @@ -0,0 +1,1531 @@ +import { html, nothing } from 'lit'; +import { ref } from 'lit/directives/ref.js'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; +import { ifNotEmpty } from '../utils/Directives.js'; +import { assignToSlot, ComponentStoryFormat, CSFIdentifier, getSourceFromLit, raw } from '../utils/StoryUtils.js'; +import { Alert } from './Alert.js'; + +import './Alert.js'; +import '../button/Button.js'; + +export default { + title: 'UI Components/Alert', + component: 'omni-alert' +} as CSFIdentifier; + +export interface Args { + status?: 'success' | 'warning' | 'error' | 'info' | 'none'; + message?: string; + headerAlign?: 'left' | 'center' | 'right'; + description?: string; + descriptionAlign?: 'left' | 'center' | 'right'; + primaryAction?: string; + secondaryAction?: string; + enableSecondary?: boolean; + actionAlign?: 'left' | 'center' | 'right' | 'stretch'; + + /* Slots */ + 'status-indicator': string; + header: string; + '[Default Slot]': string; + primary: string; + secondary: string; + + /* Internal args used by story only. Not applicable to actual component */ + hide?: boolean; +} + +const alertHtml = (args: Args, onElement?: (a?: Alert) => void) => html` + { + if (onElement) { + onElement(a as Alert | undefined); + } + (a as Alert)?.show(); + })} + @alert-close="${() => { + args.hide = true; + document.dispatchEvent( + new CustomEvent('story-renderer-interactive-update', { + bubbles: true, + composed: true + }) + ); + }}" + data-testid="test-alert" + status="${ifNotEmpty(args.status)}" + message="${ifNotEmpty(args.message)}" + header-align="${ifNotEmpty(args.headerAlign)}" + description="${ifNotEmpty(args.description)}" + description-align="${ifNotEmpty(args.descriptionAlign)}" + primary-action="${ifNotEmpty(args.primaryAction)}" + secondary-action="${ifNotEmpty(args.secondaryAction)}" + ?enable-secondary=${args.enableSecondary} + action-align="${ifNotEmpty(args.actionAlign)}" + >${args['status-indicator'] ? html`${'\r\n'}${unsafeHTML(assignToSlot('status-indicator', args['status-indicator']))}` : nothing}${ + args.header ? html`${'\r\n'}${unsafeHTML(assignToSlot('header', args.header))}` : nothing +}${args['[Default Slot]'] ? html`${'\r\n'}${unsafeHTML(args['[Default Slot]'])}` : nothing}${ + args.primary ? html`${'\r\n'}${unsafeHTML(assignToSlot('primary', args.primary))}` : nothing +}${args.secondary ? html`${'\r\n'}${unsafeHTML(assignToSlot('secondary', args.secondary))}` : nothing} + +`; + +export const Interactive: ComponentStoryFormat = { + render: (args: Args) => html` + + ${args.hide ? nothing : alertHtml(args)} + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: `document.querySelector('omni-alert').show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +};` + } + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + document.querySelector('omni-alert').show(); + } +};` + } + } + ], + name: 'Interactive', + args: { + 'status-indicator': '', + header: '', + '[Default Slot]': '', + primary: '', + secondary: '', + + hide: true, + + message: 'Message Alert', + description: 'Additional context for the alert.', + + enableSecondary: undefined, + + status: undefined, + headerAlign: undefined, + descriptionAlign: undefined, + primaryAction: undefined, + secondaryAction: undefined, + actionAlign: undefined + } +}; + +export const Showing_Alerts: ComponentStoryFormat = { + description: () => html` +
+ Alerts can be shown programmatically using the static Alert.show() function. +
+ `, + render: (args: Args) => html` + + + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: raw``, + jsFragment: `import { Alert } from '@capitec/omni-components/alert'; + +document.querySelector('omni-button').addEventListener('click', () => { + Alert.show({ + status: 'success', + message: 'Success!', + description: 'It was successful.', + }); +});` + } + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: raw``, + jsFragment: `import { Alert } from '@capitec/omni-components/alert'; + +window.vueData = { + showAlert: () => { + Alert.show({ + status: 'success', + message: 'Success!', + description: 'It was successful.', + }); + } +};` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: raw``, + jsFragment: `import { Alert } from '@capitec/omni-components/alert'; + +const showAlert = () => { + Alert.show({ + status: 'success', + message: 'Success!', + description: 'It was successful.', + }); +}` + } + }, + { + framework: 'React', + load: (args) => `import { OmniButton } from "@capitec/omni-components-react/button"; +import { Alert } from '@capitec/omni-components-react/alert'; + +const showAlert = () => { + Alert.show({ + status: 'success', + message: 'Success!', + description: 'It was successful.', + }); +}; + +const App = () => ;` + } + ], + name: 'Showing Alert Programmatically', + args: {} +}; + +let reason = ''; +export const Showing_Alerts_Async: ComponentStoryFormat = { + description: () => html` +
+ Alerts can be asynchronously shown and awaited programmatically using the static Alert.showAsync() function. +
+ `, + render: (args: Args) => html` + { + reason = r; + document.dispatchEvent( + new CustomEvent('story-renderer-interactive-update', { + bubbles: true, + composed: true + }) + ); + }); + }}" + > + +
${reason}
+ `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: raw` +
`, + jsFragment: `import { Alert } from '@capitec/omni-components/alert'; + +document.querySelector('omni-button').addEventListener('click', async () => { + const reason = await Alert.showAsync({ + status: 'info', + message: 'Async Alert!', + description: \`Click "Yes" for "primary" reason or "No" for "secondary" reason. +If closed from script via the "hide" function on the Alert instance, the reason would be "auto".\`, + enableSecondary: true, + primaryAction: 'Yes', + secondaryAction: 'No' + }); + document.getElementById('reason').innerHTML = reason; +});` + } + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: raw` +
`, + jsFragment: `import { Alert } from '@capitec/omni-components/alert'; + +window.vueData = { + showAlert: async () => { + const reason = await Alert.showAsync({ + status: 'info', + message: 'Async Alert!', + description: \`Click "Yes" for "primary" reason or "No" for "secondary" reason. + If closed from script via the "hide" function on the Alert instance, the reason would be "auto".\`, + enableSecondary: true, + primaryAction: 'Yes', + secondaryAction: 'No' + }); + document.getElementById('reason').innerHTML = reason; + } +};` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: raw` +
`, + jsFragment: `import { Alert } from '@capitec/omni-components/alert'; + +const showAlert = async () => { + const reason = await Alert.showAsync({ + status: 'info', + message: 'Async Alert!', + description: \`Click "Yes" for "primary" reason or "No" for "secondary" reason. +If closed from script via the "hide" function on the Alert instance, the reason would be "auto".\`, + enableSecondary: true, + primaryAction: 'Yes', + secondaryAction: 'No' + }); + document.getElementById('reason').innerHTML = reason; +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniButton } from "@capitec/omni-components-react/button"; +import { Alert } from '@capitec/omni-components-react/alert'; + +const showAlert = async () => { + const reason = await Alert.showAsync({ + status: 'info', + message: 'Async Alert!', + description: \`Click "Yes" for "primary" reason or "No" for "secondary" reason. +If closed from script via the "hide" function on the Alert instance, the reason would be "auto".\`, + enableSecondary: true, + primaryAction: 'Yes', + secondaryAction: 'No' + }); + document.getElementById('reason').innerHTML = reason; +}; + +const App = () => <> + +
+ ;` + } + ], + name: 'Showing Async Alert Programmatically', + args: {} +}; + +export const Status: ComponentStoryFormat = { + description: () => html` +
+

Set the display status of the <omni-alert>.

+
+ The status attribute supports the following options: +

    +
  • 'success' - Checkmark icon to indicate success.
  • +
  • 'warning' - Yield icon to indicate warning.
  • +
  • 'error' - Exclamation icon to indicate error.
  • +
  • 'info' - Information icon to indicate info.
  • +
  • 'none' - No icon. (Default)
  • +
+ +
+ `, + render: (args: Args) => html` + + ${args.hide ? nothing : alertHtml(args)} + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: `document.querySelector('omni-alert').show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniAlert } from "@capitec/omni-components-react/alert"; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +}; + +const App = () => ;` + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + document.querySelector('omni-alert').show(); + } +};` + } + } + ], + name: 'Status', + args: { + 'status-indicator': '', + header: '', + '[Default Slot]': '', + primary: '', + secondary: '', + + hide: true, + + message: 'Message Alert', + description: 'Additional context for the alert.', + + enableSecondary: undefined, + + status: 'success', + headerAlign: undefined, + descriptionAlign: undefined, + primaryAction: undefined, + secondaryAction: undefined, + actionAlign: undefined + } +}; + +export const Header_Align: ComponentStoryFormat = { + description: () => html`Align header content horizontally (Defaults to 'center').`, + render: (args: Args) => html` + + ${args.hide ? nothing : alertHtml(args)} + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: `document.querySelector('omni-alert').show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniAlert } from "@capitec/omni-components-react/alert"; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +}; + +const App = () => ;` + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + document.querySelector('omni-alert').show(); + } +};` + } + } + ], + name: 'Header Align', + args: { + 'status-indicator': '', + header: '', + '[Default Slot]': '', + primary: '', + secondary: '', + + hide: true, + + message: 'Message Alert', + description: 'Additional context for the alert.', + + enableSecondary: undefined, + + status: undefined, + headerAlign: 'left', + descriptionAlign: undefined, + primaryAction: undefined, + secondaryAction: undefined, + actionAlign: undefined + } +}; + +export const Description_Align: ComponentStoryFormat = { + description: () => html`Align description content horizontally (Defaults to 'center').`, + render: (args: Args) => html` + + ${ + args.hide + ? nothing + : alertHtml(args, (a) => { + if (a) { + a.description = `Additional context for the alert. +Aligned to the ${args.descriptionAlign}.`; + } + }) + } + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: (args) => `const alert = document.querySelector('omni-alert'); +alert.description = \`Additional context for the alert. +Aligned to the ${args.descriptionAlign}.\`; + +alert.show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: (args) => `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.description = \`Additional context for the alert. +Aligned to the ${args.descriptionAlign}.\`; + + omniAlert.show(); + } +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniAlert } from "@capitec/omni-components-react/alert"; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.description = \`Additional context for the alert. +Aligned to the ${args.descriptionAlign}.\`; + + omniAlert.show(); + } +}; + +const App = () => ;` + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: (args) => `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + + const alert = document.querySelector('omni-alert'); + alert.description = \`Additional context for the alert. +Aligned to the ${args.descriptionAlign}.\`; + + alert.show(); + } +};` + } + } + ], + name: 'Header Align', + args: { + 'status-indicator': '', + header: '', + '[Default Slot]': '', + primary: '', + secondary: '', + + hide: true, + + message: 'Message Alert', + description: undefined, + + enableSecondary: undefined, + + status: undefined, + headerAlign: undefined, + descriptionAlign: 'right', + primaryAction: undefined, + secondaryAction: undefined, + actionAlign: undefined + } +}; + +export const Primary_Action: ComponentStoryFormat = { + description: () => html`Set the label for the primary action button (Defaults to 'Ok').`, + render: (args: Args) => html` + + ${args.hide ? nothing : alertHtml(args)} + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: `document.querySelector('omni-alert').show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniAlert } from "@capitec/omni-components-react/alert"; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +}; + +const App = () => ;` + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + document.querySelector('omni-alert').show(); + } +};` + } + } + ], + name: 'Primary Action', + args: { + 'status-indicator': '', + header: '', + '[Default Slot]': '', + primary: '', + secondary: '', + + hide: true, + + message: 'Message Alert', + description: 'Additional context for the alert.', + + enableSecondary: undefined, + + status: undefined, + headerAlign: undefined, + descriptionAlign: undefined, + primaryAction: 'Acknowledge', + secondaryAction: undefined, + actionAlign: undefined + } +}; + +export const Secondary_Action: ComponentStoryFormat = { + description: () => html` + +
    +
  • Set the label for the secondary action button with the secondary-action attribute (Defaults to 'Cancel').
  • +
  • Enable the secondary action button with the enable-secondary attribute.
  • +
+
+ + `, + render: (args: Args) => html` + + ${args.hide ? nothing : alertHtml(args)} + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: `document.querySelector('omni-alert').show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniAlert } from "@capitec/omni-components-react/alert"; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +}; + +const App = () => ;` + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + document.querySelector('omni-alert').show(); + } +};` + } + } + ], + name: 'Secondary Action', + args: { + 'status-indicator': '', + header: '', + '[Default Slot]': '', + primary: '', + secondary: '', + + hide: true, + + message: 'Message Alert', + description: 'Additional context for the alert.', + + enableSecondary: true, + + status: undefined, + headerAlign: undefined, + descriptionAlign: undefined, + primaryAction: undefined, + secondaryAction: 'Back', + actionAlign: undefined + } +}; + +export const Action_Align: ComponentStoryFormat = { + description: () => html`Align the action button(s) horizontally (Defaults to 'right').`, + render: (args: Args) => html` + + ${args.hide ? nothing : alertHtml(args)} + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: `document.querySelector('omni-alert').show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniAlert } from "@capitec/omni-components-react/alert"; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +}; + +const App = () => ;` + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + document.querySelector('omni-alert').show(); + } +};` + } + } + ], + name: 'Action Align', + args: { + 'status-indicator': '', + header: '', + '[Default Slot]': '', + primary: '', + secondary: '', + + hide: true, + + message: 'Message Alert', + description: 'Additional context for the alert.', + + enableSecondary: true, + + status: undefined, + headerAlign: undefined, + descriptionAlign: undefined, + primaryAction: 'Accept', + secondaryAction: 'Decline', + actionAlign: 'center' + } +}; + +export const Custom_Status_Indicator: ComponentStoryFormat = { + description: 'Render content as the status indicator instead of default status icons.', + render: (args: Args) => html` + + ${args.hide ? nothing : alertHtml(args)} + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: `document.querySelector('omni-alert').show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniAlert } from "@capitec/omni-components-react/alert"; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +}; + +const App = () => + 🔓 + ;` + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + document.querySelector('omni-alert').show(); + } +};` + } + } + ], + name: 'Custom Status Indicator', + args: { + 'status-indicator': raw`🔓`, + header: '', + '[Default Slot]': '', + primary: '', + secondary: '', + + hide: true, + + message: 'Message Alert', + description: 'Additional context for the alert.', + + enableSecondary: undefined, + + status: undefined, + headerAlign: undefined, + descriptionAlign: undefined, + primaryAction: undefined, + secondaryAction: undefined, + actionAlign: undefined + } +}; + +export const Custom_Header: ComponentStoryFormat = { + description: () => html`Render content as the header message area. This overrides any text specified via the message attribute.`, + render: (args: Args) => html` + + ${args.hide ? nothing : alertHtml(args)} + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: `document.querySelector('omni-alert').show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniAlert } from "@capitec/omni-components-react/alert"; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +}; + +const App = () => + Alert using the header slot + ;` + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + document.querySelector('omni-alert').show(); + } +};` + } + } + ], + name: 'Custom Header', + args: { + 'status-indicator': '', + header: raw`Alert using the header slot`, + '[Default Slot]': '', + primary: '', + secondary: '', + + hide: true, + + message: 'Message Alert', + description: 'Additional context for the alert.', + + enableSecondary: undefined, + + status: undefined, + headerAlign: undefined, + descriptionAlign: undefined, + primaryAction: undefined, + secondaryAction: undefined, + actionAlign: undefined + } +}; + +export const Custom_Body: ComponentStoryFormat = { + description: () => html`Render rich html content in the description. This appends to text specified via the description attribute.`, + render: (args: Args) => html` + + ${args.hide ? nothing : alertHtml(args)} + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: `document.querySelector('omni-alert').show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniAlert } from "@capitec/omni-components-react/alert"; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +}; + +const App = () => + Alert using the default slot and the description attribute. + ;` + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + document.querySelector('omni-alert').show(); + } +};` + } + } + ], + name: 'Custom Body', + args: { + 'status-indicator': '', + header: '', + '[Default Slot]': raw`Alert using the default slot and the description attribute.`, + primary: '', + secondary: '', + + hide: true, + + message: 'Message Alert', + description: 'Additional context for the alert.', + + enableSecondary: undefined, + + status: undefined, + headerAlign: undefined, + descriptionAlign: undefined, + primaryAction: undefined, + secondaryAction: undefined, + actionAlign: undefined + } +}; + +export const Custom_Primary_Action: ComponentStoryFormat = { + description: () => + html`Render rich html content as the primary action. This replaces any text specified via the primary-action attribute.`, + render: (args: Args) => html` + + ${args.hide ? nothing : alertHtml(args)} + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: `document.querySelector('omni-alert').show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniAlert } from "@capitec/omni-components-react/alert"; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +}; + +const App = () => + + ;` + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + document.querySelector('omni-alert').show(); + } +};` + } + } + ], + name: 'Custom Primary Action', + args: { + 'status-indicator': '', + header: '', + '[Default Slot]': '', + primary: raw``, + secondary: '', + + hide: true, + + message: 'Message Alert', + description: 'Additional context for the alert.', + + enableSecondary: undefined, + + status: undefined, + headerAlign: undefined, + descriptionAlign: undefined, + primaryAction: undefined, + secondaryAction: undefined, + actionAlign: undefined + } +}; + +export const Custom_Secondary_Action: ComponentStoryFormat = { + description: () => + html`Render rich html content as the secondary action. This replaces any text specified via the secondary-action attribute.`, + render: (args: Args) => html` + + ${args.hide ? nothing : alertHtml(args)} + `, + frameworkSources: [ + { + framework: 'HTML', + sourceParts: { + htmlFragment: (args) => raw` + ${getSourceFromLit(alertHtml(args))} + `, + jsFragment: `document.querySelector('omni-alert').show();` + } + }, + { + framework: 'Lit', + sourceParts: { + htmlFragment: (args) => + raw`${getSourceFromLit( + alertHtml(args), + (container) => container.firstElementChild?.setAttribute('data-replace-token', ''), + (s) => s.replace(' data-replace-token=""', ' ${ref(onRef)}') + )} `, + jsFragment: `import { ref } from 'https://unpkg.com/lit-html/directives/ref.js?module'; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +};` + } + }, + { + framework: 'React', + load: (args) => `import { OmniAlert } from "@capitec/omni-components-react/alert"; + +const onRef = e => { + const omniAlert = e; + if (omniAlert) { + omniAlert.show(); + } +}; + +const App = () => + + ;` + }, + { + framework: 'Vue', + sourceParts: { + htmlFragment: (args) => + getSourceFromLit(alertHtml(args)).replaceAll(' enable-secondary', ' :enable-secondary="true"') + + ` + +
+{{ (() => { run() })() }} +
+`, + jsFragment: `window.vueData = { + run: async () => { + await customElements.whenDefined('omni-alert'); + document.querySelector('omni-alert').show(); + } +};` + } + } + ], + name: 'Custom Secondary Action', + args: { + 'status-indicator': '', + header: '', + '[Default Slot]': '', + primary: '', + secondary: raw``, + + hide: true, + + message: 'Message Alert', + description: 'Additional context for the alert.', + + enableSecondary: true, + + status: undefined, + headerAlign: undefined, + descriptionAlign: undefined, + primaryAction: undefined, + secondaryAction: undefined, + actionAlign: undefined + } +}; diff --git a/src/alert/Alert.ts b/src/alert/Alert.ts new file mode 100644 index 000000000..d4be5ae27 --- /dev/null +++ b/src/alert/Alert.ts @@ -0,0 +1,752 @@ +import { html, css, type TemplateResult, nothing } from 'lit'; +import { customElement, property, query } from 'lit/decorators.js'; +import { OmniElement } from '../core/OmniElement.js'; +import { Modal } from '../modal/Modal.js'; +import type { RenderFunction, RenderResult } from '../render-element/RenderElement.js'; + +export type { RenderFunction, RenderResult } from '../render-element/RenderElement.js'; + +import '../button/Button.js'; +import '../render-element/RenderElement.js'; +import '../modal/Modal.js'; + +/** + * Component that displays an alert. + * + * @import + * ```js + * import '@capitec/omni-components/alert'; + * ``` + * + * @example + * ```html + * + * + * ``` + * + * @element omni-alert + * + * Registry of all properties defined by the component. + * + * @fires alert-action-click - Dispatched when an alert action button is clicked. + * @fires alert-close - Dispatched when the alert is closed. + * + * @slot status-indicator - Content to render as the status indicator instead of default status icons. + * @slot header - Content to render inside the component message area. + * @slot - Content to render inside the component description body. + * @slot primary - Content to render as the primary action button. + * @slot secondary - Content to render as the secondary action button. + * + * @csspart modal - Internal `omni-modal` element instance. + * @csspart content - Internal `HTMLDivElement` instance for container of header and description content. + * @csspart content - Internal `HTMLDivElement` instance for each line of description (does not include slotted description content). + * @csspart header - Internal `HTMLDivElement` instance for header. + * @csspart actions - Internal `HTMLDivElement` instance for container of action button(s). + * + * @cssprop --omni-alert-min-width - Minimum width for alert. + * @cssprop --omni-alert-max-width - Maximum width for alert. + * @cssprop --omni-alert-border - Alert border. + * @cssprop --omni-alert-border-radius - Alert border radius. + * @cssprop --omni-alert-box-shadow - Alert box shadow. + * + * @cssprop --omni-alert-animation-duration - Alert fade in and out animation duration. + * @cssprop --omni-alert-padding-top - Alert content top padding. + * @cssprop --omni-alert-padding-bottom - Alert content bottom padding. + * @cssprop --omni-alert-padding-left - Alert content left padding. + * @cssprop --omni-alert-padding-right - Alert content right padding. + * + * @cssprop --omni-alert-header-font-color - Alert header font color. + * @cssprop --omni-alert-header-font-family - Alert header font family. + * @cssprop --omni-alert-header-font-size - Alert header font size. + * @cssprop --omni-alert-header-font-weight - Alert header font weight. + * @cssprop --omni-alert-header-line-height - Alert header line height. + * @cssprop --omni-alert-header-background - Alert header background. + * + * @cssprop --omni-alert-header-padding-top - Alert header top padding. + * @cssprop --omni-alert-header-padding-bottom - Alert header bottom padding. + * @cssprop --omni-alert-header-padding-left - Alert header left padding. + * @cssprop --omni-alert-header-padding-right - Alert header right padding. + * + * @cssprop --omni-alert-description-font-color - Alert description font color. + * @cssprop --omni-alert-description-font-family - Alert description font family. + * @cssprop --omni-alert-description-font-size - Alert description font size. + * @cssprop --omni-alert-description-font-weight - Alert description font weight. + * @cssprop --omni-alert-description-line-height - Alert description line height. + * + * @cssprop --omni-alert-description-padding-top - Alert description top padding. + * @cssprop --omni-alert-description-padding-bottom - Alert description bottom padding. + * @cssprop --omni-alert-description-padding-left - Alert description left padding. + * @cssprop --omni-alert-description-padding-right - Alert description right padding. + * + * @cssprop --omni-alert-action-button-padding-top - Alert action button(s) top padding. + * @cssprop --omni-alert-action-button-padding-bottom - Alert action button(s) bottom padding. + * @cssprop --omni-alert-action-button-padding-left - Alert action button(s) left padding. + * @cssprop --omni-alert-action-button-padding-right - Alert action button(s) right padding. + * + * @cssprop --omni-alert-action-button-internal-padding-top - Alert action button(s) internal top padding. + * @cssprop --omni-alert-action-button-internal-padding-bottom - Alert action button(s) internal bottom padding. + * @cssprop --omni-alert-action-button-internal-padding-left - Alert action button(s) internal left padding. + * @cssprop --omni-alert-action-button-internal-padding-right - Alert action button(s) internal right padding. + * + * @cssprop --omni-alert-header-horizontal-gap - Alert header horizontal space between status indicator and header content. + * + * @cssprop --omni-alert-header-status-size - Alert header status indicator symmetrical size. + */ +@customElement('omni-alert') +export class Alert extends OmniElement { + /** + * Internal `omni-modal` instance. + * @no_attribute + * @ignore + */ + @query('omni-modal') modal!: Modal; + + /** + * The alert status (Defaults to 'none'). + * @attr + */ + @property({ type: String, reflect: true }) status: 'success' | 'warning' | 'error' | 'info' | 'none' = 'none'; + + /** + * The alert header message. + * @attr + */ + @property({ type: String, reflect: true }) message?: string; + + /** + * Header content horizontal alignment: + * - `left` Align header to the left. + * - `center` Align header to the center. (Default) + * - `right` Align header to the right. + * @attr [header-align] + */ + @property({ type: String, attribute: 'header-align', reflect: true }) headerAlign?: 'left' | 'center' | 'right'; + + /** + * The alert detail message. + * @attr + */ + @property({ type: String, reflect: true }) description?: string; + + /** + * Description content horizontal alignment: + * - `left` Align description content to the left. + * - `center` Align description content to the center. (Default) + * - `right` Align description content to the right. + * @attr [description-align] + */ + @property({ type: String, attribute: 'description-align', reflect: true }) descriptionAlign?: 'left' | 'center' | 'right'; + + /** + * The primary action button label (Defaults to 'Ok'). + * @attr [primary-action] + */ + @property({ type: String, reflect: true, attribute: 'primary-action' }) primaryAction?: string; + + /** + * The secondary action button label (Defaults to 'Cancel'). + * @attr [secondary-action] + */ + @property({ type: String, reflect: true, attribute: 'secondary-action' }) secondaryAction?: string; + + /** + * If true, will provide a secondary action button. + * @attr [enable-secondary] + */ + @property({ type: Boolean, reflect: true, attribute: 'enable-secondary' }) enableSecondary?: boolean; + + /** + * Action button(s) horizontal alignment: + * - `left` Align action button(s) to the left. + * - `center` Align action button(s) to the center. + * - `right` Align action button(s) to the right. (Default) + * - `stretch` Align action button(s) stretched to fill the horizontal space. + * @attr [action-align] + */ + @property({ type: String, attribute: 'action-align', reflect: true }) actionAlign?: 'left' | 'center' | 'right' | 'stretch'; + + /** + * Create a global `omni-alert` element without showing it. + * + * @returns The alert instance. + */ + static create(init: AlertInit) { + const element = document.body.appendChild(document.createElement('omni-alert')); + if (!init) { + init = {}; + } + + // Set the `omni-alert` component values. + element.status = init.status ?? 'none'; + element.message = init.message; + element.headerAlign = init.headerAlign; + element.descriptionAlign = init.descriptionAlign; + element.description = init.description; + element.primaryAction = init.primaryAction; + element.secondaryAction = init.secondaryAction; + element.enableSecondary = init.enableSecondary; + element.actionAlign = init.actionAlign; + if (init.id) { + element.id = init.id; + } + + // Setup optional renderers for slot(s) + if (init.statusIndicator) { + const renderElement = document.createElement('omni-render-element'); + renderElement.slot = 'status-indicator'; + renderElement.renderer = typeof init.statusIndicator === 'function' ? init.statusIndicator : () => init.statusIndicator as RenderResult; + element.appendChild(renderElement); + } + if (init.header) { + const renderElement = document.createElement('omni-render-element'); + renderElement.slot = 'header'; + renderElement.renderer = typeof init.header === 'function' ? init.header : () => init.header as RenderResult; + element.appendChild(renderElement); + } + if (init.body) { + const renderElement = document.createElement('omni-render-element'); + renderElement.renderer = typeof init.body === 'function' ? init.body : () => init.body as RenderResult; + element.appendChild(renderElement); + } + if (init.primary) { + const renderElement = document.createElement('omni-render-element'); + renderElement.slot = 'primary'; + renderElement.renderer = typeof init.primary === 'function' ? init.primary : () => init.primary as RenderResult; + element.appendChild(renderElement); + } + if (init.secondary) { + const renderElement = document.createElement('omni-render-element'); + renderElement.slot = 'secondary'; + renderElement.renderer = typeof init.secondary === 'function' ? init.secondary : () => init.secondary as RenderResult; + element.appendChild(renderElement); + } + + return element as Alert; + } + + /** + * Show a global `omni-alert` element. + * + * @returns The alert instance. + */ + static show( + init: AlertInit & { + onClose?: (reason: 'auto' | 'primary' | 'secondary') => void; + } + ) { + const element = Alert.create(init); + + if (init.onClose) { + let reason: 'auto' | 'primary' | 'secondary' = 'auto'; + element.addEventListener('alert-action-click', (e: Event) => { + const actionClickEvent = e as CustomEvent<{ secondary: boolean }>; + reason = actionClickEvent.detail.secondary ? 'secondary' : 'primary'; + }); + element.addEventListener('alert-close', () => { + init.onClose?.apply(element, [reason]); + }); + } + + // Show the component as a modal dialog. + return element.show() as Alert; + } + + /** + * Show a global `omni-alert` element asynchronously, waits for it to close and returns the reason for close. + * + * @returns The reason for the alert close. + */ + static showAsync(init: AlertInit) { + const element = Alert.create(init); + return element.showAsync() as Promise<'auto' | 'primary' | 'secondary'>; + } + + /** + * Show the `omni-alert` asynchronously, waits for it to close and returns the reason for close. + * + * @returns The reason for the alert close. + */ + showAsync() { + return new Promise<'auto' | 'primary' | 'secondary'>((resolve, reject) => { + try { + this.show(); + let reason: 'auto' | 'primary' | 'secondary' = 'auto'; + this.addEventListener('alert-action-click', (e: Event) => { + const actionClickEvent = e as CustomEvent<{ secondary: boolean }>; + reason = actionClickEvent.detail.secondary ? 'secondary' : 'primary'; + }); + this.addEventListener('alert-close', () => { + resolve?.apply(this, [reason]); + }); + } catch (error) { + reject.apply(this, [error]); + } + }); + } + + /** + * Show the `omni-alert`. + * + * @returns The alert instance. + */ + show(): Alert { + // Show the component modal dialog, after the initial component render has completed. + this.updateComplete.then(() => { + this.modal.hide = false; + }); + return this; + } + + /** + * Hide the `omni-alert` and remove the component from the DOM + */ + hide(): void { + this.updateComplete.then(async () => { + const { matches: motionOK } = window.matchMedia('(prefers-reduced-motion: no-preference)'); + + // Animate the alert fading out if the user allows motion. + if (motionOK && document.timeline) { + // Get current opacity to cater for existing fade out of timed toasts. + const currentOpacity = Number(getComputedStyle(this.modal).getPropertyValue('opacity')); + + const anim = this.modal.animate( + [ + // key frames + { offset: 0, opacity: currentOpacity }, + { offset: 1, opacity: 0 } + ], + { + // sync options + duration: 500, + easing: 'ease' + } + ); + await anim.finished; + } + + this.modal.hide = true; + this.dispatchEvent(new CustomEvent('alert-close')); + if (this.parentElement) { + this.remove(); + } + }); + } + + private onActionClick(secondary?: boolean) { + this.dispatchEvent( + new CustomEvent('alert-action-click', { + detail: { + secondary: secondary ?? false + } + }) + ); + + this.hide(); + } + + /** + * The element style template. + */ + static override get styles() { + return [ + super.styles, + css` + :host { + box-sizing: border-box; + } + + omni-modal { + --omni-modal-body-padding: 0px; + } + + omni-modal::part(container) { + + min-width: var(--omni-alert-min-width, 10%); + max-width: var(--omni-alert-max-width, 80%); + } + + /** Dialog */ + + .container { + display: flex; + flex-direction: column; + align-items: stretch; + justify-content: flex-start; + + padding: 0px; + + border: var(--omni-alert-border, none); + + box-shadow: var(--omni-alert-box-shadow, 0px 0px 3px rgba(0, 0, 0, 0.1)); + border-radius: var(--omni-alert-border-radius, 10px); + } + + omni-modal:not([hide]) { + animation: fadein var(--omni-alert-animation-duration, 0.2s) ease-in-out; + animation-fill-mode: forwards; + } + + @media (prefers-reduced-motion) { + /* styles to apply if a user's device settings are set to reduced motion */ + omni-modal:not([hide]) { + animation: unset; + opacity: 1; + } + } + + @keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + /* Content */ + + .content { + display: flex; + flex-direction: column; + justify-content: center; + + padding-top: var(--omni-alert-padding-top, 10px); + padding-bottom: var(--omni-alert-padding-bottom, 10px); + padding-left: var(--omni-alert-padding-left, 10px); + padding-right: var(--omni-alert-padding-right, 10px); + } + + .header { + display: inline-flex; + align-items: center; + text-align: center; + justify-content: center; + color: var(--omni-alert-header-font-color,var(--omni-font-color)); + background: var(--omni-alert-header-background, var(--omni-background-color)); + font-family: var(--omni-alert-header-font-family, var(--omni-font-family)); + font-size: var(--omni-alert-header-font-size, var(--omni-font-size)); + line-height: var(--omni-alert-header-line-height, 1.2); + font-weight: var(--omni-alert-header-font-weight, bold); + + position: relative; + + margin-top: var(--omni-alert-header-padding-top, 10px); + margin-bottom: var(--omni-alert-header-padding-bottom, 0px); + margin-left: var(--omni-alert-header-padding-left, 0px); + margin-right: var(--omni-alert-header-padding-right, 0px); + } + + .header.left { + justify-content: left; + } + + .header.right { + justify-content: right; + text-align: right; + } + + ::slotted(*:not([slot])), + .description { + font-family: var(--omni-alert-description-font-family, sans-serif); + font-size: var(--omni-alert-description-font-size, 16px); + font-weight: var(--omni-alert-description-font-weight, normal); + line-height: var(--omni-alert-description-line-height, 1.2); + + color: var(--omni-alert-description-font-color, var(--omni-font-color)); + + text-align: center; + + margin-top: var(--omni-alert-description-padding-top, 10px); + margin-bottom: var(--omni-alert-description-padding-bottom, 0px); + margin-left: var(--omni-alert-description-padding-left, 0px); + margin-right: var(--omni-alert-description-padding-right, 0px); + } + + .description.left { + justify-content: left; + text-align: left; + } + + .description.right { + justify-content: right; + text-align: right; + } + + .actions { + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; + } + + .actions.center { + justify-content: center; + text-align: center; + } + + .actions.left { + flex-direction: row-reverse; + text-align: left; + } + + .actions.left .action-btn { + padding-left: var(--omni-alert-action-button-padding-left, 4px); + padding-right: var(--omni-alert-action-button-padding-right); + } + + .actions.stretch .action-btn, + .actions.stretch .clear-btn { + padding-left: var(--omni-alert-action-button-padding-left, 4px); + padding-right: var(--omni-alert-action-button-padding-right, 4px); + width: 100%; + } + + .action-btn { + padding-top: var(--omni-alert-action-button-padding-top); + padding-bottom: var(--omni-alert-action-button-padding-bottom, 4px); + padding-left: var(--omni-alert-action-button-padding-left); + padding-right: var(--omni-alert-action-button-padding-right, 4px); + + --omni-button-padding-top:var(--omni-alert-action-button-internal-padding-top, 0px); + --omni-button-padding-bottom:var(--omni-alert-action-button-internal-padding-bottom, 0px); + --omni-button-padding-left:var(--omni-alert-action-button-internal-padding-left, 4px); + --omni-button-padding-right:var(--omni-alert-action-button-internal-padding-right, 4px); + } + + .clear-btn { + line-height: normal; + padding-top: var(--omni-alert-action-button-padding-top, 4px); + padding-bottom: var(--omni-alert-action-button-padding-bottom); + padding-left: var(--omni-alert-action-button-padding-left); + padding-right: var(--omni-alert-action-button-padding-right); + + --omni-button-padding-top:var(--omni-alert-action-button-internal-padding-top); + --omni-button-padding-bottom:var(--omni-alert-action-button-internal-padding-bottom); + --omni-button-padding-left:var(--omni-alert-action-button-internal-padding-left); + --omni-button-padding-right:var(--omni-alert-action-button-internal-padding-right); + } + + .status-icon { + + margin-right: var(--omni-alert-header-horizontal-gap, 10px); + + width: var(--omni-alert-header-status-size, 24px); + height: var(--omni-alert-header-status-size, 24px); + + min-width: var(--omni-alert-header-status-size, 24px); + min-height: var(--omni-alert-header-status-size, 24px); + + max-width: var(--omni-alert-header-status-size, 24px); + max-height: var(--omni-alert-header-status-size, 24px); + } + ` + ]; + } + + /** + * Generate the web component template. + * + * @returns The HTML component template. + */ + override render(): TemplateResult { + // Determine the icon to show. + let iconTemplate: TemplateResult | typeof nothing = nothing; + + // Derive the icon from the status. + switch (this.status) { + case 'info': + iconTemplate = html` + + + + + + + `; + break; + + case 'success': + iconTemplate = html` + + + + + + + `; + break; + + case 'error': + iconTemplate = html` + + + + + + + `; + break; + + case 'warning': + iconTemplate = html` + + + + + + + `; + break; + + case 'none': + default: + iconTemplate = nothing; + break; + } + + // Generate the component template. + return html` + +
+
+ + ${iconTemplate} + + + ${this.message ? html`
${this.message}
` : nothing} +
+
+ ${ + this.description + ? this.description + .split('\n') + .map( + (paragraph) => html`
${paragraph}
` + ) + : nothing + } + + +
+
+ ${ + this.enableSecondary + ? html` +
+ + + +
+ ` + : nothing + } +
+ + + +
+
+
+ `; + } +} + +/** + * Context for `Alert.show`/`Alert.showAsync` function(s) to programmatically render a new `` instance. + */ +export type AlertInit = { + /** + * The id to apply to the Alert element. + */ + id?: string; + + /** + * A function that returns, or an instance of content to render as the alert status indicator + */ + statusIndicator?: RenderFunction | RenderResult; + + /** + * A function that returns, or an instance of content to render in the alert header + */ + header?: RenderFunction | RenderResult; + + /** + * A function that returns, or an instance of content to render as alert body + */ + body?: RenderFunction | RenderResult; + + /** + * A function that returns, or an instance of content to render as the alert primary action + */ + primary?: RenderFunction | RenderResult; + + /** + * A function that returns, or an instance of content to render as the alert secondary action + */ + secondary?: RenderFunction | RenderResult; + + /** + * The alert status (Defaults to 'none'). + */ + status?: 'success' | 'warning' | 'error' | 'info' | 'none'; + + /** + * The alert header message. + */ + message?: string; + + /** + * Header content horizontal alignment: + * - `left` Align header to the left. + * - `center` Align header to the center. (Default) + * - `right` Align header to the right. + */ + headerAlign?: 'left' | 'center' | 'right'; + + /** + * The alert detail message. + */ + description?: string; + + /** + * Description content horizontal alignment: + * - `left` Align description content to the left. + * - `center` Align description content to the center. (Default) + * - `right` Align description content to the right. + */ + descriptionAlign?: 'left' | 'center' | 'right'; + + /** + * The primary action button label (Defaults to 'Ok'). + */ + primaryAction?: string; + + /** + * The secondary action button label (Defaults to 'Cancel'). + */ + secondaryAction?: string; + + /** + * If true, will provide a secondary action button. + */ + enableSecondary?: boolean; + + /** + * Action button(s) horizontal alignment: + * - `left` Align action button(s) to the left. + * - `center` Align action button(s) to the center. + * - `right` Align action button(s) to the right. (Default) + * - `stretch` Align action button(s) stretched to fill the horizontal space. + */ + actionAlign?: 'left' | 'center' | 'right' | 'stretch'; +}; + +declare global { + interface HTMLElementTagNameMap { + 'omni-alert': Alert; + } +} diff --git a/src/alert/README.md b/src/alert/README.md new file mode 100644 index 000000000..515245744 --- /dev/null +++ b/src/alert/README.md @@ -0,0 +1,130 @@ +# omni-alert + +Component that displays an alert. + +## Example + +```html + + +``` + +## Properties + +| Property | Attribute | Modifiers | Type | Default | Description | +|--------------------|---------------------|-----------|--------------------------------------------------|---------|--------------------------------------------------| +| `actionAlign` | `action-align` | | `"left" \| "center" \| "right" \| "stretch" \| undefined` | | Action button(s) horizontal alignment:
- `left` Align action button(s) to the left.
- `center` Align action button(s) to the center.
- `right` Align action button(s) to the right. (Default)
- `stretch` Align action button(s) stretched to fill the horizontal space. | +| `description` | `description` | | `string \| undefined` | | The alert detail message. | +| `descriptionAlign` | `description-align` | | `"left" \| "center" \| "right" \| undefined` | | Description content horizontal alignment:
- `left` Align description content to the left.
- `center` Align description content to the center. (Default)
- `right` Align description content to the right. | +| `dir` | | | `string` | | | +| `enableSecondary` | `enable-secondary` | | `boolean \| undefined` | | If true, will provide a secondary action button. | +| `headerAlign` | `header-align` | | `"left" \| "center" \| "right" \| undefined` | | Header content horizontal alignment:
- `left` Align header to the left.
- `center` Align header to the center. (Default)
- `right` Align header to the right. | +| `lang` | | | `string` | | | +| `message` | `message` | | `string \| undefined` | | The alert header message. | +| `override` | `override` | | | | The element style template. | +| `primaryAction` | `primary-action` | | `string \| undefined` | | The primary action button label (Defaults to 'Ok'). | +| `secondaryAction` | `secondary-action` | | `string \| undefined` | | The secondary action button label (Defaults to 'Cancel'). | +| `status` | `status` | | `"success" \| "warning" \| "error" \| "info" \| "none"` | "none" | The alert status (Defaults to 'none'). | +| `styles` | | readonly | `CSSResultGroup[]` | | | + +## Methods + +| Method | Type | Description | +|-------------|--------------------------------------------------|--------------------------------------------------| +| `hide` | `(): void` | Hide the `omni-alert` and remove the component from the DOM | +| `show` | `(): Alert` | Show the `omni-alert`. | +| `showAsync` | `(): Promise<"auto" \| "primary" \| "secondary">` | Show the `omni-alert` asynchronously, waits for it to close and returns the reason for close. | + +## Events + +| Event | Type | Description | +|----------------------|----------------------------------------|--------------------------------------------------| +| `alert-action-click` | `CustomEvent<{ secondary: boolean; }>` | Dispatched when an alert action button is clicked. | +| `alert-close` | | Dispatched when the alert is closed. | + +## Slots + +| Name | Description | +|---------------------|--------------------------------------------------| +| | Content to render inside the component description body. | +| `header` | Content to render inside the component message area. | +| `loading_indicator` | Used to define content that is displayed while async rendering is awaiting, or when renderLoading() is implicitly called | +| `primary` | Content to render as the primary action button. | +| `secondary` | Content to render as the secondary action button. | +| `status-indicator` | Content to render as the status indicator instead of default status icons. | + +## CSS Shadow Parts + +| Part | Description | +|-----------|--------------------------------------------------| +| `actions` | Internal `HTMLDivElement` instance for container of action button(s). | +| `content` | Internal `HTMLDivElement` instance for container of header and description content. | +| `header` | Internal `HTMLDivElement` instance for header. | +| `modal` | Internal `omni-modal` element instance. | + +## CSS Custom Properties + +| Property | Description | +|--------------------------------------------------|--------------------------------------------------| +| `--omni-alert-action-button-internal-padding-bottom` | Alert action button(s) internal bottom padding. | +| `--omni-alert-action-button-internal-padding-left` | Alert action button(s) internal left padding. | +| `--omni-alert-action-button-internal-padding-right` | Alert action button(s) internal right padding. | +| `--omni-alert-action-button-internal-padding-top` | Alert action button(s) internal top padding. | +| `--omni-alert-action-button-padding-bottom` | Alert action button(s) bottom padding. | +| `--omni-alert-action-button-padding-left` | Alert action button(s) left padding. | +| `--omni-alert-action-button-padding-right` | Alert action button(s) right padding. | +| `--omni-alert-action-button-padding-top` | Alert action button(s) top padding. | +| `--omni-alert-animation-duration` | Alert fade in and out animation duration. | +| `--omni-alert-border` | Alert border. | +| `--omni-alert-border-radius` | Alert border radius. | +| `--omni-alert-box-shadow` | Alert box shadow. | +| `--omni-alert-description-font-color` | Alert description font color. | +| `--omni-alert-description-font-family` | Alert description font family. | +| `--omni-alert-description-font-size` | Alert description font size. | +| `--omni-alert-description-font-weight` | Alert description font weight. | +| `--omni-alert-description-line-height` | Alert description line height. | +| `--omni-alert-description-padding-bottom` | Alert description bottom padding. | +| `--omni-alert-description-padding-left` | Alert description left padding. | +| `--omni-alert-description-padding-right` | Alert description right padding. | +| `--omni-alert-description-padding-top` | Alert description top padding. | +| `--omni-alert-header-background` | Alert header background. | +| `--omni-alert-header-font-color` | Alert header font color. | +| `--omni-alert-header-font-family` | Alert header font family. | +| `--omni-alert-header-font-size` | Alert header font size. | +| `--omni-alert-header-font-weight` | Alert header font weight. | +| `--omni-alert-header-horizontal-gap` | Alert header horizontal space between status indicator and header content. | +| `--omni-alert-header-line-height` | Alert header line height. | +| `--omni-alert-header-padding-bottom` | Alert header bottom padding. | +| `--omni-alert-header-padding-left` | Alert header left padding. | +| `--omni-alert-header-padding-right` | Alert header right padding. | +| `--omni-alert-header-padding-top` | Alert header top padding. | +| `--omni-alert-header-status-size` | Alert header status indicator symmetrical size. | +| `--omni-alert-max-width` | Maximum width for alert. | +| `--omni-alert-min-width` | Minimum width for alert. | +| `--omni-alert-padding-bottom` | Alert content bottom padding. | +| `--omni-alert-padding-left` | Alert content left padding. | +| `--omni-alert-padding-right` | Alert content right padding. | +| `--omni-alert-padding-top` | Alert content top padding. | +| `--omni-theme-accent-active-color` | Theme accent active color. | +| `--omni-theme-accent-color` | Theme accent color. | +| `--omni-theme-accent-hover-color` | Theme accent hover color. | +| `--omni-theme-background-active-color` | Theme background active color. | +| `--omni-theme-background-color` | Theme background color. | +| `--omni-theme-background-hover-color` | Theme background hover color. | +| `--omni-theme-border-radius` | Theme border radius. | +| `--omni-theme-border-width` | Theme border width. | +| `--omni-theme-box-shadow` | Theme box shadow. | +| `--omni-theme-box-shadow-color` | Theme inactive color. | +| `--omni-theme-disabled-background-color` | Theme disabled background color. | +| `--omni-theme-disabled-border-color` | Theme disabled border color. | +| `--omni-theme-error-border-color` | Theme error border color. | +| `--omni-theme-error-font-color` | Theme disabled background color. | +| `--omni-theme-font-color` | Theme font color. | +| `--omni-theme-font-family` | Theme font family. | +| `--omni-theme-font-size` | Theme font size. | +| `--omni-theme-font-weight` | Theme font weight. | +| `--omni-theme-hint-font-color` | Theme hint font color. | +| `--omni-theme-inactive-color` | Theme inactive color. | +| `--omni-theme-primary-active-color` | Theme primary active color. | +| `--omni-theme-primary-color` | Theme primary color. | +| `--omni-theme-primary-hover-color` | Theme primary hover color. | diff --git a/src/alert/index.ts b/src/alert/index.ts new file mode 100644 index 000000000..315789b33 --- /dev/null +++ b/src/alert/index.ts @@ -0,0 +1 @@ +export * from './Alert.js'; diff --git a/src/button/README.md b/src/button/README.md index 8f12dd928..2bafb580c 100644 --- a/src/button/README.md +++ b/src/button/README.md @@ -20,7 +20,7 @@ Control that allows an action to be executed. | `label` | `label` | | `string \| undefined` | | Text label. | | `lang` | | | `string` | | | | `override` | `override` | | | | Used to set the base direction of text for display | -| `slotPosition` | `slot-position` | | `"left" \| "top" \| "right" \| "bottom"` | "left" | Position of slotted content. | +| `slotPosition` | `slot-position` | | `"left" \| "right" \| "top" \| "bottom"` | "left" | Position of slotted content. | | `styles` | | readonly | `CSSResultGroup[]` | | | | `type` | `type` | | `"primary" \| "secondary" \| "clear" \| "white"` | "secondary" | Display type. | diff --git a/src/modal/Modal.ts b/src/modal/Modal.ts index b347e609d..c67e856f9 100644 --- a/src/modal/Modal.ts +++ b/src/modal/Modal.ts @@ -233,6 +233,8 @@ export class Modal extends OmniElement { left: var(--omni-modal-dialog-left, 0px); right: var(--omni-modal-dialog-right, 0px); bottom: var(--omni-modal-dialog-bottom, 0px); + + opacity: inherit; } ::backdrop { diff --git a/src/modal/README.md b/src/modal/README.md index 0bc1b9292..da9948329 100644 --- a/src/modal/README.md +++ b/src/modal/README.md @@ -17,7 +17,7 @@ Control to display modal content with optional header and footer content. | Property | Attribute | Modifiers | Type | Default | Description | |----------------|-----------------|-----------|----------------------------------------------|---------|--------------------------------------------------| | `dir` | | | `string` | | | -| `headerAlign` | `header-align` | | `"left" \| "right" \| "center" \| undefined` | | Header text horizontal alignment:
- `left` Align header to the left.
- `center` Align header to the center.
- `right` Align header to the right. | +| `headerAlign` | `header-align` | | `"left" \| "center" \| "right" \| undefined` | | Header text horizontal alignment:
- `left` Align header to the left.
- `center` Align header to the center.
- `right` Align header to the right. | | `headerLabel` | `header-label` | | `string` | "" | Title text to be displayed in header area. | | `hide` | `hide` | | `boolean \| undefined` | | If true, will hide the modal. | | `lang` | | | `string` | | | diff --git a/src/toast/README.md b/src/toast/README.md index 8c1a8bc5f..fda5883ac 100644 --- a/src/toast/README.md +++ b/src/toast/README.md @@ -24,7 +24,7 @@ Component to visually notify a user of a message. | `lang` | | | `string` | | | | `override` | `override` | | | | Used to set the base direction of text for display | | `styles` | | readonly | `CSSResultGroup[]` | | | -| `type` | `type` | | `"none" \| "success" \| "warning" \| "error" \| "info"` | "none" | The type of toast to display. | +| `type` | `type` | | `"success" \| "warning" \| "error" \| "info" \| "none"` | "none" | The type of toast to display. | ## Events @@ -134,7 +134,7 @@ A toast container that animates in and stacks toast elements. | `dir` | | | `string` | | | | `lang` | | | `string` | | | | `override` | `override` | | | | Used to set the base direction of text for display | -| `position` | `position` | | `"left" \| "top" \| "right" \| "bottom" \| "top-left" \| "top-right" \| "bottom-left" \| "bottom-right"` | "bottom" | The position to stack toasts | +| `position` | `position` | | `"left" \| "right" \| "top" \| "bottom" \| "top-left" \| "top-right" \| "bottom-left" \| "bottom-right"` | "bottom" | The position to stack toasts | | `reverse` | `reverse` | | `boolean \| undefined` | | Reverse the order of toast with newest toasts showed on top of the stack. By default newest toasts are showed at the bottom of the stack. | | `styles` | | readonly | `CSSResult[]` | | | diff --git a/src/toast/ToastStack.stories.ts b/src/toast/ToastStack.stories.ts index 7f7a23d17..0e512b9ba 100644 --- a/src/toast/ToastStack.stories.ts +++ b/src/toast/ToastStack.stories.ts @@ -348,7 +348,9 @@ const onRef = e => { getSourceFromLit(renderStack(args)).replaceAll(' closeable', ' :closeable="true"').replaceAll(' reverse', ' :reverse="true"') + ` +
{{ (() => { run() })() }} +
`, jsFragment: `window.vueData = { run: async () => { @@ -623,7 +625,9 @@ const onRef = e => { getSourceFromLit(renderStack(args)).replaceAll(' closeable', ' :closeable="true"').replaceAll(' reverse', ' :reverse="true"') + ` +
{{ (() => { run() })() }} +
`, jsFragment: `window.vueData = { run: async () => { @@ -774,7 +778,9 @@ const onRef = e => { getSourceFromLit(renderStack(args)).replaceAll(' closeable', ' :closeable="true"').replaceAll(' reverse', ' :reverse="true"') + ` +
{{ (() => { run() })() }} +
`, jsFragment: `window.vueData = { run: async () => { diff --git a/src/utils/JestPlaywright.ts b/src/utils/JestPlaywright.ts index 404fe1852..250cac1b4 100644 --- a/src/utils/JestPlaywright.ts +++ b/src/utils/JestPlaywright.ts @@ -8,8 +8,7 @@ import { type Page, type PageScreenshotOptions, type LocatorScreenshotOptions, - JSHandle, - ElementHandle + type ElementHandle } from '@playwright/test'; export * from '@playwright/test'; import { fn } from 'jest-mock'; @@ -164,7 +163,7 @@ async function getStoryArgs(page: Page, key: string, readySelector = '[ return args; } -async function mockEventListener(locatorOrHandle: Locator | ElementHandle | null | undefined, eventName: string) { +async function mockEventListener(locatorOrHandle: Locator | ElementHandle | null | undefined, eventName: string, callback?: (e: Event) => void) { const tempFunction = `mock_${v4()}`; const eventFunction = fn(); @@ -173,38 +172,85 @@ async function mockEventListener(locatorOrHandle: Locator | ElementHandle | null } let page: Page; - const evalFunc = (node: HTMLElement, { tempFunction, eventName }: { tempFunction: string; eventName: string }) => { - //@ts-ignore - node.addEventListener(eventName, () => window[tempFunction]()); + const evalFunc = (node: HTMLElement, { tempFunction, eventName, fullEvent }: { tempFunction: string; eventName: string; fullEvent: boolean }) => { + // Stringify Event https://stackoverflow.com/a/58416333 + function stringifyObject(object: any, maxDepth = 4, currentDepth = 0) { + if (currentDepth > maxDepth) return object?.toString(); + + const obj: Record = {}; + for (const key in object) { + let value = object[key]; + if (value instanceof Node) + if (value instanceof Element) { + value = value.outerHTML; + } else if (value.textContent) { + value = value.textContent; + } else if ((value as any).id) { + value = { id: (value as any).id }; + } else { + value = value.toString(); + } + else if (value instanceof Window) { + value = 'Window'; + } else if (value instanceof Object) { + value = stringifyObject(value, maxDepth, currentDepth + 1); + } + + obj[key] = value; + } + + return currentDepth ? obj : JSON.stringify(obj); + } + + node.addEventListener(eventName, (e) => { + const eData = fullEvent ? stringifyObject(e) : ''; + // console.log(e); + // console.log(eData); + //@ts-ignore + window[tempFunction](eData); + }); + }; + const pageFunction = (e: string) => { + eventFunction(); + if (callback) { + callback(JSON.parse(e)); + } }; if ((locatorOrHandle as ElementHandle).ownerFrame) { const handle = locatorOrHandle as ElementHandle; page = (await handle.ownerFrame())?.page() as Page; - await page.exposeFunction(tempFunction, () => eventFunction()); + await page.exposeFunction(tempFunction, pageFunction); - await handle.evaluate(evalFunc, { tempFunction, eventName }); + await handle.evaluate(evalFunc, { tempFunction, eventName, fullEvent: Boolean(callback) }); } else { const locator = locatorOrHandle as Locator; page = locator.page() as Page; - await page.exposeFunction(tempFunction, () => eventFunction()); + await page.exposeFunction(tempFunction, pageFunction); - await locator.evaluate(evalFunc, { tempFunction, eventName }); + await locator.evaluate(evalFunc, { tempFunction, eventName, fullEvent: Boolean(callback) }); } return eventFunction; } -/* - const valueChange = jestMock.fn(); - await page.exposeFunction('jestChange', () => valueChange()); - await selectComponent.evaluate((node) => { - node.addEventListener('change', () => window.jestChange()); +function createWaitHandle() { + let resolveFn: (value: T) => void; + let rejectFn: (reason?: any) => void; + const promise = new Promise((resolve, reject) => { + resolveFn = resolve; + rejectFn = reject; }); -*/ + return { + completed: promise, + release: resolveFn!, + error: rejectFn! + }; +} + // TODO: Revisit once playwright clipboard support is completed /* clipboard isolation: [feature] clipboard isolation: https://github.com/microsoft/playwright/issues/13097 @@ -239,4 +285,4 @@ declare global { } } -export { expect, withCoverage, getStoryArgs, mockEventListener /*keyboardCopy, keyboardPaste, clipboardCopy*/ }; +export { expect, withCoverage, getStoryArgs, mockEventListener, createWaitHandle /*keyboardCopy, keyboardPaste, clipboardCopy*/ }; diff --git a/src/utils/LivePropertyEditor.ts b/src/utils/LivePropertyEditor.ts index afb214101..208acb354 100644 --- a/src/utils/LivePropertyEditor.ts +++ b/src/utils/LivePropertyEditor.ts @@ -277,10 +277,13 @@ export class LivePropertyEditor extends OmniElement { !attribute.type?.text?.replace('| undefined', '')?.trim().includes('Promise') && attribute.type?.text?.replace('| undefined', '')?.trim().includes("'") ) { - const typesRaw = attribute.type?.text.split(' | '); + const typesRaw = attribute.type?.text?.replace('| undefined', '').split(' | '); const types = []; for (const type in typesRaw) { - const typeValue = typesRaw[type].replaceAll('| ', '').replaceAll('\r\n', '').replaceAll(' ', ''); + const typeValue = typesRaw[type] + .replaceAll('| ', '') + .replace(/(\r\n|\n|\r)/gm, '') + .replaceAll(' ', ''); types.push(typeValue.substring(1, typeValue.length - 1)); } const startValue = this.data diff --git a/src/utils/StoryUtils.ts b/src/utils/StoryUtils.ts index 06df49d5e..b259651af 100644 --- a/src/utils/StoryUtils.ts +++ b/src/utils/StoryUtils.ts @@ -482,12 +482,16 @@ function filterJsDocLinks(jsdoc: string) { function transformFromJsdoc(jsdoc: string) { if (!jsdoc) return jsdoc; - const newline = '\r\n'; - jsdoc = filterJsDocLinks(jsdoc); - jsdoc = jsdoc.replace(new RegExp(newline, 'g'), raw`
`); + + jsdoc = jsdoc.replace(new RegExp(//, 'g'), raw`>`); + + jsdoc = jsdoc.replace(/(\r\n|\n|\r)/gm, raw`
`); jsdoc = jsdoc.replace(new RegExp(/\*/, 'g'), '•'); + jsdoc = jsdoc.replace(/(`(.*?)`)/gi, raw`$2`); + return jsdoc; }