Compare commits
1 Commits
v6-stepper
...
v6-dist
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b9f1fcaab |
Vendored
+13
-13
@@ -4,19 +4,19 @@
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root {
|
||||
--bs-blue-025: color-mix(in lab, #fff 94%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-050: color-mix(in lab, #fff 90%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-100: color-mix(in lab, #fff 80%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-200: color-mix(in lab, #fff 60%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-300: color-mix(in lab, #fff 40%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-400: color-mix(in lab, #fff 20%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-500: oklch(60% 0.24 258deg);
|
||||
--bs-blue-600: color-mix(in lab, #000 16%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-700: color-mix(in lab, #000 32%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-800: color-mix(in lab, #000 48%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-900: color-mix(in lab, #000 64%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-950: color-mix(in lab, #000 76%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-975: color-mix(in lab, #000 88%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-025: color-mix(in lab, #fff 94%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-050: color-mix(in lab, #fff 90%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-100: color-mix(in lab, #fff 80%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-200: color-mix(in lab, #fff 60%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-300: color-mix(in lab, #fff 40%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-400: color-mix(in lab, #fff 20%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-500: oklch(60% 0.24 240deg);
|
||||
--bs-blue-600: color-mix(in lab, #000 16%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-700: color-mix(in lab, #000 32%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-800: color-mix(in lab, #000 48%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-900: color-mix(in lab, #000 64%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-950: color-mix(in lab, #000 76%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-975: color-mix(in lab, #000 88%, oklch(60% 0.24 240deg));
|
||||
--bs-indigo-025: color-mix(in lab, #fff 94%, oklch(56% 0.26 288deg));
|
||||
--bs-indigo-050: color-mix(in lab, #fff 90%, oklch(56% 0.26 288deg));
|
||||
--bs-indigo-100: color-mix(in lab, #fff 80%, oklch(56% 0.26 288deg));
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+19
-20
@@ -4,19 +4,19 @@
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root {
|
||||
--bs-blue-025: color-mix(in lab, #fff 94%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-050: color-mix(in lab, #fff 90%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-100: color-mix(in lab, #fff 80%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-200: color-mix(in lab, #fff 60%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-300: color-mix(in lab, #fff 40%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-400: color-mix(in lab, #fff 20%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-500: oklch(60% 0.24 258deg);
|
||||
--bs-blue-600: color-mix(in lab, #000 16%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-700: color-mix(in lab, #000 32%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-800: color-mix(in lab, #000 48%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-900: color-mix(in lab, #000 64%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-950: color-mix(in lab, #000 76%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-975: color-mix(in lab, #000 88%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-025: color-mix(in lab, #fff 94%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-050: color-mix(in lab, #fff 90%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-100: color-mix(in lab, #fff 80%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-200: color-mix(in lab, #fff 60%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-300: color-mix(in lab, #fff 40%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-400: color-mix(in lab, #fff 20%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-500: oklch(60% 0.24 240deg);
|
||||
--bs-blue-600: color-mix(in lab, #000 16%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-700: color-mix(in lab, #000 32%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-800: color-mix(in lab, #000 48%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-900: color-mix(in lab, #000 64%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-950: color-mix(in lab, #000 76%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-975: color-mix(in lab, #000 88%, oklch(60% 0.24 240deg));
|
||||
--bs-indigo-025: color-mix(in lab, #fff 94%, oklch(56% 0.26 288deg));
|
||||
--bs-indigo-050: color-mix(in lab, #fff 90%, oklch(56% 0.26 288deg));
|
||||
--bs-indigo-100: color-mix(in lab, #fff 80%, oklch(56% 0.26 288deg));
|
||||
@@ -450,6 +450,7 @@
|
||||
--bs-body-color-rgb: to-rgb(var(--bs-color-body));
|
||||
--bs-body-bg-rgb: to-rgb(var(--bs-bg-body));
|
||||
--bs-heading-color: inherit;
|
||||
--bs-hr-border-color: var(--bs-border-color);
|
||||
--bs-link-color: light-dark(var(--bs-primary-base), var(--bs-primary-text));
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: color-mix(in oklch, var(--bs-link-color) 90%, #000);
|
||||
@@ -471,7 +472,7 @@
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 3px;
|
||||
--bs-focus-ring-offset: -1px;
|
||||
--bs-focus-ring-offset: 1px;
|
||||
--bs-focus-ring-color: var(--bs-primary-focus-ring);
|
||||
--bs-focus-ring: var(--bs-focus-ring-width) solid var(--bs-focus-ring-color);
|
||||
--bs-form-valid-color: var(--bs-success);
|
||||
@@ -521,10 +522,8 @@
|
||||
}
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-block-start: var(--bs-border-width) solid;
|
||||
opacity: 0.25;
|
||||
border-block-start: var(--bs-border-width) solid var(--bs-hr-border-color);
|
||||
}
|
||||
h6,
|
||||
.h6, h5,
|
||||
@@ -633,13 +632,13 @@
|
||||
top: -0.5em;
|
||||
}
|
||||
a {
|
||||
color: var(--bs-link-color);
|
||||
color: var(--bs-theme-text, var(--bs-link-color));
|
||||
-webkit-text-decoration: var(--bs-link-decoration);
|
||||
text-decoration: var(--bs-link-decoration);
|
||||
text-underline-offset: 0.2em;
|
||||
}
|
||||
a:hover {
|
||||
color: var(--bs-link-hover-color);
|
||||
color: var(--bs-theme-text-emphasis, var(--bs-link-hover-color));
|
||||
-webkit-text-decoration: var(--bs-link-hover-decoration, var(--bs-link-decoration));
|
||||
text-decoration: var(--bs-link-hover-decoration, var(--bs-link-decoration));
|
||||
}
|
||||
@@ -678,7 +677,7 @@
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 95%;
|
||||
color: var(--bs-bg-body);
|
||||
background-color: var(--bs-color-body);
|
||||
background-color: var(--bs-fg-body);
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
kbd kbd {
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+61
-146
@@ -4,19 +4,19 @@
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root {
|
||||
--bs-blue-025: color-mix(in lab, #fff 94%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-050: color-mix(in lab, #fff 90%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-100: color-mix(in lab, #fff 80%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-200: color-mix(in lab, #fff 60%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-300: color-mix(in lab, #fff 40%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-400: color-mix(in lab, #fff 20%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-500: oklch(60% 0.24 258deg);
|
||||
--bs-blue-600: color-mix(in lab, #000 16%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-700: color-mix(in lab, #000 32%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-800: color-mix(in lab, #000 48%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-900: color-mix(in lab, #000 64%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-950: color-mix(in lab, #000 76%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-975: color-mix(in lab, #000 88%, oklch(60% 0.24 258deg));
|
||||
--bs-blue-025: color-mix(in lab, #fff 94%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-050: color-mix(in lab, #fff 90%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-100: color-mix(in lab, #fff 80%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-200: color-mix(in lab, #fff 60%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-300: color-mix(in lab, #fff 40%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-400: color-mix(in lab, #fff 20%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-500: oklch(60% 0.24 240deg);
|
||||
--bs-blue-600: color-mix(in lab, #000 16%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-700: color-mix(in lab, #000 32%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-800: color-mix(in lab, #000 48%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-900: color-mix(in lab, #000 64%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-950: color-mix(in lab, #000 76%, oklch(60% 0.24 240deg));
|
||||
--bs-blue-975: color-mix(in lab, #000 88%, oklch(60% 0.24 240deg));
|
||||
--bs-indigo-025: color-mix(in lab, #fff 94%, oklch(56% 0.26 288deg));
|
||||
--bs-indigo-050: color-mix(in lab, #fff 90%, oklch(56% 0.26 288deg));
|
||||
--bs-indigo-100: color-mix(in lab, #fff 80%, oklch(56% 0.26 288deg));
|
||||
@@ -450,6 +450,7 @@
|
||||
--bs-body-color-rgb: to-rgb(var(--bs-color-body));
|
||||
--bs-body-bg-rgb: to-rgb(var(--bs-bg-body));
|
||||
--bs-heading-color: inherit;
|
||||
--bs-hr-border-color: var(--bs-border-color);
|
||||
--bs-link-color: light-dark(var(--bs-primary-base), var(--bs-primary-text));
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: color-mix(in oklch, var(--bs-link-color) 90%, #000);
|
||||
@@ -471,7 +472,7 @@
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 3px;
|
||||
--bs-focus-ring-offset: -1px;
|
||||
--bs-focus-ring-offset: 1px;
|
||||
--bs-focus-ring-color: var(--bs-primary-focus-ring);
|
||||
--bs-focus-ring: var(--bs-focus-ring-width) solid var(--bs-focus-ring-color);
|
||||
--bs-form-valid-color: var(--bs-success);
|
||||
@@ -493,106 +494,6 @@
|
||||
--bs-form-invalid-border-color: var(--bs-red-300);
|
||||
}
|
||||
|
||||
@layer helpers {
|
||||
.text-bg-primary {
|
||||
color: var(--bs-primary-text);
|
||||
--bs-bg: var(--bs-primary-bg-subtle);
|
||||
}
|
||||
.text-bg-accent {
|
||||
color: var(--bs-accent-text);
|
||||
--bs-bg: var(--bs-accent-bg-subtle);
|
||||
}
|
||||
.text-bg-success {
|
||||
color: var(--bs-success-text);
|
||||
--bs-bg: var(--bs-success-bg-subtle);
|
||||
}
|
||||
.text-bg-danger {
|
||||
color: var(--bs-danger-text);
|
||||
--bs-bg: var(--bs-danger-bg-subtle);
|
||||
}
|
||||
.text-bg-warning {
|
||||
color: var(--bs-warning-text);
|
||||
--bs-bg: var(--bs-warning-bg-subtle);
|
||||
}
|
||||
.text-bg-info {
|
||||
color: var(--bs-info-text);
|
||||
--bs-bg: var(--bs-info-bg-subtle);
|
||||
}
|
||||
.text-bg-inverse {
|
||||
color: var(--bs-inverse-text);
|
||||
--bs-bg: var(--bs-inverse-bg-subtle);
|
||||
}
|
||||
.text-bg-secondary {
|
||||
color: var(--bs-secondary-text);
|
||||
--bs-bg: var(--bs-secondary-bg-subtle);
|
||||
}
|
||||
}
|
||||
@layer helpers {
|
||||
.link-primary {
|
||||
--bs-link-color: var(--bs-primary-text);
|
||||
}
|
||||
.link-primary:hover, .link-primary:focus {
|
||||
--bs-link-color: var(--bs-primary-text-emphasis);
|
||||
--bs-link-hover-color: var(--bs-primary-text-emphasis);
|
||||
}
|
||||
.link-accent {
|
||||
--bs-link-color: var(--bs-accent-text);
|
||||
}
|
||||
.link-accent:hover, .link-accent:focus {
|
||||
--bs-link-color: var(--bs-accent-text-emphasis);
|
||||
--bs-link-hover-color: var(--bs-accent-text-emphasis);
|
||||
}
|
||||
.link-success {
|
||||
--bs-link-color: var(--bs-success-text);
|
||||
}
|
||||
.link-success:hover, .link-success:focus {
|
||||
--bs-link-color: var(--bs-success-text-emphasis);
|
||||
--bs-link-hover-color: var(--bs-success-text-emphasis);
|
||||
}
|
||||
.link-danger {
|
||||
--bs-link-color: var(--bs-danger-text);
|
||||
}
|
||||
.link-danger:hover, .link-danger:focus {
|
||||
--bs-link-color: var(--bs-danger-text-emphasis);
|
||||
--bs-link-hover-color: var(--bs-danger-text-emphasis);
|
||||
}
|
||||
.link-warning {
|
||||
--bs-link-color: var(--bs-warning-text);
|
||||
}
|
||||
.link-warning:hover, .link-warning:focus {
|
||||
--bs-link-color: var(--bs-warning-text-emphasis);
|
||||
--bs-link-hover-color: var(--bs-warning-text-emphasis);
|
||||
}
|
||||
.link-info {
|
||||
--bs-link-color: var(--bs-info-text);
|
||||
}
|
||||
.link-info:hover, .link-info:focus {
|
||||
--bs-link-color: var(--bs-info-text-emphasis);
|
||||
--bs-link-hover-color: var(--bs-info-text-emphasis);
|
||||
}
|
||||
.link-inverse {
|
||||
--bs-link-color: var(--bs-inverse-text);
|
||||
}
|
||||
.link-inverse:hover, .link-inverse:focus {
|
||||
--bs-link-color: var(--bs-inverse-text-emphasis);
|
||||
--bs-link-hover-color: var(--bs-inverse-text-emphasis);
|
||||
}
|
||||
.link-secondary {
|
||||
--bs-link-color: var(--bs-secondary-text);
|
||||
}
|
||||
.link-secondary:hover, .link-secondary:focus {
|
||||
--bs-link-color: var(--bs-secondary-text-emphasis);
|
||||
--bs-link-hover-color: var(--bs-secondary-text-emphasis);
|
||||
}
|
||||
.link-body-emphasis {
|
||||
color: color-mix(in srgb, var(--bs-emphasis-color), transparent var(--bs-link-opacity));
|
||||
text-decoration-color: color-mix(in srgb, var(--bs-emphasis-color), transparent var(--bs-link-underline-opacity));
|
||||
}
|
||||
.link-body-emphasis:hover, .link-body-emphasis:focus {
|
||||
color: color-mix(in srgb, var(--bs-emphasis-color), transparent var(--bs-link-opacity, 0.75));
|
||||
text-decoration-color: color-mix(in srgb, var(--bs-emphasis-color), transparent var(--bs-link-underline-opacity, 0.75));
|
||||
}
|
||||
}
|
||||
@layer helpers {
|
||||
.focus-ring:focus-visible {
|
||||
outline: var(--bs-focus-ring);
|
||||
@@ -770,8 +671,7 @@
|
||||
align-self: stretch;
|
||||
width: var(--bs-border-width);
|
||||
min-height: 1em;
|
||||
background-color: currentcolor;
|
||||
opacity: 0.25;
|
||||
background-color: var(--bs-border-color);
|
||||
}
|
||||
}
|
||||
@layer utilities {
|
||||
@@ -2091,36 +1991,6 @@
|
||||
--bs-fg: light-dark(var(--bs-gray-800), var(--bs-gray-200));
|
||||
color: var(--bs-fg);
|
||||
}
|
||||
.fg-10 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 10%, transparent);
|
||||
}
|
||||
.fg-20 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 20%, transparent);
|
||||
}
|
||||
.fg-30 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 30%, transparent);
|
||||
}
|
||||
.fg-40 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 40%, transparent);
|
||||
}
|
||||
.fg-50 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 50%, transparent);
|
||||
}
|
||||
.fg-60 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 60%, transparent);
|
||||
}
|
||||
.fg-70 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 70%, transparent);
|
||||
}
|
||||
.fg-80 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 80%, transparent);
|
||||
}
|
||||
.fg-90 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 90%, transparent);
|
||||
}
|
||||
.fg-100 {
|
||||
color: var(--bs-fg);
|
||||
}
|
||||
.fg-contrast-primary {
|
||||
--bs-fg: var(--bs-white);
|
||||
color: var(--bs-fg);
|
||||
@@ -2153,6 +2023,36 @@
|
||||
--bs-fg: light-dark(var(--bs-gray-900), var(--bs-white));
|
||||
color: var(--bs-fg);
|
||||
}
|
||||
.fg-10 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 10%, transparent);
|
||||
}
|
||||
.fg-20 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 20%, transparent);
|
||||
}
|
||||
.fg-30 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 30%, transparent);
|
||||
}
|
||||
.fg-40 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 40%, transparent);
|
||||
}
|
||||
.fg-50 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 50%, transparent);
|
||||
}
|
||||
.fg-60 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 60%, transparent);
|
||||
}
|
||||
.fg-70 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 70%, transparent);
|
||||
}
|
||||
.fg-80 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 80%, transparent);
|
||||
}
|
||||
.fg-90 {
|
||||
color: color-mix(in oklch, var(--bs-fg) 90%, transparent);
|
||||
}
|
||||
.fg-100 {
|
||||
color: var(--bs-fg);
|
||||
}
|
||||
.link-10 {
|
||||
color: color-mix(in oklch, var(--bs-link-color) 10%, transparent);
|
||||
}
|
||||
@@ -2507,6 +2407,21 @@
|
||||
.bg-100 {
|
||||
background-color: var(--bs-bg);
|
||||
}
|
||||
.theme-contrast {
|
||||
background-color: var(--bs-theme-bg);
|
||||
color: var(--bs-theme-contrast);
|
||||
}
|
||||
.theme-subtle {
|
||||
background-color: var(--bs-theme-bg-subtle);
|
||||
color: var(--bs-theme-text);
|
||||
}
|
||||
.theme-muted {
|
||||
background-color: var(--bs-theme-bg-muted);
|
||||
color: var(--bs-theme-text-emphasis);
|
||||
}
|
||||
.theme-border {
|
||||
border: var(--bs-border-width) solid var(--bs-theme-border);
|
||||
}
|
||||
.bg-gradient {
|
||||
background-image: var(--bs-gradient);
|
||||
}
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+528
-352
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1258
-268
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1256
-269
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1258
-268
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+471
-48
@@ -29,8 +29,16 @@
|
||||
const TAB_KEY = 'Tab';
|
||||
const ARROW_UP_KEY = 'ArrowUp';
|
||||
const ARROW_DOWN_KEY = 'ArrowDown';
|
||||
const RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button
|
||||
const ARROW_LEFT_KEY = 'ArrowLeft';
|
||||
const ARROW_RIGHT_KEY = 'ArrowRight';
|
||||
const HOME_KEY = 'Home';
|
||||
const END_KEY = 'End';
|
||||
const ENTER_KEY = 'Enter';
|
||||
const SPACE_KEY = ' ';
|
||||
const RIGHT_MOUSE_BUTTON = 2;
|
||||
|
||||
// Hover intent delay (ms) - grace period before closing submenu
|
||||
const SUBMENU_CLOSE_DELAY = 100;
|
||||
const EVENT_HIDE = `hide${EVENT_KEY}`;
|
||||
const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
|
||||
const EVENT_SHOW = `show${EVENT_KEY}`;
|
||||
@@ -42,11 +50,28 @@
|
||||
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)';
|
||||
const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`;
|
||||
const SELECTOR_MENU = '.dropdown-menu';
|
||||
const SELECTOR_SUBMENU = '.dropdown-submenu';
|
||||
const SELECTOR_SUBMENU_TOGGLE = '.dropdown-submenu > .dropdown-item';
|
||||
const SELECTOR_NAVBAR_NAV = '.navbar-nav';
|
||||
const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';
|
||||
const SELECTOR_VISIBLE_ITEMS = '.dropdown-item:not(.disabled):not(:disabled)';
|
||||
|
||||
// Default placement with RTL support
|
||||
const DEFAULT_PLACEMENT = index_js.isRTL() ? 'bottom-end' : 'bottom-start';
|
||||
// Default logical placement (uses start/end which get resolved to left/right based on RTL)
|
||||
const DEFAULT_PLACEMENT = 'bottom-start';
|
||||
const SUBMENU_PLACEMENT = 'end-start';
|
||||
|
||||
// Resolve logical placement (start/end) to physical (left/right) based on RTL
|
||||
const resolveLogicalPlacement = placement => {
|
||||
if (index_js.isRTL()) {
|
||||
// RTL: start → right, end → left
|
||||
return placement.replace(/^start(?=-|$)/, 'right').replace(/^end(?=-|$)/, 'left');
|
||||
}
|
||||
|
||||
// LTR: start → left, end → right
|
||||
return placement.replace(/^start(?=-|$)/, 'left').replace(/^end(?=-|$)/, 'right');
|
||||
};
|
||||
|
||||
// Helper for barycentric coordinate calculation (point in triangle check)
|
||||
const triangleSign = (p1, p2, p3) => (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);
|
||||
const Default = {
|
||||
autoClose: true,
|
||||
boundary: 'clippingParents',
|
||||
@@ -54,7 +79,11 @@
|
||||
offset: [0, 2],
|
||||
floatingConfig: null,
|
||||
placement: DEFAULT_PLACEMENT,
|
||||
reference: 'toggle'
|
||||
reference: 'toggle',
|
||||
// Submenu options
|
||||
submenuTrigger: 'both',
|
||||
// 'click', 'hover', or 'both'
|
||||
submenuDelay: SUBMENU_CLOSE_DELAY
|
||||
};
|
||||
const DefaultType = {
|
||||
autoClose: '(boolean|string)',
|
||||
@@ -63,7 +92,9 @@
|
||||
offset: '(array|string|function)',
|
||||
floatingConfig: '(null|object|function)',
|
||||
placement: 'string',
|
||||
reference: '(string|element|object)'
|
||||
reference: '(string|element|object)',
|
||||
submenuTrigger: 'string',
|
||||
submenuDelay: 'number'
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -80,11 +111,19 @@
|
||||
this._mediaQueryListeners = [];
|
||||
this._responsivePlacements = null;
|
||||
this._parent = this._element.parentNode; // dropdown wrapper
|
||||
this._isSubmenu = this._parent.classList.contains('dropdown-submenu');
|
||||
this._openSubmenus = new Map(); // Map of submenu element -> cleanup function
|
||||
this._submenuCloseTimeouts = new Map(); // Map of submenu element -> timeout ID
|
||||
this._hoverIntentData = null; // For safe triangle calculation
|
||||
|
||||
// TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
|
||||
this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] || SelectorEngine.findOne(SELECTOR_MENU, this._parent);
|
||||
|
||||
// Parse responsive placements on init
|
||||
this._parseResponsivePlacements();
|
||||
|
||||
// Set up submenu event listeners
|
||||
this._setupSubmenuListeners();
|
||||
}
|
||||
|
||||
// Getters
|
||||
@@ -125,9 +164,10 @@
|
||||
}
|
||||
}
|
||||
this._element.focus();
|
||||
this._element.setAttribute('aria-expanded', true);
|
||||
this._element.setAttribute('aria-expanded', 'true');
|
||||
this._menu.classList.add(CLASS_NAME_SHOW);
|
||||
this._element.classList.add(CLASS_NAME_SHOW);
|
||||
this._parent.classList.add(CLASS_NAME_SHOW);
|
||||
EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget);
|
||||
}
|
||||
hide() {
|
||||
@@ -142,6 +182,8 @@
|
||||
dispose() {
|
||||
this._disposeFloating();
|
||||
this._disposeMediaQueryListeners();
|
||||
this._closeAllSubmenus();
|
||||
this._clearAllSubmenuTimeouts();
|
||||
super.dispose();
|
||||
}
|
||||
update() {
|
||||
@@ -157,6 +199,9 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Close all open submenus first
|
||||
this._closeAllSubmenus();
|
||||
|
||||
// If this is a touch-enabled device we remove the extra
|
||||
// empty mouseover listeners we added for iOS support
|
||||
if ('ontouchstart' in document.documentElement) {
|
||||
@@ -167,6 +212,7 @@
|
||||
this._disposeFloating();
|
||||
this._menu.classList.remove(CLASS_NAME_SHOW);
|
||||
this._element.classList.remove(CLASS_NAME_SHOW);
|
||||
this._parent.classList.remove(CLASS_NAME_SHOW);
|
||||
this._element.setAttribute('aria-expanded', 'false');
|
||||
Manipulator.removeDataAttribute(this._menu, 'placement');
|
||||
Manipulator.removeDataAttribute(this._menu, 'display');
|
||||
@@ -201,8 +247,7 @@
|
||||
this._floatingCleanup = dom.autoUpdate(referenceElement, this._menu, () => this._updateFloatingPosition(referenceElement));
|
||||
}
|
||||
async _updateFloatingPosition(referenceElement = null) {
|
||||
// Check if menu exists and is still in the DOM
|
||||
if (!this._menu || !this._menu.isConnected) {
|
||||
if (!this._menu) {
|
||||
return;
|
||||
}
|
||||
if (!referenceElement) {
|
||||
@@ -219,37 +264,17 @@
|
||||
const placement = this._getPlacement();
|
||||
const middleware = this._getFloatingMiddleware();
|
||||
const floatingConfig = this._getFloatingConfig(placement, middleware);
|
||||
const {
|
||||
x,
|
||||
y,
|
||||
placement: finalPlacement
|
||||
} = await dom.computePosition(referenceElement, this._menu, floatingConfig);
|
||||
|
||||
// Menu may have been disposed during the async computePosition call
|
||||
if (!this._menu || !this._menu.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply position to dropdown menu
|
||||
Object.assign(this._menu.style, {
|
||||
position: 'absolute',
|
||||
left: `${x}px`,
|
||||
top: `${y}px`,
|
||||
margin: '0'
|
||||
});
|
||||
|
||||
// Set placement attribute for CSS styling
|
||||
Manipulator.setDataAttribute(this._menu, 'placement', finalPlacement);
|
||||
await this._applyFloatingPosition(referenceElement, this._menu, floatingConfig.placement, floatingConfig.middleware);
|
||||
}
|
||||
_isShown() {
|
||||
return this._menu.classList.contains(CLASS_NAME_SHOW);
|
||||
}
|
||||
_getPlacement() {
|
||||
// If we have responsive placements, find the appropriate one for current viewport
|
||||
if (this._responsivePlacements) {
|
||||
return floatingUi_js.getResponsivePlacement(this._responsivePlacements, DEFAULT_PLACEMENT);
|
||||
}
|
||||
return this._config.placement;
|
||||
const placement = this._responsivePlacements ? floatingUi_js.getResponsivePlacement(this._responsivePlacements, DEFAULT_PLACEMENT) : this._config.placement;
|
||||
|
||||
// Resolve logical placements (start/end) to physical (left/right) based on RTL
|
||||
return resolveLogicalPlacement(placement);
|
||||
}
|
||||
_parseResponsivePlacements() {
|
||||
this._responsivePlacements = floatingUi_js.parseResponsivePlacement(this._config.placement, DEFAULT_PLACEMENT);
|
||||
@@ -271,18 +296,18 @@
|
||||
}
|
||||
_getOffset() {
|
||||
const {
|
||||
offset
|
||||
offset: offsetConfig
|
||||
} = this._config;
|
||||
if (typeof offset === 'string') {
|
||||
return offset.split(',').map(value => Number.parseInt(value, 10));
|
||||
if (typeof offsetConfig === 'string') {
|
||||
return offsetConfig.split(',').map(value => Number.parseInt(value, 10));
|
||||
}
|
||||
if (typeof offset === 'function') {
|
||||
if (typeof offsetConfig === 'function') {
|
||||
// Floating UI passes different args, adapt the interface for offset function callbacks
|
||||
return ({
|
||||
placement,
|
||||
rects
|
||||
}) => {
|
||||
const result = offset({
|
||||
const result = offsetConfig({
|
||||
placement,
|
||||
reference: rects.reference,
|
||||
floating: rects.floating
|
||||
@@ -290,7 +315,7 @@
|
||||
return result;
|
||||
};
|
||||
}
|
||||
return offset;
|
||||
return offsetConfig;
|
||||
}
|
||||
_getFloatingMiddleware() {
|
||||
const offsetValue = this._getOffset();
|
||||
@@ -348,11 +373,296 @@
|
||||
this._floatingCleanup = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Shared helper for positioning any floating element
|
||||
async _applyFloatingPosition(reference, floating, placement, middleware) {
|
||||
if (!floating.isConnected) {
|
||||
return null;
|
||||
}
|
||||
const {
|
||||
x,
|
||||
y,
|
||||
placement: finalPlacement
|
||||
} = await dom.computePosition(reference, floating, {
|
||||
placement,
|
||||
middleware
|
||||
});
|
||||
if (!floating.isConnected) {
|
||||
return null;
|
||||
}
|
||||
Object.assign(floating.style, {
|
||||
position: 'absolute',
|
||||
left: `${x}px`,
|
||||
top: `${y}px`,
|
||||
margin: '0'
|
||||
});
|
||||
Manipulator.setDataAttribute(floating, 'placement', finalPlacement);
|
||||
return finalPlacement;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Submenu handling
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
_setupSubmenuListeners() {
|
||||
// Set up hover listeners for submenu triggers
|
||||
if (this._config.submenuTrigger === 'hover' || this._config.submenuTrigger === 'both') {
|
||||
EventHandler.on(this._menu, 'mouseenter', SELECTOR_SUBMENU_TOGGLE, event => {
|
||||
this._onSubmenuTriggerEnter(event);
|
||||
});
|
||||
EventHandler.on(this._menu, 'mouseleave', SELECTOR_SUBMENU, event => {
|
||||
this._onSubmenuLeave(event);
|
||||
});
|
||||
|
||||
// Track mouse movement for safe triangle calculation
|
||||
EventHandler.on(this._menu, 'mousemove', event => {
|
||||
this._trackMousePosition(event);
|
||||
});
|
||||
}
|
||||
|
||||
// Set up click listener for submenu triggers
|
||||
if (this._config.submenuTrigger === 'click' || this._config.submenuTrigger === 'both') {
|
||||
EventHandler.on(this._menu, 'click', SELECTOR_SUBMENU_TOGGLE, event => {
|
||||
this._onSubmenuTriggerClick(event);
|
||||
});
|
||||
}
|
||||
}
|
||||
_onSubmenuTriggerEnter(event) {
|
||||
const trigger = event.target.closest(SELECTOR_SUBMENU_TOGGLE);
|
||||
if (!trigger) {
|
||||
return;
|
||||
}
|
||||
const submenuWrapper = trigger.closest(SELECTOR_SUBMENU);
|
||||
const submenu = SelectorEngine.findOne(SELECTOR_MENU, submenuWrapper);
|
||||
if (!submenu) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cancel any pending close timeout for this submenu
|
||||
this._cancelSubmenuCloseTimeout(submenu);
|
||||
|
||||
// Close other open submenus at the same level
|
||||
this._closeSiblingSubmenus(submenuWrapper);
|
||||
|
||||
// Open this submenu
|
||||
this._openSubmenu(trigger, submenu, submenuWrapper);
|
||||
}
|
||||
_onSubmenuLeave(event) {
|
||||
const submenuWrapper = event.target.closest(SELECTOR_SUBMENU);
|
||||
const submenu = SelectorEngine.findOne(SELECTOR_MENU, submenuWrapper);
|
||||
if (!submenu || !this._openSubmenus.has(submenu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we're moving toward the submenu (safe triangle)
|
||||
if (this._isMovingTowardSubmenu(event, submenu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule submenu close with delay
|
||||
this._scheduleSubmenuClose(submenu, submenuWrapper);
|
||||
}
|
||||
_onSubmenuTriggerClick(event) {
|
||||
const trigger = event.target.closest(SELECTOR_SUBMENU_TOGGLE);
|
||||
if (!trigger) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const submenuWrapper = trigger.closest(SELECTOR_SUBMENU);
|
||||
const submenu = SelectorEngine.findOne(SELECTOR_MENU, submenuWrapper);
|
||||
if (!submenu) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle submenu
|
||||
if (this._openSubmenus.has(submenu)) {
|
||||
this._closeSubmenu(submenu, submenuWrapper);
|
||||
} else {
|
||||
this._closeSiblingSubmenus(submenuWrapper);
|
||||
this._openSubmenu(trigger, submenu, submenuWrapper);
|
||||
}
|
||||
}
|
||||
_openSubmenu(trigger, submenu, submenuWrapper) {
|
||||
if (this._openSubmenus.has(submenu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set ARIA attributes
|
||||
trigger.setAttribute('aria-expanded', 'true');
|
||||
trigger.setAttribute('aria-haspopup', 'true');
|
||||
|
||||
// Position and show submenu
|
||||
submenu.classList.add(CLASS_NAME_SHOW);
|
||||
submenuWrapper.classList.add(CLASS_NAME_SHOW);
|
||||
|
||||
// Set up Floating UI positioning for submenu
|
||||
const cleanup = this._createSubmenuFloating(trigger, submenu, submenuWrapper);
|
||||
this._openSubmenus.set(submenu, cleanup);
|
||||
|
||||
// Set up mouseenter on submenu to cancel close timeout
|
||||
EventHandler.on(submenu, 'mouseenter', () => {
|
||||
this._cancelSubmenuCloseTimeout(submenu);
|
||||
});
|
||||
}
|
||||
_closeSubmenu(submenu, submenuWrapper) {
|
||||
if (!this._openSubmenus.has(submenu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Close any nested submenus first
|
||||
const nestedSubmenus = SelectorEngine.find(`${SELECTOR_SUBMENU} ${SELECTOR_MENU}.${CLASS_NAME_SHOW}`, submenu);
|
||||
for (const nested of nestedSubmenus) {
|
||||
const nestedWrapper = nested.closest(SELECTOR_SUBMENU);
|
||||
this._closeSubmenu(nested, nestedWrapper);
|
||||
}
|
||||
|
||||
// Get the trigger
|
||||
const trigger = SelectorEngine.findOne(SELECTOR_SUBMENU_TOGGLE, submenuWrapper);
|
||||
|
||||
// Clean up Floating UI
|
||||
const cleanup = this._openSubmenus.get(submenu);
|
||||
if (cleanup) {
|
||||
cleanup();
|
||||
}
|
||||
this._openSubmenus.delete(submenu);
|
||||
|
||||
// Remove event listeners
|
||||
EventHandler.off(submenu, 'mouseenter');
|
||||
|
||||
// Update ARIA and visibility
|
||||
if (trigger) {
|
||||
trigger.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
submenu.classList.remove(CLASS_NAME_SHOW);
|
||||
submenuWrapper.classList.remove(CLASS_NAME_SHOW);
|
||||
|
||||
// Clear inline styles
|
||||
submenu.style.position = '';
|
||||
submenu.style.left = '';
|
||||
submenu.style.top = '';
|
||||
submenu.style.margin = '';
|
||||
}
|
||||
_closeAllSubmenus() {
|
||||
for (const [submenu] of this._openSubmenus) {
|
||||
const submenuWrapper = submenu.closest(SELECTOR_SUBMENU);
|
||||
this._closeSubmenu(submenu, submenuWrapper);
|
||||
}
|
||||
}
|
||||
_closeSiblingSubmenus(currentSubmenuWrapper) {
|
||||
// Find all sibling submenu wrappers and close their menus
|
||||
const parent = currentSubmenuWrapper.parentNode;
|
||||
const siblingSubmenus = SelectorEngine.find(`${SELECTOR_SUBMENU} > ${SELECTOR_MENU}.${CLASS_NAME_SHOW}`, parent);
|
||||
for (const siblingMenu of siblingSubmenus) {
|
||||
const siblingWrapper = siblingMenu.closest(SELECTOR_SUBMENU);
|
||||
if (siblingWrapper !== currentSubmenuWrapper) {
|
||||
this._closeSubmenu(siblingMenu, siblingWrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
_createSubmenuFloating(trigger, submenu, submenuWrapper) {
|
||||
const referenceElement = submenuWrapper;
|
||||
const placement = resolveLogicalPlacement(SUBMENU_PLACEMENT);
|
||||
const middleware = [dom.offset({
|
||||
mainAxis: 0,
|
||||
crossAxis: -4
|
||||
}), dom.flip({
|
||||
fallbackPlacements: [resolveLogicalPlacement('start-start'), resolveLogicalPlacement('end-end'), resolveLogicalPlacement('start-end')]
|
||||
}), dom.shift({
|
||||
padding: 8
|
||||
})];
|
||||
const updatePosition = () => this._applyFloatingPosition(referenceElement, submenu, placement, middleware);
|
||||
updatePosition();
|
||||
return dom.autoUpdate(referenceElement, submenu, updatePosition);
|
||||
}
|
||||
_scheduleSubmenuClose(submenu, submenuWrapper) {
|
||||
this._cancelSubmenuCloseTimeout(submenu);
|
||||
const timeoutId = setTimeout(() => {
|
||||
this._closeSubmenu(submenu, submenuWrapper);
|
||||
this._submenuCloseTimeouts.delete(submenu);
|
||||
}, this._config.submenuDelay);
|
||||
this._submenuCloseTimeouts.set(submenu, timeoutId);
|
||||
}
|
||||
_cancelSubmenuCloseTimeout(submenu) {
|
||||
const timeoutId = this._submenuCloseTimeouts.get(submenu);
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
this._submenuCloseTimeouts.delete(submenu);
|
||||
}
|
||||
}
|
||||
_clearAllSubmenuTimeouts() {
|
||||
for (const timeoutId of this._submenuCloseTimeouts.values()) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
this._submenuCloseTimeouts.clear();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Hover intent / Safe triangle
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
_trackMousePosition(event) {
|
||||
this._hoverIntentData = {
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
}
|
||||
_isMovingTowardSubmenu(event, submenu) {
|
||||
if (!this._hoverIntentData) {
|
||||
return false;
|
||||
}
|
||||
const submenuRect = submenu.getBoundingClientRect();
|
||||
const currentPos = {
|
||||
x: event.clientX,
|
||||
y: event.clientY
|
||||
};
|
||||
const lastPos = {
|
||||
x: this._hoverIntentData.x,
|
||||
y: this._hoverIntentData.y
|
||||
};
|
||||
|
||||
// Create a triangle from current position to submenu edges
|
||||
// The triangle represents the "safe zone" for diagonal movement
|
||||
const isRtl = index_js.isRTL();
|
||||
|
||||
// Determine which edge of the submenu to target based on direction
|
||||
const targetX = isRtl ? submenuRect.right : submenuRect.left;
|
||||
const topCorner = {
|
||||
x: targetX,
|
||||
y: submenuRect.top
|
||||
};
|
||||
const bottomCorner = {
|
||||
x: targetX,
|
||||
y: submenuRect.bottom
|
||||
};
|
||||
|
||||
// Check if cursor is moving toward the submenu
|
||||
// by checking if the current position is within the safe triangle
|
||||
return this._pointInTriangle(currentPos, lastPos, topCorner, bottomCorner);
|
||||
}
|
||||
_pointInTriangle(point, v1, v2, v3) {
|
||||
// Barycentric coordinate method to check if point is inside triangle
|
||||
const d1 = triangleSign(point, v1, v2);
|
||||
const d2 = triangleSign(point, v2, v3);
|
||||
const d3 = triangleSign(point, v3, v1);
|
||||
const hasNeg = d1 < 0 || d2 < 0 || d3 < 0;
|
||||
const hasPos = d1 > 0 || d2 > 0 || d3 > 0;
|
||||
return !(hasNeg && hasPos);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Keyboard navigation
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
_selectMenuItem({
|
||||
key,
|
||||
target
|
||||
}) {
|
||||
const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => index_js.isVisible(element));
|
||||
// Get items only from the current menu level (not nested submenus)
|
||||
// If target is inside a menu, use that menu; otherwise use the main menu
|
||||
const currentMenu = target.closest(SELECTOR_MENU) || this._menu;
|
||||
const items = SelectorEngine.find(`:scope > li > ${SELECTOR_VISIBLE_ITEMS}, :scope > ${SELECTOR_VISIBLE_ITEMS}`, currentMenu).filter(element => index_js.isVisible(element));
|
||||
if (!items.length) {
|
||||
return;
|
||||
}
|
||||
@@ -361,6 +671,89 @@
|
||||
// allow cycling to get the last item in case key equals ARROW_UP_KEY
|
||||
index_js.getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus();
|
||||
}
|
||||
_handleSubmenuKeydown(event) {
|
||||
const {
|
||||
key,
|
||||
target
|
||||
} = event;
|
||||
const isRtl = index_js.isRTL();
|
||||
|
||||
// Determine the "enter submenu" and "exit submenu" keys based on RTL
|
||||
const enterKey = isRtl ? ARROW_LEFT_KEY : ARROW_RIGHT_KEY;
|
||||
const exitKey = isRtl ? ARROW_RIGHT_KEY : ARROW_LEFT_KEY;
|
||||
|
||||
// Check if target is a submenu trigger
|
||||
const submenuWrapper = target.closest(SELECTOR_SUBMENU);
|
||||
const isSubmenuTrigger = submenuWrapper && target.matches(SELECTOR_SUBMENU_TOGGLE);
|
||||
|
||||
// Handle Enter/Space on submenu trigger
|
||||
if ((key === ENTER_KEY || key === SPACE_KEY) && isSubmenuTrigger) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const submenu = SelectorEngine.findOne(SELECTOR_MENU, submenuWrapper);
|
||||
if (submenu) {
|
||||
this._closeSiblingSubmenus(submenuWrapper);
|
||||
this._openSubmenu(target, submenu, submenuWrapper);
|
||||
// Focus first item in submenu
|
||||
requestAnimationFrame(() => {
|
||||
const firstItem = SelectorEngine.findOne(SELECTOR_VISIBLE_ITEMS, submenu);
|
||||
if (firstItem) {
|
||||
firstItem.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle Right arrow (or Left in RTL) - enter submenu
|
||||
if (key === enterKey && isSubmenuTrigger) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const submenu = SelectorEngine.findOne(SELECTOR_MENU, submenuWrapper);
|
||||
if (submenu) {
|
||||
this._closeSiblingSubmenus(submenuWrapper);
|
||||
this._openSubmenu(target, submenu, submenuWrapper);
|
||||
// Focus first item in submenu
|
||||
requestAnimationFrame(() => {
|
||||
const firstItem = SelectorEngine.findOne(SELECTOR_VISIBLE_ITEMS, submenu);
|
||||
if (firstItem) {
|
||||
firstItem.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle Left arrow (or Right in RTL) - exit submenu
|
||||
if (key === exitKey) {
|
||||
const currentMenu = target.closest(SELECTOR_MENU);
|
||||
const parentSubmenuWrapper = currentMenu?.closest(SELECTOR_SUBMENU);
|
||||
if (parentSubmenuWrapper) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const parentTrigger = SelectorEngine.findOne(SELECTOR_SUBMENU_TOGGLE, parentSubmenuWrapper);
|
||||
this._closeSubmenu(currentMenu, parentSubmenuWrapper);
|
||||
if (parentTrigger) {
|
||||
parentTrigger.focus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Home/End keys
|
||||
if (key === HOME_KEY || key === END_KEY) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const currentMenu = target.closest(SELECTOR_MENU);
|
||||
const items = SelectorEngine.find(`:scope > li > ${SELECTOR_VISIBLE_ITEMS}, :scope > ${SELECTOR_VISIBLE_ITEMS}`, currentMenu).filter(element => index_js.isVisible(element));
|
||||
if (items.length) {
|
||||
const targetItem = key === HOME_KEY ? items[0] : items[items.length - 1];
|
||||
targetItem.focus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static clearMenus(event) {
|
||||
if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY) {
|
||||
return;
|
||||
@@ -391,32 +784,62 @@
|
||||
}
|
||||
}
|
||||
static dataApiKeydownHandler(event) {
|
||||
// If not an UP | DOWN | ESCAPE key => not a dropdown command
|
||||
// If input/textarea && if key is other than ESCAPE => not a dropdown command
|
||||
|
||||
// If not a relevant key => not a dropdown command
|
||||
const isInput = /input|textarea/i.test(event.target.tagName);
|
||||
const isEscapeEvent = event.key === ESCAPE_KEY;
|
||||
const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key);
|
||||
if (!isUpOrDownEvent && !isEscapeEvent) {
|
||||
const isLeftOrRightEvent = [ARROW_LEFT_KEY, ARROW_RIGHT_KEY].includes(event.key);
|
||||
const isHomeOrEndEvent = [HOME_KEY, END_KEY].includes(event.key);
|
||||
const isEnterOrSpaceEvent = [ENTER_KEY, SPACE_KEY].includes(event.key);
|
||||
|
||||
// Allow Enter/Space only on submenu triggers
|
||||
const isSubmenuTrigger = event.target.matches(SELECTOR_SUBMENU_TOGGLE);
|
||||
if (!isUpOrDownEvent && !isEscapeEvent && !isLeftOrRightEvent && !isHomeOrEndEvent && !(isEnterOrSpaceEvent && isSubmenuTrigger)) {
|
||||
return;
|
||||
}
|
||||
if (isInput && !isEscapeEvent) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
|
||||
// TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
|
||||
const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode);
|
||||
if (!getToggleButton) {
|
||||
return;
|
||||
}
|
||||
const instance = Dropdown.getOrCreateInstance(getToggleButton);
|
||||
|
||||
// Handle submenu navigation first
|
||||
if ((isLeftOrRightEvent || isHomeOrEndEvent || isEnterOrSpaceEvent && isSubmenuTrigger) && instance._handleSubmenuKeydown(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle Up/Down navigation
|
||||
if (isUpOrDownEvent) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
instance.show();
|
||||
instance._selectMenuItem(event);
|
||||
return;
|
||||
}
|
||||
if (instance._isShown()) {
|
||||
// else is escape and we check if it is shown
|
||||
|
||||
// Handle Escape
|
||||
if (isEscapeEvent && instance._isShown()) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// If in a submenu, close just that submenu
|
||||
const currentMenu = event.target.closest(SELECTOR_MENU);
|
||||
const parentSubmenuWrapper = currentMenu?.closest(SELECTOR_SUBMENU);
|
||||
if (parentSubmenuWrapper && instance._openSubmenus.size > 0) {
|
||||
const parentTrigger = SelectorEngine.findOne(SELECTOR_SUBMENU_TOGGLE, parentSubmenuWrapper);
|
||||
instance._closeSubmenu(currentMenu, parentSubmenuWrapper);
|
||||
if (parentTrigger) {
|
||||
parentTrigger.focus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise close the whole dropdown
|
||||
instance.hide();
|
||||
getToggleButton.focus();
|
||||
}
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+238
@@ -0,0 +1,238 @@
|
||||
/*!
|
||||
* Bootstrap otp-input.js v5.3.8 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./dom/selector-engine.js')) :
|
||||
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './dom/selector-engine'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.OtpInput = factory(global.BaseComponent, global.EventHandler, global.SelectorEngine));
|
||||
})(this, (function (BaseComponent, EventHandler, SelectorEngine) { 'use strict';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Bootstrap otp-input.js
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
|
||||
const NAME = 'otpInput';
|
||||
const DATA_KEY = 'bs.otp-input';
|
||||
const EVENT_KEY = `.${DATA_KEY}`;
|
||||
const DATA_API_KEY = '.data-api';
|
||||
const EVENT_COMPLETE = `complete${EVENT_KEY}`;
|
||||
const EVENT_INPUT = `input${EVENT_KEY}`;
|
||||
const SELECTOR_DATA_OTP = '[data-bs-otp]';
|
||||
const SELECTOR_INPUT = 'input';
|
||||
const Default = {
|
||||
length: 6,
|
||||
mask: false
|
||||
};
|
||||
const DefaultType = {
|
||||
length: 'number',
|
||||
mask: 'boolean'
|
||||
};
|
||||
|
||||
/**
|
||||
* Class definition
|
||||
*/
|
||||
|
||||
class OtpInput extends BaseComponent {
|
||||
constructor(element, config) {
|
||||
super(element, config);
|
||||
this._inputs = SelectorEngine.find(SELECTOR_INPUT, this._element);
|
||||
this._setupInputs();
|
||||
this._addEventListeners();
|
||||
}
|
||||
|
||||
// Getters
|
||||
static get Default() {
|
||||
return Default;
|
||||
}
|
||||
static get DefaultType() {
|
||||
return DefaultType;
|
||||
}
|
||||
static get NAME() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
// Public
|
||||
getValue() {
|
||||
return this._inputs.map(input => input.value).join('');
|
||||
}
|
||||
setValue(value) {
|
||||
const chars = String(value).split('');
|
||||
for (const [index, input] of this._inputs.entries()) {
|
||||
input.value = chars[index] || '';
|
||||
}
|
||||
this._checkComplete();
|
||||
}
|
||||
clear() {
|
||||
for (const input of this._inputs) {
|
||||
input.value = '';
|
||||
}
|
||||
this._inputs[0]?.focus();
|
||||
}
|
||||
focus() {
|
||||
// Focus first empty input, or last input if all filled
|
||||
const emptyInput = this._inputs.find(input => !input.value);
|
||||
if (emptyInput) {
|
||||
emptyInput.focus();
|
||||
} else {
|
||||
this._inputs.at(-1)?.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// Private
|
||||
_setupInputs() {
|
||||
for (const input of this._inputs) {
|
||||
// Set attributes for proper OTP handling
|
||||
input.setAttribute('maxlength', '1');
|
||||
input.setAttribute('inputmode', 'numeric');
|
||||
input.setAttribute('pattern', '\\d*');
|
||||
|
||||
// First input gets autocomplete for browser OTP autofill
|
||||
if (input === this._inputs[0]) {
|
||||
input.setAttribute('autocomplete', 'one-time-code');
|
||||
} else {
|
||||
input.setAttribute('autocomplete', 'off');
|
||||
}
|
||||
|
||||
// Mask input if configured
|
||||
if (this._config.mask) {
|
||||
input.setAttribute('type', 'password');
|
||||
}
|
||||
}
|
||||
}
|
||||
_addEventListeners() {
|
||||
for (const [index, input] of this._inputs.entries()) {
|
||||
EventHandler.on(input, 'input', event => this._handleInput(event, index));
|
||||
EventHandler.on(input, 'keydown', event => this._handleKeydown(event, index));
|
||||
EventHandler.on(input, 'paste', event => this._handlePaste(event));
|
||||
EventHandler.on(input, 'focus', event => this._handleFocus(event));
|
||||
}
|
||||
}
|
||||
_handleInput(event, index) {
|
||||
const input = event.target;
|
||||
|
||||
// Only allow digits
|
||||
if (!/^\d*$/.test(input.value)) {
|
||||
input.value = input.value.replace(/\D/g, '');
|
||||
}
|
||||
const {
|
||||
value
|
||||
} = input;
|
||||
|
||||
// Handle multi-character input (some browsers/autofill)
|
||||
if (value.length > 1) {
|
||||
// Distribute characters across inputs
|
||||
const chars = value.split('');
|
||||
input.value = chars[0] || '';
|
||||
for (let i = 1; i < chars.length && index + i < this._inputs.length; i++) {
|
||||
this._inputs[index + i].value = chars[i];
|
||||
}
|
||||
|
||||
// Focus appropriate input
|
||||
const nextIndex = Math.min(index + chars.length, this._inputs.length - 1);
|
||||
this._inputs[nextIndex].focus();
|
||||
} else if (value && index < this._inputs.length - 1) {
|
||||
// Auto-advance to next input
|
||||
this._inputs[index + 1].focus();
|
||||
}
|
||||
EventHandler.trigger(this._element, EVENT_INPUT, {
|
||||
value: this.getValue(),
|
||||
index
|
||||
});
|
||||
this._checkComplete();
|
||||
}
|
||||
_handleKeydown(event, index) {
|
||||
const {
|
||||
key
|
||||
} = event;
|
||||
switch (key) {
|
||||
case 'Backspace':
|
||||
{
|
||||
if (!this._inputs[index].value && index > 0) {
|
||||
// Move to previous input and clear it
|
||||
event.preventDefault();
|
||||
this._inputs[index - 1].value = '';
|
||||
this._inputs[index - 1].focus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'Delete':
|
||||
{
|
||||
// Clear current and shift remaining values left
|
||||
event.preventDefault();
|
||||
for (let i = index; i < this._inputs.length - 1; i++) {
|
||||
this._inputs[i].value = this._inputs[i + 1].value;
|
||||
}
|
||||
this._inputs.at(-1).value = '';
|
||||
break;
|
||||
}
|
||||
case 'ArrowLeft':
|
||||
{
|
||||
if (index > 0) {
|
||||
event.preventDefault();
|
||||
this._inputs[index - 1].focus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'ArrowRight':
|
||||
{
|
||||
if (index < this._inputs.length - 1) {
|
||||
event.preventDefault();
|
||||
this._inputs[index + 1].focus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// No default
|
||||
}
|
||||
}
|
||||
_handlePaste(event) {
|
||||
event.preventDefault();
|
||||
const pastedData = (event.clipboardData || window.clipboardData).getData('text');
|
||||
const digits = pastedData.replace(/\D/g, '').slice(0, this._inputs.length);
|
||||
if (digits) {
|
||||
this.setValue(digits);
|
||||
|
||||
// Focus last filled input or last input
|
||||
const lastIndex = Math.min(digits.length, this._inputs.length) - 1;
|
||||
this._inputs[lastIndex].focus();
|
||||
}
|
||||
}
|
||||
_handleFocus(event) {
|
||||
// Select the content on focus for easy replacement
|
||||
event.target.select();
|
||||
}
|
||||
_checkComplete() {
|
||||
const value = this.getValue();
|
||||
const isComplete = value.length === this._inputs.length && this._inputs.every(input => input.value !== '');
|
||||
if (isComplete) {
|
||||
EventHandler.trigger(this._element, EVENT_COMPLETE, {
|
||||
value
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data API implementation
|
||||
*/
|
||||
|
||||
EventHandler.on(document, `DOMContentLoaded${EVENT_KEY}${DATA_API_KEY}`, () => {
|
||||
for (const element of SelectorEngine.find(SELECTOR_DATA_OTP)) {
|
||||
OtpInput.getOrCreateInstance(element);
|
||||
}
|
||||
});
|
||||
|
||||
return OtpInput;
|
||||
|
||||
}));
|
||||
//# sourceMappingURL=otp-input.js.map
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+245
@@ -0,0 +1,245 @@
|
||||
/*!
|
||||
* Bootstrap strength.js v5.3.8 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./dom/selector-engine.js')) :
|
||||
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './dom/selector-engine'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Strength = factory(global.BaseComponent, global.EventHandler, global.SelectorEngine));
|
||||
})(this, (function (BaseComponent, EventHandler, SelectorEngine) { 'use strict';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Bootstrap strength.js
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
|
||||
const NAME = 'strength';
|
||||
const DATA_KEY = 'bs.strength';
|
||||
const EVENT_KEY = `.${DATA_KEY}`;
|
||||
const DATA_API_KEY = '.data-api';
|
||||
const EVENT_STRENGTH_CHANGE = `strengthChange${EVENT_KEY}`;
|
||||
const SELECTOR_DATA_STRENGTH = '[data-bs-strength]';
|
||||
const STRENGTH_LEVELS = ['weak', 'fair', 'good', 'strong'];
|
||||
const Default = {
|
||||
input: null,
|
||||
// Selector or element for password input
|
||||
minLength: 8,
|
||||
messages: {
|
||||
weak: 'Weak',
|
||||
fair: 'Fair',
|
||||
good: 'Good',
|
||||
strong: 'Strong'
|
||||
},
|
||||
weights: {
|
||||
minLength: 1,
|
||||
extraLength: 1,
|
||||
lowercase: 1,
|
||||
uppercase: 1,
|
||||
numbers: 1,
|
||||
special: 1,
|
||||
multipleSpecial: 1,
|
||||
longPassword: 1
|
||||
},
|
||||
thresholds: [2, 4, 6],
|
||||
// weak ≤2, fair ≤4, good ≤6, strong >6
|
||||
scorer: null // Custom scoring function (password) => number
|
||||
};
|
||||
const DefaultType = {
|
||||
input: '(string|element|null)',
|
||||
minLength: 'number',
|
||||
messages: 'object',
|
||||
weights: 'object',
|
||||
thresholds: 'array',
|
||||
scorer: '(function|null)'
|
||||
};
|
||||
|
||||
/**
|
||||
* Class definition
|
||||
*/
|
||||
|
||||
class Strength extends BaseComponent {
|
||||
constructor(element, config) {
|
||||
super(element, config);
|
||||
this._input = this._getInput();
|
||||
this._segments = SelectorEngine.find('.strength-segment', this._element);
|
||||
this._textElement = SelectorEngine.findOne('.strength-text', this._element.parentElement);
|
||||
this._currentStrength = null;
|
||||
if (this._input) {
|
||||
this._addEventListeners();
|
||||
// Check initial value
|
||||
this._evaluate();
|
||||
}
|
||||
}
|
||||
|
||||
// Getters
|
||||
static get Default() {
|
||||
return Default;
|
||||
}
|
||||
static get DefaultType() {
|
||||
return DefaultType;
|
||||
}
|
||||
static get NAME() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
// Public
|
||||
getStrength() {
|
||||
return this._currentStrength;
|
||||
}
|
||||
evaluate() {
|
||||
this._evaluate();
|
||||
}
|
||||
|
||||
// Private
|
||||
_getInput() {
|
||||
if (this._config.input) {
|
||||
return typeof this._config.input === 'string' ? SelectorEngine.findOne(this._config.input) : this._config.input;
|
||||
}
|
||||
|
||||
// Look for preceding password input
|
||||
const parent = this._element.parentElement;
|
||||
return SelectorEngine.findOne('input[type="password"]', parent);
|
||||
}
|
||||
_addEventListeners() {
|
||||
EventHandler.on(this._input, 'input', () => this._evaluate());
|
||||
EventHandler.on(this._input, 'change', () => this._evaluate());
|
||||
}
|
||||
_evaluate() {
|
||||
const password = this._input.value;
|
||||
const score = this._calculateScore(password);
|
||||
const strength = this._scoreToStrength(score);
|
||||
if (strength !== this._currentStrength) {
|
||||
this._currentStrength = strength;
|
||||
this._updateUI(strength, score);
|
||||
EventHandler.trigger(this._element, EVENT_STRENGTH_CHANGE, {
|
||||
strength,
|
||||
score,
|
||||
password: password.length > 0 ? '***' : '' // Don't expose actual password
|
||||
});
|
||||
}
|
||||
}
|
||||
_calculateScore(password) {
|
||||
if (!password) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Use custom scorer if provided
|
||||
if (typeof this._config.scorer === 'function') {
|
||||
return this._config.scorer(password);
|
||||
}
|
||||
const {
|
||||
weights
|
||||
} = this._config;
|
||||
let score = 0;
|
||||
|
||||
// Length scoring
|
||||
if (password.length >= this._config.minLength) {
|
||||
score += weights.minLength;
|
||||
}
|
||||
if (password.length >= this._config.minLength + 4) {
|
||||
score += weights.extraLength;
|
||||
}
|
||||
|
||||
// Character variety
|
||||
if (/[a-z]/.test(password)) {
|
||||
score += weights.lowercase;
|
||||
}
|
||||
if (/[A-Z]/.test(password)) {
|
||||
score += weights.uppercase;
|
||||
}
|
||||
if (/\d/.test(password)) {
|
||||
score += weights.numbers;
|
||||
}
|
||||
|
||||
// Special characters
|
||||
if (/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
|
||||
score += weights.special;
|
||||
}
|
||||
|
||||
// Extra points for more special chars or length
|
||||
if (/[!@#$%^&*(),.?":{}|<>].*[!@#$%^&*(),.?":{}|<>]/.test(password)) {
|
||||
score += weights.multipleSpecial;
|
||||
}
|
||||
if (password.length >= 16) {
|
||||
score += weights.longPassword;
|
||||
}
|
||||
return score;
|
||||
}
|
||||
_scoreToStrength(score) {
|
||||
if (score === 0) {
|
||||
return null;
|
||||
}
|
||||
const [weak, fair, good] = this._config.thresholds;
|
||||
if (score <= weak) {
|
||||
return 'weak';
|
||||
}
|
||||
if (score <= fair) {
|
||||
return 'fair';
|
||||
}
|
||||
if (score <= good) {
|
||||
return 'good';
|
||||
}
|
||||
return 'strong';
|
||||
}
|
||||
_updateUI(strength) {
|
||||
// Update data attribute on element
|
||||
if (strength) {
|
||||
this._element.dataset.bsStrength = strength;
|
||||
} else {
|
||||
delete this._element.dataset.bsStrength;
|
||||
}
|
||||
|
||||
// Update segmented meter
|
||||
const strengthIndex = strength ? STRENGTH_LEVELS.indexOf(strength) : -1;
|
||||
for (const [index, segment] of this._segments.entries()) {
|
||||
if (index <= strengthIndex) {
|
||||
segment.classList.add('active');
|
||||
} else {
|
||||
segment.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
// Update text feedback
|
||||
if (this._textElement) {
|
||||
if (strength && this._config.messages[strength]) {
|
||||
this._textElement.textContent = this._config.messages[strength];
|
||||
this._textElement.dataset.bsStrength = strength;
|
||||
|
||||
// Also set the color via inheriting from parent or using CSS variable
|
||||
const colorMap = {
|
||||
weak: 'danger',
|
||||
fair: 'warning',
|
||||
good: 'info',
|
||||
strong: 'success'
|
||||
};
|
||||
this._textElement.style.setProperty('--strength-color', `var(--${colorMap[strength]}-text)`);
|
||||
} else {
|
||||
this._textElement.textContent = '';
|
||||
delete this._textElement.dataset.bsStrength;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data API implementation
|
||||
*/
|
||||
|
||||
EventHandler.on(document, `DOMContentLoaded${EVENT_KEY}${DATA_API_KEY}`, () => {
|
||||
for (const element of SelectorEngine.find(SELECTOR_DATA_STRENGTH)) {
|
||||
Strength.getOrCreateInstance(element);
|
||||
}
|
||||
});
|
||||
|
||||
return Strength;
|
||||
|
||||
}));
|
||||
//# sourceMappingURL=strength.js.map
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+98
@@ -0,0 +1,98 @@
|
||||
/*!
|
||||
* Bootstrap toggler.js v5.3.8 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./util/component-functions.js')) :
|
||||
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './util/component-functions'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Toggler = factory(global.BaseComponent, global.EventHandler, global.ComponentFunctions));
|
||||
})(this, (function (BaseComponent, EventHandler, componentFunctions_js) { 'use strict';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Bootstrap toggler.js
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
|
||||
const NAME = 'toggler';
|
||||
const DATA_KEY = 'bs.toggler';
|
||||
const EVENT_KEY = `.${DATA_KEY}`;
|
||||
const EVENT_TOGGLE = `toggle${EVENT_KEY}`;
|
||||
const EVENT_TOGGLED = `toggled${EVENT_KEY}`;
|
||||
const EVENT_CLICK = 'click';
|
||||
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="toggler"]';
|
||||
const DefaultType = {
|
||||
attribute: 'string',
|
||||
value: '(string|number|boolean)'
|
||||
};
|
||||
const Default = {
|
||||
attribute: 'class',
|
||||
value: null
|
||||
};
|
||||
|
||||
/**
|
||||
* Class definition
|
||||
*/
|
||||
|
||||
class Toggler extends BaseComponent {
|
||||
// Getters
|
||||
static get Default() {
|
||||
return Default;
|
||||
}
|
||||
static get DefaultType() {
|
||||
return DefaultType;
|
||||
}
|
||||
static get NAME() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
// Public
|
||||
toggle() {
|
||||
const toggleEvent = EventHandler.trigger(this._element, EVENT_TOGGLE);
|
||||
if (toggleEvent.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
this._execute();
|
||||
EventHandler.trigger(this._element, EVENT_TOGGLED);
|
||||
}
|
||||
|
||||
// Private
|
||||
_execute() {
|
||||
const {
|
||||
attribute,
|
||||
value
|
||||
} = this._config;
|
||||
if (attribute === 'id') {
|
||||
return; // You have to be kidding
|
||||
}
|
||||
if (attribute === 'class') {
|
||||
this._element.classList.toggle(value);
|
||||
return;
|
||||
}
|
||||
|
||||
// Compare as strings since getAttribute() always returns a string
|
||||
if (this._element.getAttribute(attribute) === String(value)) {
|
||||
this._element.removeAttribute(attribute);
|
||||
return;
|
||||
}
|
||||
this._element.setAttribute(attribute, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data API implementation
|
||||
*/
|
||||
|
||||
componentFunctions_js.eventActionOnPlugin(Toggler, EVENT_CLICK, SELECTOR_DATA_TOGGLE, 'toggle');
|
||||
|
||||
return Toggler;
|
||||
|
||||
}));
|
||||
//# sourceMappingURL=toggler.js.map
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"toggler.js","sources":["../src/toggler.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap toggler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { eventActionOnPlugin } from './util/component-functions.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'toggler'\nconst DATA_KEY = 'bs.toggler'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_TOGGLE = `toggle${EVENT_KEY}`\nconst EVENT_TOGGLED = `toggled${EVENT_KEY}`\nconst EVENT_CLICK = 'click'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"toggler\"]'\n\nconst DefaultType = {\n attribute: 'string',\n value: '(string|number|boolean)'\n}\n\nconst Default = {\n attribute: 'class',\n value: null\n}\n\n/**\n * Class definition\n */\n\nclass Toggler extends BaseComponent {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n const toggleEvent = EventHandler.trigger(this._element, EVENT_TOGGLE)\n\n if (toggleEvent.defaultPrevented) {\n return\n }\n\n this._execute()\n\n EventHandler.trigger(this._element, EVENT_TOGGLED)\n }\n\n // Private\n _execute() {\n const { attribute, value } = this._config\n\n if (attribute === 'id') {\n return // You have to be kidding\n }\n\n if (attribute === 'class') {\n this._element.classList.toggle(value)\n return\n }\n\n // Compare as strings since getAttribute() always returns a string\n if (this._element.getAttribute(attribute) === String(value)) {\n this._element.removeAttribute(attribute)\n return\n }\n\n this._element.setAttribute(attribute, value)\n }\n}\n\n/**\n * Data API implementation\n */\n\neventActionOnPlugin(Toggler, EVENT_CLICK, SELECTOR_DATA_TOGGLE, 'toggle')\n\nexport default Toggler\n"],"names":["NAME","DATA_KEY","EVENT_KEY","EVENT_TOGGLE","EVENT_TOGGLED","EVENT_CLICK","SELECTOR_DATA_TOGGLE","DefaultType","attribute","value","Default","Toggler","BaseComponent","toggle","toggleEvent","EventHandler","trigger","_element","defaultPrevented","_execute","_config","classList","getAttribute","String","removeAttribute","setAttribute","eventActionOnPlugin"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;;EAMA;EACA;EACA;;EAEA,MAAMA,IAAI,GAAG,SAAS;EACtB,MAAMC,QAAQ,GAAG,YAAY;EAC7B,MAAMC,SAAS,GAAG,CAAA,CAAA,EAAID,QAAQ,CAAA,CAAE;EAEhC,MAAME,YAAY,GAAG,CAAA,MAAA,EAASD,SAAS,CAAA,CAAE;EACzC,MAAME,aAAa,GAAG,CAAA,OAAA,EAAUF,SAAS,CAAA,CAAE;EAC3C,MAAMG,WAAW,GAAG,OAAO;EAE3B,MAAMC,oBAAoB,GAAG,4BAA4B;EAEzD,MAAMC,WAAW,GAAG;EAClBC,EAAAA,SAAS,EAAE,QAAQ;EACnBC,EAAAA,KAAK,EAAE;EACT,CAAC;EAED,MAAMC,OAAO,GAAG;EACdF,EAAAA,SAAS,EAAE,OAAO;EAClBC,EAAAA,KAAK,EAAE;EACT,CAAC;;EAED;EACA;EACA;;EAEA,MAAME,OAAO,SAASC,aAAa,CAAC;EAClC;IACA,WAAWF,OAAOA,GAAG;EACnB,IAAA,OAAOA,OAAO;EAChB,EAAA;IAEA,WAAWH,WAAWA,GAAG;EACvB,IAAA,OAAOA,WAAW;EACpB,EAAA;IAEA,WAAWP,IAAIA,GAAG;EAChB,IAAA,OAAOA,IAAI;EACb,EAAA;;EAEA;EACAa,EAAAA,MAAMA,GAAG;MACP,MAAMC,WAAW,GAAGC,YAAY,CAACC,OAAO,CAAC,IAAI,CAACC,QAAQ,EAAEd,YAAY,CAAC;MAErE,IAAIW,WAAW,CAACI,gBAAgB,EAAE;EAChC,MAAA;EACF,IAAA;MAEA,IAAI,CAACC,QAAQ,EAAE;MAEfJ,YAAY,CAACC,OAAO,CAAC,IAAI,CAACC,QAAQ,EAAEb,aAAa,CAAC;EACpD,EAAA;;EAEA;EACAe,EAAAA,QAAQA,GAAG;MACT,MAAM;QAAEX,SAAS;EAAEC,MAAAA;OAAO,GAAG,IAAI,CAACW,OAAO;MAEzC,IAAIZ,SAAS,KAAK,IAAI,EAAE;EACtB,MAAA,OAAM;EACR,IAAA;MAEA,IAAIA,SAAS,KAAK,OAAO,EAAE;QACzB,IAAI,CAACS,QAAQ,CAACI,SAAS,CAACR,MAAM,CAACJ,KAAK,CAAC;EACrC,MAAA;EACF,IAAA;;EAEA;EACA,IAAA,IAAI,IAAI,CAACQ,QAAQ,CAACK,YAAY,CAACd,SAAS,CAAC,KAAKe,MAAM,CAACd,KAAK,CAAC,EAAE;EAC3D,MAAA,IAAI,CAACQ,QAAQ,CAACO,eAAe,CAAChB,SAAS,CAAC;EACxC,MAAA;EACF,IAAA;MAEA,IAAI,CAACS,QAAQ,CAACQ,YAAY,CAACjB,SAAS,EAAEC,KAAK,CAAC;EAC9C,EAAA;EACF;;EAEA;EACA;EACA;;AAEAiB,2CAAmB,CAACf,OAAO,EAAEN,WAAW,EAAEC,oBAAoB,EAAE,QAAQ,CAAC;;;;;;;;"}
|
||||
Vendored
+29
@@ -33,8 +33,37 @@
|
||||
instance[method]();
|
||||
});
|
||||
};
|
||||
const eventActionOnPlugin = (Plugin, onEvent, stringSelector, method, callback = null) => {
|
||||
eventAction(`${onEvent}.${Plugin.NAME}`, stringSelector, data => {
|
||||
const instances = data.targets.filter(Boolean).map(element => Plugin.getOrCreateInstance(element));
|
||||
if (typeof callback === 'function') {
|
||||
callback({
|
||||
...data,
|
||||
instances
|
||||
});
|
||||
}
|
||||
for (const instance of instances) {
|
||||
instance[method]();
|
||||
}
|
||||
});
|
||||
};
|
||||
const eventAction = (onEvent, stringSelector, callback) => {
|
||||
const selector = `${stringSelector}:not(.disabled):not(:disabled)`;
|
||||
EventHandler.on(document, onEvent, selector, function (event) {
|
||||
if (['A', 'AREA'].includes(this.tagName)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
const selector = SelectorEngine.getSelectorFromElement(this);
|
||||
const targets = selector ? SelectorEngine.find(selector) : [this];
|
||||
callback({
|
||||
targets,
|
||||
event
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.enableDismissTrigger = enableDismissTrigger;
|
||||
exports.eventActionOnPlugin = eventActionOnPlugin;
|
||||
|
||||
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"component-functions.js","sources":["../../src/util/component-functions.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n"],"names":["enableDismissTrigger","component","method","clickEvent","EVENT_KEY","name","NAME","EventHandler","on","document","event","includes","tagName","preventDefault","isDisabled","target","SelectorEngine","getElementFromSelector","closest","instance","getOrCreateInstance"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;AAMA,QAAMA,oBAAoB,GAAGA,CAACC,SAAS,EAAEC,MAAM,GAAG,MAAM,KAAK;EAC3D,EAAA,MAAMC,UAAU,GAAG,CAAA,aAAA,EAAgBF,SAAS,CAACG,SAAS,CAAA,CAAE;EACxD,EAAA,MAAMC,IAAI,GAAGJ,SAAS,CAACK,IAAI;EAE3BC,EAAAA,YAAY,CAACC,EAAE,CAACC,QAAQ,EAAEN,UAAU,EAAE,CAAA,kBAAA,EAAqBE,IAAI,CAAA,EAAA,CAAI,EAAE,UAAUK,KAAK,EAAE;EACpF,IAAA,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAACC,QAAQ,CAAC,IAAI,CAACC,OAAO,CAAC,EAAE;QACxCF,KAAK,CAACG,cAAc,EAAE;EACxB,IAAA;EAEA,IAAA,IAAIC,mBAAU,CAAC,IAAI,CAAC,EAAE;EACpB,MAAA;EACF,IAAA;EAEA,IAAA,MAAMC,MAAM,GAAGC,cAAc,CAACC,sBAAsB,CAAC,IAAI,CAAC,IAAI,IAAI,CAACC,OAAO,CAAC,CAAA,CAAA,EAAIb,IAAI,EAAE,CAAC;EACtF,IAAA,MAAMc,QAAQ,GAAGlB,SAAS,CAACmB,mBAAmB,CAACL,MAAM,CAAC;;EAEtD;EACAI,IAAAA,QAAQ,CAACjB,MAAM,CAAC,EAAE;EACpB,EAAA,CAAC,CAAC;EACJ;;;;;;;;;;"}
|
||||
{"version":3,"file":"component-functions.js","sources":["../../src/util/component-functions.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nconst eventActionOnPlugin = (Plugin, onEvent, stringSelector, method, callback = null) => {\n eventAction(`${onEvent}.${Plugin.NAME}`, stringSelector, data => {\n const instances = data.targets.filter(Boolean).map(element => Plugin.getOrCreateInstance(element))\n if (typeof callback === 'function') {\n callback({ ...data, instances })\n }\n\n for (const instance of instances) {\n instance[method]()\n }\n })\n}\n\nconst eventAction = (onEvent, stringSelector, callback) => {\n const selector = `${stringSelector}:not(.disabled):not(:disabled)`\n EventHandler.on(document, onEvent, selector, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n const selector = SelectorEngine.getSelectorFromElement(this)\n const targets = selector ? SelectorEngine.find(selector) : [this]\n\n callback({ targets, event })\n })\n}\n\nexport {\n enableDismissTrigger,\n eventActionOnPlugin\n}\n"],"names":["enableDismissTrigger","component","method","clickEvent","EVENT_KEY","name","NAME","EventHandler","on","document","event","includes","tagName","preventDefault","isDisabled","target","SelectorEngine","getElementFromSelector","closest","instance","getOrCreateInstance","eventActionOnPlugin","Plugin","onEvent","stringSelector","callback","eventAction","data","instances","targets","filter","Boolean","map","element","selector","getSelectorFromElement","find"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;AAMA,QAAMA,oBAAoB,GAAGA,CAACC,SAAS,EAAEC,MAAM,GAAG,MAAM,KAAK;EAC3D,EAAA,MAAMC,UAAU,GAAG,CAAA,aAAA,EAAgBF,SAAS,CAACG,SAAS,CAAA,CAAE;EACxD,EAAA,MAAMC,IAAI,GAAGJ,SAAS,CAACK,IAAI;EAE3BC,EAAAA,YAAY,CAACC,EAAE,CAACC,QAAQ,EAAEN,UAAU,EAAE,CAAA,kBAAA,EAAqBE,IAAI,CAAA,EAAA,CAAI,EAAE,UAAUK,KAAK,EAAE;EACpF,IAAA,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAACC,QAAQ,CAAC,IAAI,CAACC,OAAO,CAAC,EAAE;QACxCF,KAAK,CAACG,cAAc,EAAE;EACxB,IAAA;EAEA,IAAA,IAAIC,mBAAU,CAAC,IAAI,CAAC,EAAE;EACpB,MAAA;EACF,IAAA;EAEA,IAAA,MAAMC,MAAM,GAAGC,cAAc,CAACC,sBAAsB,CAAC,IAAI,CAAC,IAAI,IAAI,CAACC,OAAO,CAAC,CAAA,CAAA,EAAIb,IAAI,EAAE,CAAC;EACtF,IAAA,MAAMc,QAAQ,GAAGlB,SAAS,CAACmB,mBAAmB,CAACL,MAAM,CAAC;;EAEtD;EACAI,IAAAA,QAAQ,CAACjB,MAAM,CAAC,EAAE;EACpB,EAAA,CAAC,CAAC;EACJ;AAEA,QAAMmB,mBAAmB,GAAGA,CAACC,MAAM,EAAEC,OAAO,EAAEC,cAAc,EAAEtB,MAAM,EAAEuB,QAAQ,GAAG,IAAI,KAAK;EACxFC,EAAAA,WAAW,CAAC,CAAA,EAAGH,OAAO,CAAA,CAAA,EAAID,MAAM,CAAChB,IAAI,CAAA,CAAE,EAAEkB,cAAc,EAAEG,IAAI,IAAI;MAC/D,MAAMC,SAAS,GAAGD,IAAI,CAACE,OAAO,CAACC,MAAM,CAACC,OAAO,CAAC,CAACC,GAAG,CAACC,OAAO,IAAIX,MAAM,CAACF,mBAAmB,CAACa,OAAO,CAAC,CAAC;EAClG,IAAA,IAAI,OAAOR,QAAQ,KAAK,UAAU,EAAE;EAClCA,MAAAA,QAAQ,CAAC;EAAE,QAAA,GAAGE,IAAI;EAAEC,QAAAA;EAAU,OAAC,CAAC;EAClC,IAAA;EAEA,IAAA,KAAK,MAAMT,QAAQ,IAAIS,SAAS,EAAE;EAChCT,MAAAA,QAAQ,CAACjB,MAAM,CAAC,EAAE;EACpB,IAAA;EACF,EAAA,CAAC,CAAC;EACJ;EAEA,MAAMwB,WAAW,GAAGA,CAACH,OAAO,EAAEC,cAAc,EAAEC,QAAQ,KAAK;EACzD,EAAA,MAAMS,QAAQ,GAAG,CAAA,EAAGV,cAAc,CAAA,8BAAA,CAAgC;IAClEjB,YAAY,CAACC,EAAE,CAACC,QAAQ,EAAEc,OAAO,EAAEW,QAAQ,EAAE,UAAUxB,KAAK,EAAE;EAC5D,IAAA,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAACC,QAAQ,CAAC,IAAI,CAACC,OAAO,CAAC,EAAE;QACxCF,KAAK,CAACG,cAAc,EAAE;EACxB,IAAA;EAEA,IAAA,MAAMqB,QAAQ,GAAGlB,cAAc,CAACmB,sBAAsB,CAAC,IAAI,CAAC;EAC5D,IAAA,MAAMN,OAAO,GAAGK,QAAQ,GAAGlB,cAAc,CAACoB,IAAI,CAACF,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;EAEjET,IAAAA,QAAQ,CAAC;QAAEI,OAAO;EAAEnB,MAAAA;EAAM,KAAC,CAAC;EAC9B,EAAA,CAAC,CAAC;EACJ,CAAC;;;;;;;;;;;"}
|
||||
Reference in New Issue
Block a user