@limetech/lime-elements 40.11.2 → 40.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/cjs/{focus-trigger-element-BfnJmxKO.js → focus-trigger-element-Sr7Yjtmk.js} +6 -17
- package/dist/cjs/get-focus-target-DgqZ25gx.js +105 -0
- package/dist/cjs/limel-breadcrumbs_6.cjs.entry.js +2 -1
- package/dist/cjs/limel-hotkey_4.cjs.entry.js +2 -71
- package/dist/cjs/limel-popover_2.cjs.entry.js +2 -1
- package/dist/collection/util/focus-trigger-element.js +6 -17
- package/dist/collection/util/get-focus-target.js +47 -16
- package/dist/esm/{focus-trigger-element-BOFcjLq3.js → focus-trigger-element-CIEHI_yk.js} +6 -17
- package/dist/esm/get-focus-target-BhoYaGlg.js +102 -0
- package/dist/esm/limel-breadcrumbs_6.entry.js +2 -1
- package/dist/esm/limel-hotkey_4.entry.js +1 -70
- package/dist/esm/limel-popover_2.entry.js +2 -1
- package/dist/lime-elements/lime-elements.esm.js +1 -1
- package/dist/lime-elements/p-09390c6a.entry.js +1 -0
- package/dist/lime-elements/p-25d0d06b.entry.js +159 -0
- package/dist/lime-elements/p-9ff6a455.entry.js +1 -0
- package/dist/lime-elements/p-B8Rm8W5O.js +1 -0
- package/dist/lime-elements/p-BhoYaGlg.js +1 -0
- package/dist/types/util/focus-trigger-element.d.ts +4 -4
- package/dist/types/util/get-focus-target.d.ts +18 -6
- package/package.json +1 -1
- package/dist/lime-elements/p-1a5478e3.entry.js +0 -1
- package/dist/lime-elements/p-2cf9f2e1.entry.js +0 -159
- package/dist/lime-elements/p-9461c6bb.entry.js +0 -1
- package/dist/lime-elements/p-D0F7gOYG.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [40.11.3](https://github.com/Lundalogik/lime-elements/compare/v40.11.2...v40.11.3) (2026-10-19)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
* **util:** return focus to the trigger with the shared focus lookup ([985f596](https://github.com/Lundalogik/lime-elements/commit/985f596b818d91b07c8d33f4fd85c458916acf6f))
|
|
7
|
+
|
|
1
8
|
## [40.11.2](https://github.com/Lundalogik/lime-elements/compare/v40.11.1...v40.11.2) (2026-10-19)
|
|
2
9
|
|
|
3
10
|
### Bug Fixes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var _assignValue = require('./_assignValue-DQh76m39.js');
|
|
4
|
+
var getFocusTarget = require('./get-focus-target-DgqZ25gx.js');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* This base implementation of `_.zipObject` which assigns values using `assignFunc`.
|
|
@@ -44,36 +45,24 @@ function zipObject(props, values) {
|
|
|
44
45
|
return baseZipObject(props || [], values || [], _assignValue.assignValue);
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
const FOCUSABLE_SELECTOR = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
48
48
|
const isDisabled = (element) => {
|
|
49
49
|
return (element.disabled === true ||
|
|
50
50
|
element.hasAttribute('disabled') ||
|
|
51
51
|
element.getAttribute('aria-disabled') === 'true');
|
|
52
52
|
};
|
|
53
53
|
/**
|
|
54
|
-
* Focuses the first focusable element inside
|
|
55
|
-
* Supports custom elements by searching
|
|
56
|
-
* and its light DOM.
|
|
54
|
+
* Focuses a trigger element, or the first focusable element inside it if the
|
|
55
|
+
* trigger can not take focus itself. Supports custom elements by searching
|
|
56
|
+
* both the element's shadow root and its light DOM.
|
|
57
57
|
*
|
|
58
58
|
* @param trigger - The trigger element to focus.
|
|
59
|
-
* @returns `
|
|
59
|
+
* @returns `false` if there is no trigger, or it is disabled. Otherwise `true`.
|
|
60
60
|
*/
|
|
61
61
|
const focusTriggerElement = (trigger) => {
|
|
62
|
-
var _a;
|
|
63
62
|
if (!trigger || isDisabled(trigger)) {
|
|
64
63
|
return false;
|
|
65
64
|
}
|
|
66
|
-
|
|
67
|
-
if (shadowFocusable) {
|
|
68
|
-
shadowFocusable.focus();
|
|
69
|
-
return true;
|
|
70
|
-
}
|
|
71
|
-
const lightDomFocusable = trigger.querySelector(FOCUSABLE_SELECTOR);
|
|
72
|
-
if (lightDomFocusable) {
|
|
73
|
-
lightDomFocusable.focus();
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
trigger.focus();
|
|
65
|
+
getFocusTarget.findFocusTarget(trigger).focus();
|
|
77
66
|
return true;
|
|
78
67
|
};
|
|
79
68
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const CONTROLS = ['button', 'input:not([type="hidden"])', 'select', 'textarea'];
|
|
4
|
+
const FOCUSABLE = [
|
|
5
|
+
'a[href]',
|
|
6
|
+
...CONTROLS.map((selector) => `${selector}:not([disabled])`),
|
|
7
|
+
'summary',
|
|
8
|
+
'[contenteditable]:not([contenteditable="false"])',
|
|
9
|
+
'[tabindex]',
|
|
10
|
+
]
|
|
11
|
+
.map((selector) => `${selector}:not([tabindex="-1"])`)
|
|
12
|
+
.join(', ');
|
|
13
|
+
const DISABLED = CONTROLS.map((selector) => `${selector}[disabled]:not([tabindex="-1"])`).join(', ');
|
|
14
|
+
/**
|
|
15
|
+
* Get the element that gets the focus when a user moves to `owner`. That is
|
|
16
|
+
* the owner itself if it can be focused, otherwise the first element that can
|
|
17
|
+
* be focused inside it, also inside shadow roots. A disabled control is only
|
|
18
|
+
* used when there is nothing that can be focused, and if there is no control
|
|
19
|
+
* at all, the owner itself is used.
|
|
20
|
+
*
|
|
21
|
+
* An element that passes the focus on to an element in its shadow root is
|
|
22
|
+
* never used itself, since the focus lands on the element inside.
|
|
23
|
+
*
|
|
24
|
+
* Waits for the components in the way to render, so use this for an owner
|
|
25
|
+
* that may not have rendered yet.
|
|
26
|
+
*
|
|
27
|
+
* @see findFocusTarget for an owner that has already rendered
|
|
28
|
+
* @param owner
|
|
29
|
+
*/
|
|
30
|
+
async function getFocusTarget(owner) {
|
|
31
|
+
return runWalk(findTarget(owner));
|
|
32
|
+
}
|
|
33
|
+
async function runWalk(walk, step = walk.next()) {
|
|
34
|
+
if (step.done) {
|
|
35
|
+
return step.value;
|
|
36
|
+
}
|
|
37
|
+
await step.value.componentOnReady();
|
|
38
|
+
const found = await runWalk(walk, walk.next());
|
|
39
|
+
return found;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Same as `getFocusTarget`, for an owner that has already rendered, without
|
|
43
|
+
* waiting for any component.
|
|
44
|
+
*
|
|
45
|
+
* @see getFocusTarget for an owner that may not have rendered yet
|
|
46
|
+
* @param owner
|
|
47
|
+
*/
|
|
48
|
+
function findFocusTarget(owner) {
|
|
49
|
+
const walk = findTarget(owner);
|
|
50
|
+
for (let step = walk.next();; step = walk.next()) {
|
|
51
|
+
if (step.done) {
|
|
52
|
+
return step.value;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function* findTarget(owner) {
|
|
57
|
+
var _a;
|
|
58
|
+
const search = {};
|
|
59
|
+
const found = yield* find(owner, search);
|
|
60
|
+
return (_a = found !== null && found !== void 0 ? found : search.disabled) !== null && _a !== void 0 ? _a : owner;
|
|
61
|
+
}
|
|
62
|
+
function* find(element, search) {
|
|
63
|
+
if (isFocusable(element)) {
|
|
64
|
+
return element;
|
|
65
|
+
}
|
|
66
|
+
rememberDisabled(element, search);
|
|
67
|
+
return yield* findInside(element, search);
|
|
68
|
+
}
|
|
69
|
+
function* findInside(element, search) {
|
|
70
|
+
if (isStencilComponent(element)) {
|
|
71
|
+
yield element;
|
|
72
|
+
}
|
|
73
|
+
const inShadowRoot = element.shadowRoot
|
|
74
|
+
? yield* findAmong(element.shadowRoot.children, search)
|
|
75
|
+
: undefined;
|
|
76
|
+
return inShadowRoot !== null && inShadowRoot !== void 0 ? inShadowRoot : (yield* findAmong(element.children, search));
|
|
77
|
+
}
|
|
78
|
+
function* findAmong(elements, search) {
|
|
79
|
+
for (const element of elements) {
|
|
80
|
+
if (element.localName === 'limel-tooltip') {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const found = yield* find(element, search);
|
|
84
|
+
if (found) {
|
|
85
|
+
return found;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
function isFocusable(element) {
|
|
91
|
+
var _a;
|
|
92
|
+
return !((_a = element.shadowRoot) === null || _a === void 0 ? void 0 : _a.delegatesFocus) && element.matches(FOCUSABLE);
|
|
93
|
+
}
|
|
94
|
+
function rememberDisabled(element, search) {
|
|
95
|
+
if (!search.disabled && element.matches(DISABLED)) {
|
|
96
|
+
search.disabled = element;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function isStencilComponent(element) {
|
|
100
|
+
return ('componentOnReady' in element &&
|
|
101
|
+
typeof element.componentOnReady === 'function');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
exports.findFocusTarget = findFocusTarget;
|
|
105
|
+
exports.getFocusTarget = getFocusTarget;
|
|
@@ -9,7 +9,7 @@ var linkHelper = require('./link-helper-DwlfFJVL.js');
|
|
|
9
9
|
var config = require('./config-dit--4m5.js');
|
|
10
10
|
var debounce = require('./debounce-DgDnRSlt.js');
|
|
11
11
|
var component = require('./component-Cz24PdGy.js');
|
|
12
|
-
var focusTriggerElement = require('./focus-trigger-element-
|
|
12
|
+
var focusTriggerElement = require('./focus-trigger-element-Sr7Yjtmk.js');
|
|
13
13
|
var hotkeys = require('./hotkeys-D761KWnZ.js');
|
|
14
14
|
var isFunction = require('./isFunction-RSHwsz1x.js');
|
|
15
15
|
var ponyfill = require('./ponyfill-CHp7Zocr.js');
|
|
@@ -25,6 +25,7 @@ require('./_assignValue-DQh76m39.js');
|
|
|
25
25
|
require('./_defineProperty-Csu6P9HT.js');
|
|
26
26
|
require('./_getNative-Cf52giNE.js');
|
|
27
27
|
require('./eq-DFcUoVzv.js');
|
|
28
|
+
require('./get-focus-target-DgqZ25gx.js');
|
|
28
29
|
|
|
29
30
|
const breadcrumbsCss = () => `@charset "UTF-8";:host(limel-breadcrumbs){--limel-breadcrumbs-item-height:1.5rem;--limel-breadcrumbs-gap:0.75rem;--limel-breadcrumbs-gap:0.75rem;--limel-breadcrumbs-item-text-color:var( --breadcrumbs-item-text-color, rgb(var(--contrast-1500)) );--limel-overflow-mask-horizontal:linear-gradient( to right, transparent 0%, black calc(0% + var(--limel-left-edge-fade-width, 1rem)), black calc(100% - var(--limel-right-edge-fade-width, 1rem)), transparent 100% );-webkit-mask-image:var(--limel-overflow-mask-horizontal);mask-image:var(--limel-overflow-mask-horizontal);padding-left:var(--limel-left-edge-fade-width, 1rem);padding-right:var(--limel-right-edge-fade-width, 1rem);--limel-left-edge-fade-width:0.5rem;--limel-right-edge-fade-width:0.5rem}ol,li,.step{all:unset}*{box-sizing:border-box}ol{padding:0.5rem;gap:var(--limel-breadcrumbs-gap)}.step{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:0.25rem;max-width:var(--breadcrumbs-item-max-width, 10rem);height:var(--limel-breadcrumbs-item-height);color:var(--limel-breadcrumbs-item-text-color);border-radius:100vw;font-size:var(--limel-theme-default-font-size);padding:0 0.25rem}.step:not(:has(.text)){padding:0 0.125rem}.step:not(.last):focus{outline:none}.step:not(.last):focus-visible{outline:none;box-shadow:var(--shadow-depth-8-focused)}.step:not(.last):after{content:var(--limel-breadcrumbs-divider);display:flex;align-items:center;justify-content:center;width:var(--limel-breadcrumbs-gap);position:absolute;top:0;right:calc(var(--limel-breadcrumbs-gap) * -1);bottom:0;left:auto;text-align:center}a.step{position:relative;cursor:pointer;transition:color 0.2s ease;color:var(--limel-breadcrumbs-item-text-color)}a.step:before{transition:opacity 0.2s ease, transform 0.3s ease-out;content:"";position:absolute;inset:auto 0 0 0;width:calc(100% - 0.5rem);margin:auto;height:0.125rem;border-radius:1rem;background-color:currentColor;opacity:0;transform:scale(0.6)}a.step:hover{color:rgb(var(--color-blue-default))}a.step:hover:before{opacity:0.3;transform:scale(1)}button.step:not(.last){transition:color var(--limel-clickable-transition-speed, 0.4s) ease, background-color var(--limel-clickable-transition-speed, 0.4s) ease, box-shadow var(--limel-clickable-transform-speed, 0.4s) ease, transform var(--limel-clickable-transform-speed, 0.4s) var(--limel-clickable-transform-timing-function, ease);cursor:pointer;color:var(--limel-breadcrumbs-item-text-color);background-color:transparent}button.step:not(.last):hover,button.step:not(.last):focus,button.step:not(.last):focus-visible{will-change:color, background-color, box-shadow, transform}button.step:not(.last):hover,button.step:not(.last):focus-visible{transform:translate3d(0, 0.01rem, 0);color:var(--limel-theme-on-surface-color);background-color:var(--lime-elevated-surface-background-color)}button.step:not(.last):hover{box-shadow:var(--button-shadow-hovered)}button.step:not(.last):active{--limel-clickable-transform-timing-function:cubic-bezier( 0.83, -0.15, 0.49, 1.16 );transform:translate3d(0, 0.05rem, 0);box-shadow:var(--button-shadow-pressed)}button.step:not(.last):hover,button.step:not(.last):active{--limel-clickable-transition-speed:0.2s;--limel-clickable-transform-speed:0.16s}limel-icon{flex-shrink:0;width:calc(var(--limel-breadcrumbs-item-height) - 0.25rem);height:calc(var(--limel-breadcrumbs-item-height) - 0.25rem)}.text{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;padding:0 0.25rem}.last{opacity:0.7}:host(limel-breadcrumbs){box-sizing:border-box;display:flex;width:100%;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}:host(limel-breadcrumbs)::-webkit-scrollbar{display:none}:host(limel-breadcrumbs){direction:rtl}ol{display:flex;flex-direction:row-reverse;justify-content:flex-end;margin-right:auto}.step{direction:ltr}`;
|
|
30
31
|
|
|
@@ -4,6 +4,7 @@ var index = require('./index-BlsqxTB1.js');
|
|
|
4
4
|
var hotkeys = require('./hotkeys-D761KWnZ.js');
|
|
5
5
|
var device = require('./device-C9O7lYI9.js');
|
|
6
6
|
var randomString = require('./random-string-CFCtFh5l.js');
|
|
7
|
+
var getFocusTarget = require('./get-focus-target-DgqZ25gx.js');
|
|
7
8
|
|
|
8
9
|
// Note: this function handles the same key aliases as `KEY_ALIASES` in
|
|
9
10
|
// `../../util/hotkeys.ts`, but maps them to display strings rather than
|
|
@@ -2344,76 +2345,6 @@ function normalize(text) {
|
|
|
2344
2345
|
return text.replaceAll(/\s+/g, ' ').trim().toLowerCase();
|
|
2345
2346
|
}
|
|
2346
2347
|
|
|
2347
|
-
const CONTROLS = ['button', 'input:not([type="hidden"])', 'select', 'textarea'];
|
|
2348
|
-
const FOCUSABLE = [
|
|
2349
|
-
'a[href]',
|
|
2350
|
-
...CONTROLS.map((selector) => `${selector}:not([disabled])`),
|
|
2351
|
-
'summary',
|
|
2352
|
-
'[contenteditable]:not([contenteditable="false"])',
|
|
2353
|
-
'[tabindex]',
|
|
2354
|
-
]
|
|
2355
|
-
.map((selector) => `${selector}:not([tabindex="-1"])`)
|
|
2356
|
-
.join(', ');
|
|
2357
|
-
const DISABLED = CONTROLS.map((selector) => `${selector}[disabled]:not([tabindex="-1"])`).join(', ');
|
|
2358
|
-
/**
|
|
2359
|
-
* Get the element that a screen reader describes for the owner element of a
|
|
2360
|
-
* tooltip. That is the owner itself if it can be focused, otherwise the first
|
|
2361
|
-
* element that can be focused inside it, also inside shadow roots. A disabled
|
|
2362
|
-
* control is only used when there is nothing that can be focused, and if
|
|
2363
|
-
* there is no control at all, the owner itself is used.
|
|
2364
|
-
*
|
|
2365
|
-
* An element that passes the focus on to an element in its shadow root is
|
|
2366
|
-
* never used itself, since the screen reader lands on the element inside.
|
|
2367
|
-
*
|
|
2368
|
-
* @param owner
|
|
2369
|
-
*/
|
|
2370
|
-
async function getFocusTarget(owner) {
|
|
2371
|
-
var _a, _b;
|
|
2372
|
-
const search = {};
|
|
2373
|
-
return (_b = (_a = (await find(owner, search))) !== null && _a !== void 0 ? _a : search.disabled) !== null && _b !== void 0 ? _b : owner;
|
|
2374
|
-
}
|
|
2375
|
-
async function find(element, search) {
|
|
2376
|
-
if (isFocusable(element)) {
|
|
2377
|
-
return element;
|
|
2378
|
-
}
|
|
2379
|
-
rememberDisabled(element, search);
|
|
2380
|
-
return findInside(element, search);
|
|
2381
|
-
}
|
|
2382
|
-
async function findInside(element, search) {
|
|
2383
|
-
if (isStencilComponent(element)) {
|
|
2384
|
-
await element.componentOnReady();
|
|
2385
|
-
}
|
|
2386
|
-
const inShadowRoot = element.shadowRoot
|
|
2387
|
-
? await findAmong(element.shadowRoot.children, search)
|
|
2388
|
-
: undefined;
|
|
2389
|
-
return inShadowRoot !== null && inShadowRoot !== void 0 ? inShadowRoot : findAmong(element.children, search);
|
|
2390
|
-
}
|
|
2391
|
-
async function findAmong(elements, search) {
|
|
2392
|
-
for (const element of elements) {
|
|
2393
|
-
if (element.localName === 'limel-tooltip') {
|
|
2394
|
-
continue;
|
|
2395
|
-
}
|
|
2396
|
-
const found = await find(element, search);
|
|
2397
|
-
if (found) {
|
|
2398
|
-
return found;
|
|
2399
|
-
}
|
|
2400
|
-
}
|
|
2401
|
-
return undefined;
|
|
2402
|
-
}
|
|
2403
|
-
function isFocusable(element) {
|
|
2404
|
-
var _a;
|
|
2405
|
-
return !((_a = element.shadowRoot) === null || _a === void 0 ? void 0 : _a.delegatesFocus) && element.matches(FOCUSABLE);
|
|
2406
|
-
}
|
|
2407
|
-
function rememberDisabled(element, search) {
|
|
2408
|
-
if (!search.disabled && element.matches(DISABLED)) {
|
|
2409
|
-
search.disabled = element;
|
|
2410
|
-
}
|
|
2411
|
-
}
|
|
2412
|
-
function isStencilComponent(element) {
|
|
2413
|
-
return ('componentOnReady' in element &&
|
|
2414
|
-
typeof element.componentOnReady === 'function');
|
|
2415
|
-
}
|
|
2416
|
-
|
|
2417
2348
|
/**
|
|
2418
2349
|
*
|
|
2419
2350
|
* @param id
|
|
@@ -2499,7 +2430,7 @@ const Tooltip = class {
|
|
|
2499
2430
|
return;
|
|
2500
2431
|
}
|
|
2501
2432
|
const update = ++this.latestUpdate;
|
|
2502
|
-
const element = await getFocusTarget(this.ownerElement);
|
|
2433
|
+
const element = await getFocusTarget.getFocusTarget(this.ownerElement);
|
|
2503
2434
|
if (!this.host.isConnected || update !== this.latestUpdate) {
|
|
2504
2435
|
return;
|
|
2505
2436
|
}
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
var index = require('./index-BlsqxTB1.js');
|
|
4
4
|
var randomString = require('./random-string-CFCtFh5l.js');
|
|
5
5
|
var keycodes = require('./keycodes-BQ_AERli.js');
|
|
6
|
-
var focusTriggerElement = require('./focus-trigger-element-
|
|
6
|
+
var focusTriggerElement = require('./focus-trigger-element-Sr7Yjtmk.js');
|
|
7
7
|
require('./_assignValue-DQh76m39.js');
|
|
8
8
|
require('./_defineProperty-Csu6P9HT.js');
|
|
9
9
|
require('./_getNative-Cf52giNE.js');
|
|
10
10
|
require('./isFunction-RSHwsz1x.js');
|
|
11
11
|
require('./isObject-B6Osvvqp.js');
|
|
12
12
|
require('./eq-DFcUoVzv.js');
|
|
13
|
+
require('./get-focus-target-DgqZ25gx.js');
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Check if an element is a descendant of another
|
|
@@ -1,32 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
import { findFocusTarget } from "./get-focus-target";
|
|
2
2
|
const isDisabled = (element) => {
|
|
3
3
|
return (element.disabled === true ||
|
|
4
4
|
element.hasAttribute('disabled') ||
|
|
5
5
|
element.getAttribute('aria-disabled') === 'true');
|
|
6
6
|
};
|
|
7
7
|
/**
|
|
8
|
-
* Focuses the first focusable element inside
|
|
9
|
-
* Supports custom elements by searching
|
|
10
|
-
* and its light DOM.
|
|
8
|
+
* Focuses a trigger element, or the first focusable element inside it if the
|
|
9
|
+
* trigger can not take focus itself. Supports custom elements by searching
|
|
10
|
+
* both the element's shadow root and its light DOM.
|
|
11
11
|
*
|
|
12
12
|
* @param trigger - The trigger element to focus.
|
|
13
|
-
* @returns `
|
|
13
|
+
* @returns `false` if there is no trigger, or it is disabled. Otherwise `true`.
|
|
14
14
|
*/
|
|
15
15
|
export const focusTriggerElement = (trigger) => {
|
|
16
|
-
var _a;
|
|
17
16
|
if (!trigger || isDisabled(trigger)) {
|
|
18
17
|
return false;
|
|
19
18
|
}
|
|
20
|
-
|
|
21
|
-
if (shadowFocusable) {
|
|
22
|
-
shadowFocusable.focus();
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
const lightDomFocusable = trigger.querySelector(FOCUSABLE_SELECTOR);
|
|
26
|
-
if (lightDomFocusable) {
|
|
27
|
-
lightDomFocusable.focus();
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
trigger.focus();
|
|
19
|
+
findFocusTarget(trigger).focus();
|
|
31
20
|
return true;
|
|
32
21
|
};
|
|
@@ -10,44 +10,75 @@ const FOCUSABLE = [
|
|
|
10
10
|
.join(', ');
|
|
11
11
|
const DISABLED = CONTROLS.map((selector) => `${selector}[disabled]:not([tabindex="-1"])`).join(', ');
|
|
12
12
|
/**
|
|
13
|
-
* Get the element that
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* Get the element that gets the focus when a user moves to `owner`. That is
|
|
14
|
+
* the owner itself if it can be focused, otherwise the first element that can
|
|
15
|
+
* be focused inside it, also inside shadow roots. A disabled control is only
|
|
16
|
+
* used when there is nothing that can be focused, and if there is no control
|
|
17
|
+
* at all, the owner itself is used.
|
|
18
18
|
*
|
|
19
19
|
* An element that passes the focus on to an element in its shadow root is
|
|
20
|
-
* never used itself, since the
|
|
20
|
+
* never used itself, since the focus lands on the element inside.
|
|
21
21
|
*
|
|
22
|
+
* Waits for the components in the way to render, so use this for an owner
|
|
23
|
+
* that may not have rendered yet.
|
|
24
|
+
*
|
|
25
|
+
* @see findFocusTarget for an owner that has already rendered
|
|
22
26
|
* @param owner
|
|
23
27
|
*/
|
|
24
28
|
export async function getFocusTarget(owner) {
|
|
25
|
-
|
|
29
|
+
return runWalk(findTarget(owner));
|
|
30
|
+
}
|
|
31
|
+
async function runWalk(walk, step = walk.next()) {
|
|
32
|
+
if (step.done) {
|
|
33
|
+
return step.value;
|
|
34
|
+
}
|
|
35
|
+
await step.value.componentOnReady();
|
|
36
|
+
const found = await runWalk(walk, walk.next());
|
|
37
|
+
return found;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Same as `getFocusTarget`, for an owner that has already rendered, without
|
|
41
|
+
* waiting for any component.
|
|
42
|
+
*
|
|
43
|
+
* @see getFocusTarget for an owner that may not have rendered yet
|
|
44
|
+
* @param owner
|
|
45
|
+
*/
|
|
46
|
+
export function findFocusTarget(owner) {
|
|
47
|
+
const walk = findTarget(owner);
|
|
48
|
+
for (let step = walk.next();; step = walk.next()) {
|
|
49
|
+
if (step.done) {
|
|
50
|
+
return step.value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function* findTarget(owner) {
|
|
55
|
+
var _a;
|
|
26
56
|
const search = {};
|
|
27
|
-
|
|
57
|
+
const found = yield* find(owner, search);
|
|
58
|
+
return (_a = found !== null && found !== void 0 ? found : search.disabled) !== null && _a !== void 0 ? _a : owner;
|
|
28
59
|
}
|
|
29
|
-
|
|
60
|
+
function* find(element, search) {
|
|
30
61
|
if (isFocusable(element)) {
|
|
31
62
|
return element;
|
|
32
63
|
}
|
|
33
64
|
rememberDisabled(element, search);
|
|
34
|
-
return findInside(element, search);
|
|
65
|
+
return yield* findInside(element, search);
|
|
35
66
|
}
|
|
36
|
-
|
|
67
|
+
function* findInside(element, search) {
|
|
37
68
|
if (isStencilComponent(element)) {
|
|
38
|
-
|
|
69
|
+
yield element;
|
|
39
70
|
}
|
|
40
71
|
const inShadowRoot = element.shadowRoot
|
|
41
|
-
?
|
|
72
|
+
? yield* findAmong(element.shadowRoot.children, search)
|
|
42
73
|
: undefined;
|
|
43
|
-
return inShadowRoot !== null && inShadowRoot !== void 0 ? inShadowRoot : findAmong(element.children, search);
|
|
74
|
+
return inShadowRoot !== null && inShadowRoot !== void 0 ? inShadowRoot : (yield* findAmong(element.children, search));
|
|
44
75
|
}
|
|
45
|
-
|
|
76
|
+
function* findAmong(elements, search) {
|
|
46
77
|
for (const element of elements) {
|
|
47
78
|
if (element.localName === 'limel-tooltip') {
|
|
48
79
|
continue;
|
|
49
80
|
}
|
|
50
|
-
const found =
|
|
81
|
+
const found = yield* find(element, search);
|
|
51
82
|
if (found) {
|
|
52
83
|
return found;
|
|
53
84
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { a as assignValue } from './_assignValue-CEFvyZxO.js';
|
|
2
|
+
import { f as findFocusTarget } from './get-focus-target-BhoYaGlg.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* This base implementation of `_.zipObject` which assigns values using `assignFunc`.
|
|
@@ -42,36 +43,24 @@ function zipObject(props, values) {
|
|
|
42
43
|
return baseZipObject(props || [], values || [], assignValue);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
const FOCUSABLE_SELECTOR = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
46
46
|
const isDisabled = (element) => {
|
|
47
47
|
return (element.disabled === true ||
|
|
48
48
|
element.hasAttribute('disabled') ||
|
|
49
49
|
element.getAttribute('aria-disabled') === 'true');
|
|
50
50
|
};
|
|
51
51
|
/**
|
|
52
|
-
* Focuses the first focusable element inside
|
|
53
|
-
* Supports custom elements by searching
|
|
54
|
-
* and its light DOM.
|
|
52
|
+
* Focuses a trigger element, or the first focusable element inside it if the
|
|
53
|
+
* trigger can not take focus itself. Supports custom elements by searching
|
|
54
|
+
* both the element's shadow root and its light DOM.
|
|
55
55
|
*
|
|
56
56
|
* @param trigger - The trigger element to focus.
|
|
57
|
-
* @returns `
|
|
57
|
+
* @returns `false` if there is no trigger, or it is disabled. Otherwise `true`.
|
|
58
58
|
*/
|
|
59
59
|
const focusTriggerElement = (trigger) => {
|
|
60
|
-
var _a;
|
|
61
60
|
if (!trigger || isDisabled(trigger)) {
|
|
62
61
|
return false;
|
|
63
62
|
}
|
|
64
|
-
|
|
65
|
-
if (shadowFocusable) {
|
|
66
|
-
shadowFocusable.focus();
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
const lightDomFocusable = trigger.querySelector(FOCUSABLE_SELECTOR);
|
|
70
|
-
if (lightDomFocusable) {
|
|
71
|
-
lightDomFocusable.focus();
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
trigger.focus();
|
|
63
|
+
findFocusTarget(trigger).focus();
|
|
75
64
|
return true;
|
|
76
65
|
};
|
|
77
66
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const CONTROLS = ['button', 'input:not([type="hidden"])', 'select', 'textarea'];
|
|
2
|
+
const FOCUSABLE = [
|
|
3
|
+
'a[href]',
|
|
4
|
+
...CONTROLS.map((selector) => `${selector}:not([disabled])`),
|
|
5
|
+
'summary',
|
|
6
|
+
'[contenteditable]:not([contenteditable="false"])',
|
|
7
|
+
'[tabindex]',
|
|
8
|
+
]
|
|
9
|
+
.map((selector) => `${selector}:not([tabindex="-1"])`)
|
|
10
|
+
.join(', ');
|
|
11
|
+
const DISABLED = CONTROLS.map((selector) => `${selector}[disabled]:not([tabindex="-1"])`).join(', ');
|
|
12
|
+
/**
|
|
13
|
+
* Get the element that gets the focus when a user moves to `owner`. That is
|
|
14
|
+
* the owner itself if it can be focused, otherwise the first element that can
|
|
15
|
+
* be focused inside it, also inside shadow roots. A disabled control is only
|
|
16
|
+
* used when there is nothing that can be focused, and if there is no control
|
|
17
|
+
* at all, the owner itself is used.
|
|
18
|
+
*
|
|
19
|
+
* An element that passes the focus on to an element in its shadow root is
|
|
20
|
+
* never used itself, since the focus lands on the element inside.
|
|
21
|
+
*
|
|
22
|
+
* Waits for the components in the way to render, so use this for an owner
|
|
23
|
+
* that may not have rendered yet.
|
|
24
|
+
*
|
|
25
|
+
* @see findFocusTarget for an owner that has already rendered
|
|
26
|
+
* @param owner
|
|
27
|
+
*/
|
|
28
|
+
async function getFocusTarget(owner) {
|
|
29
|
+
return runWalk(findTarget(owner));
|
|
30
|
+
}
|
|
31
|
+
async function runWalk(walk, step = walk.next()) {
|
|
32
|
+
if (step.done) {
|
|
33
|
+
return step.value;
|
|
34
|
+
}
|
|
35
|
+
await step.value.componentOnReady();
|
|
36
|
+
const found = await runWalk(walk, walk.next());
|
|
37
|
+
return found;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Same as `getFocusTarget`, for an owner that has already rendered, without
|
|
41
|
+
* waiting for any component.
|
|
42
|
+
*
|
|
43
|
+
* @see getFocusTarget for an owner that may not have rendered yet
|
|
44
|
+
* @param owner
|
|
45
|
+
*/
|
|
46
|
+
function findFocusTarget(owner) {
|
|
47
|
+
const walk = findTarget(owner);
|
|
48
|
+
for (let step = walk.next();; step = walk.next()) {
|
|
49
|
+
if (step.done) {
|
|
50
|
+
return step.value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function* findTarget(owner) {
|
|
55
|
+
var _a;
|
|
56
|
+
const search = {};
|
|
57
|
+
const found = yield* find(owner, search);
|
|
58
|
+
return (_a = found !== null && found !== void 0 ? found : search.disabled) !== null && _a !== void 0 ? _a : owner;
|
|
59
|
+
}
|
|
60
|
+
function* find(element, search) {
|
|
61
|
+
if (isFocusable(element)) {
|
|
62
|
+
return element;
|
|
63
|
+
}
|
|
64
|
+
rememberDisabled(element, search);
|
|
65
|
+
return yield* findInside(element, search);
|
|
66
|
+
}
|
|
67
|
+
function* findInside(element, search) {
|
|
68
|
+
if (isStencilComponent(element)) {
|
|
69
|
+
yield element;
|
|
70
|
+
}
|
|
71
|
+
const inShadowRoot = element.shadowRoot
|
|
72
|
+
? yield* findAmong(element.shadowRoot.children, search)
|
|
73
|
+
: undefined;
|
|
74
|
+
return inShadowRoot !== null && inShadowRoot !== void 0 ? inShadowRoot : (yield* findAmong(element.children, search));
|
|
75
|
+
}
|
|
76
|
+
function* findAmong(elements, search) {
|
|
77
|
+
for (const element of elements) {
|
|
78
|
+
if (element.localName === 'limel-tooltip') {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const found = yield* find(element, search);
|
|
82
|
+
if (found) {
|
|
83
|
+
return found;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
function isFocusable(element) {
|
|
89
|
+
var _a;
|
|
90
|
+
return !((_a = element.shadowRoot) === null || _a === void 0 ? void 0 : _a.delegatesFocus) && element.matches(FOCUSABLE);
|
|
91
|
+
}
|
|
92
|
+
function rememberDisabled(element, search) {
|
|
93
|
+
if (!search.disabled && element.matches(DISABLED)) {
|
|
94
|
+
search.disabled = element;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function isStencilComponent(element) {
|
|
98
|
+
return ('componentOnReady' in element &&
|
|
99
|
+
typeof element.componentOnReady === 'function');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { findFocusTarget as f, getFocusTarget as g };
|
|
@@ -7,7 +7,7 @@ import { b as getHref, a as getTarget, g as getRel } from './link-helper-5KsJICv
|
|
|
7
7
|
import { g as globalConfig } from './config-Dnt5w_Bp.js';
|
|
8
8
|
import { d as debounce } from './debounce-B67JMchz.js';
|
|
9
9
|
import { M as MDCTextField } from './component-CVihTrav.js';
|
|
10
|
-
import { f as focusTriggerElement, z as zipObject } from './focus-trigger-element-
|
|
10
|
+
import { f as focusTriggerElement, z as zipObject } from './focus-trigger-element-CIEHI_yk.js';
|
|
11
11
|
import { h as hotkeyFromKeyboardEvent, t as tokenizeHotkeyString, n as normalizeHotkeyString } from './hotkeys-DjmlD0Mw.js';
|
|
12
12
|
import { i as isFunction } from './isFunction-9zQTeQI8.js';
|
|
13
13
|
import { _ as __extends, a as __assign, b as __values, M as MDCFoundation, c as MDCComponent, d as closest } from './ponyfill-6YuZiAPi.js';
|
|
@@ -23,6 +23,7 @@ import './_assignValue-CEFvyZxO.js';
|
|
|
23
23
|
import './_defineProperty-C69Btzid.js';
|
|
24
24
|
import './_getNative-COawFdVX.js';
|
|
25
25
|
import './eq-CZ30nDJE.js';
|
|
26
|
+
import './get-focus-target-BhoYaGlg.js';
|
|
26
27
|
|
|
27
28
|
const breadcrumbsCss = () => `@charset "UTF-8";:host(limel-breadcrumbs){--limel-breadcrumbs-item-height:1.5rem;--limel-breadcrumbs-gap:0.75rem;--limel-breadcrumbs-gap:0.75rem;--limel-breadcrumbs-item-text-color:var( --breadcrumbs-item-text-color, rgb(var(--contrast-1500)) );--limel-overflow-mask-horizontal:linear-gradient( to right, transparent 0%, black calc(0% + var(--limel-left-edge-fade-width, 1rem)), black calc(100% - var(--limel-right-edge-fade-width, 1rem)), transparent 100% );-webkit-mask-image:var(--limel-overflow-mask-horizontal);mask-image:var(--limel-overflow-mask-horizontal);padding-left:var(--limel-left-edge-fade-width, 1rem);padding-right:var(--limel-right-edge-fade-width, 1rem);--limel-left-edge-fade-width:0.5rem;--limel-right-edge-fade-width:0.5rem}ol,li,.step{all:unset}*{box-sizing:border-box}ol{padding:0.5rem;gap:var(--limel-breadcrumbs-gap)}.step{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:0.25rem;max-width:var(--breadcrumbs-item-max-width, 10rem);height:var(--limel-breadcrumbs-item-height);color:var(--limel-breadcrumbs-item-text-color);border-radius:100vw;font-size:var(--limel-theme-default-font-size);padding:0 0.25rem}.step:not(:has(.text)){padding:0 0.125rem}.step:not(.last):focus{outline:none}.step:not(.last):focus-visible{outline:none;box-shadow:var(--shadow-depth-8-focused)}.step:not(.last):after{content:var(--limel-breadcrumbs-divider);display:flex;align-items:center;justify-content:center;width:var(--limel-breadcrumbs-gap);position:absolute;top:0;right:calc(var(--limel-breadcrumbs-gap) * -1);bottom:0;left:auto;text-align:center}a.step{position:relative;cursor:pointer;transition:color 0.2s ease;color:var(--limel-breadcrumbs-item-text-color)}a.step:before{transition:opacity 0.2s ease, transform 0.3s ease-out;content:"";position:absolute;inset:auto 0 0 0;width:calc(100% - 0.5rem);margin:auto;height:0.125rem;border-radius:1rem;background-color:currentColor;opacity:0;transform:scale(0.6)}a.step:hover{color:rgb(var(--color-blue-default))}a.step:hover:before{opacity:0.3;transform:scale(1)}button.step:not(.last){transition:color var(--limel-clickable-transition-speed, 0.4s) ease, background-color var(--limel-clickable-transition-speed, 0.4s) ease, box-shadow var(--limel-clickable-transform-speed, 0.4s) ease, transform var(--limel-clickable-transform-speed, 0.4s) var(--limel-clickable-transform-timing-function, ease);cursor:pointer;color:var(--limel-breadcrumbs-item-text-color);background-color:transparent}button.step:not(.last):hover,button.step:not(.last):focus,button.step:not(.last):focus-visible{will-change:color, background-color, box-shadow, transform}button.step:not(.last):hover,button.step:not(.last):focus-visible{transform:translate3d(0, 0.01rem, 0);color:var(--limel-theme-on-surface-color);background-color:var(--lime-elevated-surface-background-color)}button.step:not(.last):hover{box-shadow:var(--button-shadow-hovered)}button.step:not(.last):active{--limel-clickable-transform-timing-function:cubic-bezier( 0.83, -0.15, 0.49, 1.16 );transform:translate3d(0, 0.05rem, 0);box-shadow:var(--button-shadow-pressed)}button.step:not(.last):hover,button.step:not(.last):active{--limel-clickable-transition-speed:0.2s;--limel-clickable-transform-speed:0.16s}limel-icon{flex-shrink:0;width:calc(var(--limel-breadcrumbs-item-height) - 0.25rem);height:calc(var(--limel-breadcrumbs-item-height) - 0.25rem)}.text{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;padding:0 0.25rem}.last{opacity:0.7}:host(limel-breadcrumbs){box-sizing:border-box;display:flex;width:100%;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}:host(limel-breadcrumbs)::-webkit-scrollbar{display:none}:host(limel-breadcrumbs){direction:rtl}ol{display:flex;flex-direction:row-reverse;justify-content:flex-end;margin-right:auto}.step{direction:ltr}`;
|
|
28
29
|
|