Refine dialog component (#26033)

* Init

* push

* Refine

* Format

* Refine

* Update index.js
This commit is contained in:
Jan Faracik authored and GitHub committed 2026-02-09 11:13:51 -07:00
1 parent f972b9d819
commit a3f2c15bc2
7 files changed
+90 -45

No files matched your search

+1
View File
@@ -17,5 +17,6 @@ module.exports = {
"number-max-precision": 5,
"no-duplicate-selectors": null,
"hue-degree-notation": "number",
"scss/operator-no-newline-after": null,
},
};
@@ -28,9 +28,13 @@ THE SOFTWARE.
Creates a button bar at the bottom of the page for things like "Submit".
The actual buttons should be specified as the body of this tag.
This area will always be visible at the bottom of the screen.
<st:attribute name="borderless">
Hides the border of the bottom app bar unless its overlaying content.
</st:attribute>
</st:documentation>
<div class="jenkins-bottom-app-bar__shadow"></div>
<div class="jenkins-bottom-app-bar__shadow ${attrs.borderless ? 'jenkins-bottom-app-bar__shadow--borderless' : ''}"></div>
<div id="bottom-sticker">
<div class="bottom-sticker-inner jenkins-buttons-row jenkins-buttons-row--equal-width">
<d:invokeBody />
+10 -6
View File
@@ -13,6 +13,7 @@ let _defaults = {
hideCloseButton: false,
allowEmpty: false,
submitButton: false,
preventCloseOnOutsideClick: false,
};
let _typeClassMap = {
@@ -39,11 +40,12 @@ Dialog.prototype.init = function () {
this.dialog.style.minWidth = this.options.minWidth;
document.body.appendChild(this.dialog);
if (this.options.title != null) {
const title = createElementFromHtml(`<div class='jenkins-dialog__title'/>`);
// Append title element
const title = createElementFromHtml(
`<div class='jenkins-dialog__title'><span></span></div>`,
);
this.dialog.appendChild(title);
title.innerText = this.options.title;
}
title.querySelector("span").innerText = this.options.title;
if (this.dialogType === "modal") {
if (this.options.content != null) {
@@ -55,22 +57,24 @@ Dialog.prototype.init = function () {
}
if (this.options.hideCloseButton !== true) {
const closeButton = createElementFromHtml(`
<button class="jenkins-dialog__close-button jenkins-button">
<button class="jenkins-dialog__title__button jenkins-dialog__title__close-button jenkins-button">
<span class="jenkins-visually-hidden">Close</span>
${CLOSE}
</button>
`);
this.dialog.appendChild(closeButton);
title.append(closeButton);
closeButton.addEventListener("click", () =>
this.dialog.dispatchEvent(new Event("cancel")),
);
}
if (!this.options.preventCloseOnOutsideClick) {
this.dialog.addEventListener("click", function (e) {
if (e.target !== e.currentTarget) {
return;
}
this.dispatchEvent(new Event("cancel"));
});
}
this.ok = null;
} else {
this.form = null;
+2 -2
View File
@@ -77,6 +77,7 @@ $semantics: (
--header-height: 4.125rem;
// App bar
--bottom-app-bar-padding: 0.875rem;
--bottom-app-bar-shadow: color-mix(
in sRGB,
var(--text-color-secondary) 8%,
@@ -201,8 +202,7 @@ $semantics: (
--dialog-background: var(--card-background);
--dialog-box-shadow:
var(--jenkins-border--subtle-shadow), 0 5px 25px rgb(0 0 10 / 0.025),
0 0 1.5px color-mix(in sRGB, var(--black) 20%, transparent),
inset 0 0 0 1px rgb(255 255 255 / 0.05);
0 0 1.5px color-mix(in sRGB, var(--black) 20%, transparent);
::backdrop {
--dialog-backdrop-backdrop-filter: blur(0.25px);
+31 -14
View File
@@ -125,25 +125,16 @@
text-overflow: ellipsis;
}
$bottom-app-bar-padding: 0.875rem;
.jenkins-bottom-app-bar__shadow {
--semi-translucent: color-mix(in sRGB, var(--background) 75%, transparent);
--semi-translucent: color-mix(in sRGB, var(--background) 70%, transparent);
position: sticky;
height: calc(
2.375rem + ($bottom-app-bar-padding * 2) + 1px + var(--jenkins-border-width)
2.375rem + (var(--bottom-app-bar-padding) * 2) + 1px +
var(--jenkins-border-width)
);
bottom: -1px;
margin-bottom: calc((2.375rem + $bottom-app-bar-padding) * -1);
backdrop-filter: blur(20px);
background: linear-gradient(
to right,
var(--background),
var(--semi-translucent) 3rem,
var(--semi-translucent) calc(100% - 3rem),
var(--background)
);
margin-bottom: calc((2.375rem + var(--bottom-app-bar-padding)) * -1);
border-top: var(--jenkins-border-width) solid var(--jenkins-border-color);
z-index: 997;
@@ -167,7 +158,33 @@ $bottom-app-bar-padding: 0.875rem;
opacity: 0;
}
&--borderless:not(&--stuck) {
border-top-color: transparent;
}
&--borderless {
margin-top: calc(
(var(--bottom-app-bar-padding) + var(--jenkins-border-width)) * -1
);
}
&--stuck {
&::before {
content: "";
position: absolute;
inset: 0;
backdrop-filter: blur(20px);
}
background: linear-gradient(
to right,
var(--background),
var(--background) 3rem,
var(--semi-translucent),
var(--background) calc(100% - 3rem),
var(--background)
);
&::after {
opacity: 1 !important;
}
@@ -183,5 +200,5 @@ $bottom-app-bar-padding: 0.875rem;
.bottom-sticker-inner {
position: relative;
padding: $bottom-app-bar-padding 0;
padding: var(--bottom-app-bar-padding) 0;
}
+28 -16
View File
@@ -2,6 +2,8 @@ $jenkins-dialog-padding: 1.25rem;
.jenkins-dialog {
--background: var(--dialog-background);
--section-padding: #{$jenkins-dialog-padding};
--bottom-app-bar-padding: #{$jenkins-dialog-padding};
border-radius: 1rem;
border: none;
@@ -9,11 +11,12 @@ $jenkins-dialog-padding: 1.25rem;
box-shadow: var(--dialog-box-shadow);
animation: jenkins-dialog-animate-in 0.25s cubic-bezier(0, 0.68, 0.5, 1.5);
overflow: hidden;
padding: $jenkins-dialog-padding 0 0 0;
padding: 0;
display: flex;
flex-direction: column;
gap: $jenkins-dialog-padding;
outline: none;
// Thin highlight for dark themes to differentiate the dialog from its backdrop
outline: 1px solid rgb(255 255 255 / 0.05);
&::backdrop {
background: color-mix(
@@ -26,13 +29,26 @@ $jenkins-dialog-padding: 1.25rem;
}
&__title {
display: flex;
gap: 1rem;
align-items: center;
font-size: 1rem;
font-weight: var(--font-bold-weight);
padding: 0 $jenkins-dialog-padding;
padding: $jenkins-dialog-padding;
color: var(--text-color);
overflow-wrap: anywhere;
text-box: cap alphabetic;
margin-top: 0.5625rem;
&__button {
padding: 0;
width: 2rem;
min-height: 2rem;
border-radius: 100%;
}
&__close-button {
margin-left: auto !important;
}
}
&__contents {
@@ -62,7 +78,7 @@ $jenkins-dialog-padding: 1.25rem;
&__buttons {
display: flex;
padding: 0 $jenkins-dialog-padding $jenkins-dialog-padding;
padding: $jenkins-dialog-padding;
justify-content: right;
flex-direction: row-reverse;
gap: 1.25rem;
@@ -80,16 +96,6 @@ $jenkins-dialog-padding: 1.25rem;
margin: 0 0 1rem;
}
&__close-button {
position: absolute;
top: $jenkins-dialog-padding;
right: $jenkins-dialog-padding;
padding: 0;
width: 2rem;
min-height: 2rem;
border-radius: 100%;
}
&[closing] {
animation: jenkins-dialog-animate-out 0.1s linear;
@@ -97,6 +103,12 @@ $jenkins-dialog-padding: 1.25rem;
animation: jenkins-dialog-backdrop-animate-out 0.1s linear;
}
}
.jenkins-bottom-app-bar__shadow {
margin-bottom: calc(
(2.375rem + calc(var(--bottom-app-bar-padding) * 2)) * -1
);
}
}
@keyframes jenkins-dialog-backdrop-animate-in {
+13 -6
View File
@@ -1781,22 +1781,29 @@ function rowvgStartEachRow(recursive, f) {
},
);
window.addEventListener("load", function () {
// Add a class to the bottom bar when it's stuck to the bottom of the screen
const el = document.querySelector(".jenkins-bottom-app-bar__shadow");
if (el) {
Behaviour.specify(
".jenkins-bottom-app-bar__shadow",
"jenkins-bottom-app-bar__shadow",
0,
function (el) {
const dialog = el.closest("dialog");
const observer = new IntersectionObserver(
([e]) =>
e.target.classList.toggle(
"jenkins-bottom-app-bar__shadow--stuck",
e.intersectionRatio < 1,
),
{ threshold: [1] },
{
threshold: [1],
root: dialog || null,
},
);
observer.observe(el);
}
});
},
);
/**
* Function that provides compatibility to the checkboxes without title on an f:entry