ember-primitives 0.55.1 → 0.56.0
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/README.md +9 -0
- package/declarations/color-scheme.d.ts.map +1 -1
- package/declarations/components/menu.d.ts.map +1 -1
- package/declarations/components/popover.d.ts +4 -11
- package/declarations/components/popover.d.ts.map +1 -1
- package/declarations/components/tabs.d.ts +2 -1
- package/declarations/components/tabs.d.ts.map +1 -1
- package/dist/color-scheme.js +1 -0
- package/dist/color-scheme.js.map +1 -1
- package/dist/components/menu.js +15 -8
- package/dist/components/menu.js.map +1 -1
- package/dist/components/popover.js +31 -8
- package/dist/components/popover.js.map +1 -1
- package/dist/components/tabs.js.map +1 -1
- package/package.json +6 -6
- package/src/color-scheme.ts +2 -0
- package/src/components/menu.gts +15 -7
- package/src/components/popover.gts +42 -34
- package/src/components/tabs.gts +1 -0
package/README.md
CHANGED
|
@@ -75,6 +75,13 @@ See the [Contributing](CONTRIBUTING.md) guide for details.
|
|
|
75
75
|
<sub><b>pulien</b></sub>
|
|
76
76
|
</a>
|
|
77
77
|
</td>
|
|
78
|
+
<td align="center">
|
|
79
|
+
<a href="https://github.com/bendemboski">
|
|
80
|
+
<img src="https://avatars.githubusercontent.com/u/559001?v=4" width="100;" alt="bendemboski"/>
|
|
81
|
+
<br />
|
|
82
|
+
<sub><b>Ben Demboski</b></sub>
|
|
83
|
+
</a>
|
|
84
|
+
</td>
|
|
78
85
|
<td align="center">
|
|
79
86
|
<a href="https://github.com/bartocc">
|
|
80
87
|
<img src="https://avatars.githubusercontent.com/u/47953?v=4" width="100;" alt="bartocc"/>
|
|
@@ -96,6 +103,8 @@ See the [Contributing](CONTRIBUTING.md) guide for details.
|
|
|
96
103
|
<sub><b>ember-tomster</b></sub>
|
|
97
104
|
</a>
|
|
98
105
|
</td>
|
|
106
|
+
</tr>
|
|
107
|
+
<tr>
|
|
99
108
|
<td align="center">
|
|
100
109
|
<a href="https://github.com/johanrd">
|
|
101
110
|
<img src="https://avatars.githubusercontent.com/u/4601554?v=4" width="100;" alt="johanrd"/>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color-scheme.d.ts","sourceRoot":"","sources":["../src/color-scheme.ts"],"names":[],"mappings":"AAgBA;;GAEG;AACH,eAAO,MAAM,WAAW;IACtB;;OAEG;oBACa,MAAM;;QAOpB;;WAEG;2BACgB,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI;;;QAKhD;;WAEG;2BACgB,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI;;IAKlD;;OAEG;aACY,MAAM,GAAG,SAAS;;;CAsBlC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,IAAI,SAyBnB;
|
|
1
|
+
{"version":3,"file":"color-scheme.d.ts","sourceRoot":"","sources":["../src/color-scheme.ts"],"names":[],"mappings":"AAgBA;;GAEG;AACH,eAAO,MAAM,WAAW;IACtB;;OAEG;oBACa,MAAM;;QAOpB;;WAEG;2BACgB,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI;;;QAKhD;;WAEG;2BACgB,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI;;IAKlD;;OAEG;aACY,MAAM,GAAG,SAAS;;;CAsBlC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,IAAI,SAyBnB;AAgBD;;;GAGG;AACH,eAAO,MAAM,OAAO;;;;mBAIH,MAAM;CACtB,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,eAAe;;;oBAGV,MAAM;;CAEvB,CAAC;AAEF;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,WAAW,UAInD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;AAC1E,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;AAkBpD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,WAAW,QAItD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../../src/components/menu.gts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../../src/components/menu.gts"],"names":[],"mappings":"AA6XA,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAM3C,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAGvC,OAAO,EAAQ,KAAK,SAAS,IAAI,aAAa,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAW,KAAK,SAAS,IAAI,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE5E,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,KAAK,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,KAAK,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AACtC,KAAK,WAAW,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAC5C,KAAK,kBAAkB,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAiBnE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE;QACN,OAAO,EAAE;YACP;gBACE,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC;gBACnC,OAAO,EAAE,aAAa,CACpB,OAAO,OAAO,EACd,gBAAgB,GAAG,WAAW,GAAG,QAAQ,GAAG,cAAc,CAC3D,CAAC;gBACF,OAAO,EAAE,aAAa,CAAC,OAAO,OAAO,EAAE,iBAAiB,CAAC,CAAC;gBAC1D,OAAO,EAAE,aAAa,CACpB,OAAO,OAAO,EACd,gBAAgB,GAAG,WAAW,GAAG,QAAQ,GAAG,gBAAgB,CAC7D,CAAC;gBACF,MAAM,EAAE,OAAO,CAAC;aACjB;SACF,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE;QAAE,OAAO,EAAE,EAAE,CAAA;KAAE,CAAC;CACzB;AAED,QAAA,MAAM,SAAS,EAAE,GAAG,CAAC,kBAAkB,CAYrC,CAAC;AAqBH,UAAU,oBAAoB;IAC5B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE;QAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAChE,MAAM,EAAE;QAAE,OAAO,EAAE,EAAE,CAAA;KAAE,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,oBAAoB,CAAC,SAAS,CAAC,CAAC;IACzC,IAAI,EAAE,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;IACnD,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC;CACxC;AAED,QAAA,MAAM,IAAI,EAAE,GAAG,CAAC,oBAAoB,CA8BlC,CAAC;AAEH,UAAU,YAAa,SAAQ,QAAQ;IACrC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,UAAU,wBAAwB;IAChC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE;QAAE,OAAO,EAAE,EAAE,CAAA;KAAE,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,wBAAwB,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAAC;CAC5C;AAED,QAAA,MAAM,QAAQ,EAAE,GAAG,CAAC,wBAAwB,CAoB1C,CAAC;AAwDH,UAAU,uBAAuB;IAC/B,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE;QACJ,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAClC,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACtB,cAAc,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;KAC/C,CAAC;IACF,MAAM,EAAE;QACN,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,aAAa,CAAC,OAAO,IAAI,EAAE,QAAQ,CAAC,CAAC;gBAC3C,QAAQ,EAAE,aAAa,CAAC,OAAO,QAAQ,EAAE,QAAQ,CAAC,CAAC;gBACnD,SAAS,EAAE,OAAO,SAAS,CAAC;aAC7B;SACF,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,uBAAuB,CAAC,SAAS,CAAC,CAAC;IAC5C,MAAM,EAAE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;CAC3C;AAED,QAAA,MAAM,OAAO,EAAE,GAAG,CAAC,uBAAuB,CA4BxC,CAAC;AAEH,UAAU,+BAA+B;IACvC,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE;QACJ,KAAK,EAAE;YACL,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;YAClC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACtB,SAAS,EAAE,MAAM,CAAC;YAClB,YAAY,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAC;YACjD,eAAe,CAAC,EAAE,OAAO,CAAC;YAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;SAC1B,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,+BAA+B,CAAC,SAAS,CAAC,CAAC;CACrD;AAED,QAAA,MAAM,OAAO;;;;4BAdS,IAAI,CAAC,WAAW,CAAC;oBACzB,IAAI,CAAC,OAAO,CAAC;uBACV,MAAM;0BACH,kBAAkB,CAAC,cAAc,CAAC;8BAC9B,OAAO;6BACR,OAAO;;;;EAiD7B,CAAC;AAEF,UAAU,uBAAuB;IAC/B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE;QACJ,eAAe,EAAE,aAAa,CAC5B,OAAO,OAAO,EACd,gBAAgB,GAAG,WAAW,GAAG,QAAQ,GAAG,cAAc,CAC3D,CAAC;QACF,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,MAAM,EAAE;QAAE,OAAO,EAAE,EAAE,CAAA;KAAE,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,uBAAuB,CAAC,SAAS,CAAC,CAAC;IAC5C,MAAM,EAAE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;CAC3C;AAED,QAAA,MAAM,OAAO,EAAE,GAAG,CAAC,uBAAuB,CAaxC,CAAC;AAKH,qBAAa,IAAK,SAAQ,SAAS,CAAC,SAAS,CAAC;IAC5C,SAAS,SAAiB;CAsC3B;AAED,eAAe,IAAI,CAAC"}
|
|
@@ -50,14 +50,6 @@ export interface Signature {
|
|
|
50
50
|
* This argument is forwarded to the `<FloatingUI>` component.
|
|
51
51
|
*/
|
|
52
52
|
strategy?: HookSignature["Args"]["Named"]["strategy"];
|
|
53
|
-
/**
|
|
54
|
-
* By default, the popover is portaled.
|
|
55
|
-
* If you don't control your CSS, and the positioning of the popover content
|
|
56
|
-
* is misbehaving, you may pass "@inline={{true}}" to opt out of portalling.
|
|
57
|
-
*
|
|
58
|
-
* Inline may also be useful in nested menus, where you know exactly how the nesting occurs
|
|
59
|
-
*/
|
|
60
|
-
inline?: boolean;
|
|
61
53
|
};
|
|
62
54
|
Blocks: {
|
|
63
55
|
default: [
|
|
@@ -74,8 +66,10 @@ export interface Signature {
|
|
|
74
66
|
};
|
|
75
67
|
}
|
|
76
68
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
69
|
+
* Content uses `popover="manual"` + `showPopover()` to promote
|
|
70
|
+
* the element to the browser's top layer. This escapes all ancestor
|
|
71
|
+
* overflow clipping and stacking contexts — the same guarantee that
|
|
72
|
+
* portalling provided, but using the browser's native mechanism.
|
|
79
73
|
*/
|
|
80
74
|
declare const Content: TOC<{
|
|
81
75
|
Element: HTMLDivElement;
|
|
@@ -83,7 +77,6 @@ declare const Content: TOC<{
|
|
|
83
77
|
floating: ModifierLike<{
|
|
84
78
|
Element: HTMLElement;
|
|
85
79
|
}>;
|
|
86
|
-
inline?: boolean;
|
|
87
80
|
/**
|
|
88
81
|
* By default the popover content is wrapped in a div.
|
|
89
82
|
* You may change this by supplying the name of an element here.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover.d.ts","sourceRoot":"","sources":["../../src/components/popover.gts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"popover.d.ts","sourceRoot":"","sources":["../../src/components/popover.gts"],"names":[],"mappings":"AAyQA,OAAO,KAAK,EAAE,SAAS,IAAI,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AAC7F,OAAO,KAAK,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gCAAgC,CAAC;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEnE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE;QACJ;;;;WAIG;QACH,WAAW,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC;QAC5D;;;;WAIG;QACH,UAAU,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC;QAC1D;;;;WAIG;QACH,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,eAAe,CAAC,CAAC;QAChE;;;;;;;;;;;;WAYG;QACH,SAAS,CAAC,EAAE,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,EAAE,GAAG,QAAQ,GAAG,MAAM,EAAE,CAAC;QAC9E;;;;WAIG;QACH,YAAY,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC;QAC9D;;;;;;WAMG;QACH,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;KACvD,CAAC;IACF,MAAM,EAAE;QACN,OAAO,EAAE;YACP;gBACE,SAAS,EAAE,4BAA4B,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChE,YAAY,EAAE,4BAA4B,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;gBACnF,OAAO,EAAE,aAAa,CAAC,OAAO,OAAO,EAAE,UAAU,CAAC,CAAC;gBACnD,IAAI,EAAE,4BAA4B,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;gBACnE,KAAK,EAAE,YAAY,CAAC;oBAAE,OAAO,EAAE,WAAW,CAAA;iBAAE,CAAC,CAAC;aAC/C;SACF,CAAC;KACH,CAAC;CACH;AAoCD;;;;;GAKG;AACH,QAAA,MAAM,OAAO,EAAE,GAAG,CAAC;IACjB,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE;QACJ,QAAQ,EAAE,YAAY,CAAC;YAAE,OAAO,EAAE,WAAW,CAAA;SAAE,CAAC,CAAC;QACjD;;;;;;;;;;;;WAYG;QACH,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,CAAC;IACF,MAAM,EAAE;QAAE,OAAO,EAAE,EAAE,CAAA;KAAE,CAAC;CACzB,CA0BC,CAAC;AAkFH,eAAO,MAAM,OAAO,EAAE,GAAG,CAAC,SAAS,CAmCjC,CAAC;AAEH,eAAe,OAAO,CAAC"}
|
|
@@ -19,6 +19,7 @@ export interface ButtonSignature {
|
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
declare const TabButton: TOC<{
|
|
22
|
+
Element: HTMLButtonElement;
|
|
22
23
|
Args: {
|
|
23
24
|
/**
|
|
24
25
|
* @internal
|
|
@@ -211,7 +212,7 @@ declare class TabState {
|
|
|
211
212
|
activeTab?: string;
|
|
212
213
|
onChange?: () => void;
|
|
213
214
|
});
|
|
214
|
-
get activationMode(): "
|
|
215
|
+
get activationMode(): "manual" | "automatic";
|
|
215
216
|
get isAutomatic(): boolean;
|
|
216
217
|
/**
|
|
217
218
|
* This function relies on the fact that during rendering,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../src/components/tabs.gts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,
|
|
1
|
+
{"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../src/components/tabs.gts"],"names":[],"mappings":"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"}
|
package/dist/color-scheme.js
CHANGED
|
@@ -94,6 +94,7 @@ const queries = {
|
|
|
94
94
|
none: window.matchMedia('(prefers-color-scheme: no-preference)')
|
|
95
95
|
};
|
|
96
96
|
queries.dark.addEventListener('change', e => {
|
|
97
|
+
if (localPreference.isSet()) return;
|
|
97
98
|
const mode = e.matches ? 'dark' : 'light';
|
|
98
99
|
colorScheme.update(mode);
|
|
99
100
|
});
|
package/dist/color-scheme.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color-scheme.js","sources":["../src/color-scheme.ts"],"sourcesContent":["import { waitForPromise } from '@ember/test-waiters';\n\nimport { cell } from 'ember-resources';\n\nconst _colorScheme = cell<string | undefined>();\n\nlet callbacks: Set<(colorScheme: string) => void> = new Set();\n\nasync function runCallbacks(theme: string) {\n await Promise.resolve();\n\n for (const callback of callbacks.values()) {\n callback(theme);\n }\n}\n\n/**\n * Object for managing the color scheme\n */\nexport const colorScheme = {\n /**\n * Set's the current color scheme to the passed value\n */\n update: (value: string) => {\n colorScheme.current = value;\n\n void waitForPromise(runCallbacks(value));\n },\n\n on: {\n /**\n * register a function to be called when the color scheme changes.\n */\n update: (callback: (colorScheme: string) => void) => {\n callbacks.add(callback);\n },\n },\n off: {\n /**\n * unregister a function that would have been called when the color scheme changes.\n */\n update: (callback: (colorScheme: string) => void) => {\n callbacks.delete(callback);\n },\n },\n\n /**\n * the current valuel of the \"color scheme\"\n */\n get current(): string | undefined {\n return _colorScheme.current;\n },\n set current(value: string | undefined) {\n _colorScheme.current = value;\n\n if (!value) {\n localPreference.delete();\n\n return;\n }\n\n localPreference.update(value);\n setColorScheme(value);\n },\n\n get isDark() {\n return _colorScheme.current === 'dark';\n },\n get isLight() {\n return _colorScheme.current !== 'dark';\n },\n};\n\n/**\n * Synchronizes state of `colorScheme` with the users preferences as well as reconciles with previously set theme in local storage.\n *\n * This may only be called once per app.\n */\nexport function sync() {\n /**\n * reset the callbacks\n */\n callbacks = new Set();\n\n /**\n * If local prefs are set, then we don't care what prefers-color-scheme is\n */\n const userPreference = localPreference.read();\n\n if (userPreference) {\n setColorScheme(userPreference);\n _colorScheme.current = userPreference;\n\n return;\n }\n\n if (prefers.dark()) {\n setColorScheme('dark');\n _colorScheme.current = 'dark';\n } else if (prefers.light()) {\n setColorScheme('light');\n _colorScheme.current = 'light';\n }\n}\n\nconst queries = {\n dark: window.matchMedia('(prefers-color-scheme: dark)'),\n light: window.matchMedia('(prefers-color-scheme: light)'),\n none: window.matchMedia('(prefers-color-scheme: no-preference)'),\n};\n\nqueries.dark.addEventListener('change', (e) => {\n const mode = e.matches ? 'dark' : 'light';\n\n colorScheme.update(mode);\n});\n\n/**\n * Helper methods to determining what the user's preferred color scheme is\n * based on the system preferences rather than the users explicit preference.\n */\nexport const prefers = {\n dark: () => queries.dark.matches,\n light: () => queries.light.matches,\n none: () => queries.none.matches,\n custom: (name: string) => window.matchMedia(`(prefers-color-scheme: ${name})`).matches,\n};\n\nconst LOCAL_PREF_KEY = 'ember-primitives/color-scheme#local-preference';\n\n/**\n * Helper methods for working with the color scheme preference in local storage\n */\nexport const localPreference = {\n isSet: () => Boolean(localPreference.read()),\n read: () => localStorage.getItem(LOCAL_PREF_KEY),\n update: (value: string) => localStorage.setItem(LOCAL_PREF_KEY, value),\n delete: () => localStorage.removeItem(LOCAL_PREF_KEY),\n};\n\n/**\n * For the given element, returns the `color-scheme` of that element.\n */\nexport function getColorScheme(element?: HTMLElement) {\n const style = styleOf(element);\n\n return style.getPropertyValue('color-scheme');\n}\n\nexport function setColorScheme(element: HTMLElement, value: string): void;\nexport function setColorScheme(value: string): void;\n\nexport function setColorScheme(...args: [string] | [HTMLElement, string]): void {\n if (typeof args[0] === 'string') {\n styleOf().setProperty('color-scheme', args[0]);\n\n return;\n }\n\n if (typeof args[1] === 'string') {\n styleOf(args[0]).setProperty('color-scheme', args[1]);\n\n return;\n }\n\n throw new Error(`Invalid arity, expected up to 2 args, received ${args.length}`);\n}\n\n/**\n * Removes the `color-scheme` from the given element\n */\nexport function removeColorScheme(element?: HTMLElement) {\n const style = styleOf(element);\n\n style.removeProperty('color-scheme');\n}\n\nfunction styleOf(element?: HTMLElement) {\n if (element) {\n return element.style;\n }\n\n return document.documentElement.style;\n}\n\nsync();\n\nwindow.addEventListener('storage', (e: StorageEvent) => {\n try {\n if (e.key !== LOCAL_PREF_KEY) return;\n\n // If the key was removed in another tab, fall back to system preference\n if (e.newValue === null) {\n if (prefers.dark()) {\n colorScheme.update('dark');\n\n return;\n } else if (prefers.light()) {\n colorScheme.update('light');\n\n return;\n }\n\n // default to light\n colorScheme.update('light');\n\n return;\n }\n\n const newScheme = e.newValue;\n\n colorScheme.update(newScheme);\n } catch {\n // swallow errors from storage event handling\n }\n});\n"],"names":["_colorScheme","cell","callbacks","Set","runCallbacks","theme","Promise","resolve","callback","values","colorScheme","update","value","current","waitForPromise","on","add","off","delete","localPreference","setColorScheme","isDark","isLight","sync","userPreference","read","prefers","dark","light","queries","window","matchMedia","none","addEventListener","e","mode","matches","custom","name","LOCAL_PREF_KEY","isSet","Boolean","localStorage","getItem","setItem","removeItem","getColorScheme","element","style","styleOf","getPropertyValue","args","setProperty","Error","length","removeColorScheme","removeProperty","document","documentElement","key","newValue","newScheme"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"color-scheme.js","sources":["../src/color-scheme.ts"],"sourcesContent":["import { waitForPromise } from '@ember/test-waiters';\n\nimport { cell } from 'ember-resources';\n\nconst _colorScheme = cell<string | undefined>();\n\nlet callbacks: Set<(colorScheme: string) => void> = new Set();\n\nasync function runCallbacks(theme: string) {\n await Promise.resolve();\n\n for (const callback of callbacks.values()) {\n callback(theme);\n }\n}\n\n/**\n * Object for managing the color scheme\n */\nexport const colorScheme = {\n /**\n * Set's the current color scheme to the passed value\n */\n update: (value: string) => {\n colorScheme.current = value;\n\n void waitForPromise(runCallbacks(value));\n },\n\n on: {\n /**\n * register a function to be called when the color scheme changes.\n */\n update: (callback: (colorScheme: string) => void) => {\n callbacks.add(callback);\n },\n },\n off: {\n /**\n * unregister a function that would have been called when the color scheme changes.\n */\n update: (callback: (colorScheme: string) => void) => {\n callbacks.delete(callback);\n },\n },\n\n /**\n * the current valuel of the \"color scheme\"\n */\n get current(): string | undefined {\n return _colorScheme.current;\n },\n set current(value: string | undefined) {\n _colorScheme.current = value;\n\n if (!value) {\n localPreference.delete();\n\n return;\n }\n\n localPreference.update(value);\n setColorScheme(value);\n },\n\n get isDark() {\n return _colorScheme.current === 'dark';\n },\n get isLight() {\n return _colorScheme.current !== 'dark';\n },\n};\n\n/**\n * Synchronizes state of `colorScheme` with the users preferences as well as reconciles with previously set theme in local storage.\n *\n * This may only be called once per app.\n */\nexport function sync() {\n /**\n * reset the callbacks\n */\n callbacks = new Set();\n\n /**\n * If local prefs are set, then we don't care what prefers-color-scheme is\n */\n const userPreference = localPreference.read();\n\n if (userPreference) {\n setColorScheme(userPreference);\n _colorScheme.current = userPreference;\n\n return;\n }\n\n if (prefers.dark()) {\n setColorScheme('dark');\n _colorScheme.current = 'dark';\n } else if (prefers.light()) {\n setColorScheme('light');\n _colorScheme.current = 'light';\n }\n}\n\nconst queries = {\n dark: window.matchMedia('(prefers-color-scheme: dark)'),\n light: window.matchMedia('(prefers-color-scheme: light)'),\n none: window.matchMedia('(prefers-color-scheme: no-preference)'),\n};\n\nqueries.dark.addEventListener('change', (e) => {\n if (localPreference.isSet()) return;\n\n const mode = e.matches ? 'dark' : 'light';\n\n colorScheme.update(mode);\n});\n\n/**\n * Helper methods to determining what the user's preferred color scheme is\n * based on the system preferences rather than the users explicit preference.\n */\nexport const prefers = {\n dark: () => queries.dark.matches,\n light: () => queries.light.matches,\n none: () => queries.none.matches,\n custom: (name: string) => window.matchMedia(`(prefers-color-scheme: ${name})`).matches,\n};\n\nconst LOCAL_PREF_KEY = 'ember-primitives/color-scheme#local-preference';\n\n/**\n * Helper methods for working with the color scheme preference in local storage\n */\nexport const localPreference = {\n isSet: () => Boolean(localPreference.read()),\n read: () => localStorage.getItem(LOCAL_PREF_KEY),\n update: (value: string) => localStorage.setItem(LOCAL_PREF_KEY, value),\n delete: () => localStorage.removeItem(LOCAL_PREF_KEY),\n};\n\n/**\n * For the given element, returns the `color-scheme` of that element.\n */\nexport function getColorScheme(element?: HTMLElement) {\n const style = styleOf(element);\n\n return style.getPropertyValue('color-scheme');\n}\n\nexport function setColorScheme(element: HTMLElement, value: string): void;\nexport function setColorScheme(value: string): void;\n\nexport function setColorScheme(...args: [string] | [HTMLElement, string]): void {\n if (typeof args[0] === 'string') {\n styleOf().setProperty('color-scheme', args[0]);\n\n return;\n }\n\n if (typeof args[1] === 'string') {\n styleOf(args[0]).setProperty('color-scheme', args[1]);\n\n return;\n }\n\n throw new Error(`Invalid arity, expected up to 2 args, received ${args.length}`);\n}\n\n/**\n * Removes the `color-scheme` from the given element\n */\nexport function removeColorScheme(element?: HTMLElement) {\n const style = styleOf(element);\n\n style.removeProperty('color-scheme');\n}\n\nfunction styleOf(element?: HTMLElement) {\n if (element) {\n return element.style;\n }\n\n return document.documentElement.style;\n}\n\nsync();\n\nwindow.addEventListener('storage', (e: StorageEvent) => {\n try {\n if (e.key !== LOCAL_PREF_KEY) return;\n\n // If the key was removed in another tab, fall back to system preference\n if (e.newValue === null) {\n if (prefers.dark()) {\n colorScheme.update('dark');\n\n return;\n } else if (prefers.light()) {\n colorScheme.update('light');\n\n return;\n }\n\n // default to light\n colorScheme.update('light');\n\n return;\n }\n\n const newScheme = e.newValue;\n\n colorScheme.update(newScheme);\n } catch {\n // swallow errors from storage event handling\n }\n});\n"],"names":["_colorScheme","cell","callbacks","Set","runCallbacks","theme","Promise","resolve","callback","values","colorScheme","update","value","current","waitForPromise","on","add","off","delete","localPreference","setColorScheme","isDark","isLight","sync","userPreference","read","prefers","dark","light","queries","window","matchMedia","none","addEventListener","e","isSet","mode","matches","custom","name","LOCAL_PREF_KEY","Boolean","localStorage","getItem","setItem","removeItem","getColorScheme","element","style","styleOf","getPropertyValue","args","setProperty","Error","length","removeColorScheme","removeProperty","document","documentElement","key","newValue","newScheme"],"mappings":"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"}
|
package/dist/components/menu.js
CHANGED
|
@@ -4,7 +4,7 @@ import { on } from '@ember/modifier';
|
|
|
4
4
|
import { guidFor } from '@ember/object/internals';
|
|
5
5
|
import { modifier } from 'ember-modifier';
|
|
6
6
|
import { cell } from 'ember-resources';
|
|
7
|
-
import { getTabsterAttribute, MoverDirections,
|
|
7
|
+
import { getTabsterAttribute, MoverDirections, setTabsterAttribute, getTabster } from 'tabster';
|
|
8
8
|
import { Link } from './link.js';
|
|
9
9
|
import { Popover } from './popover.js';
|
|
10
10
|
import { precompileTemplate } from '@ember/template-compilation';
|
|
@@ -60,12 +60,18 @@ const installContent = modifier((element, _, {
|
|
|
60
60
|
isOpen,
|
|
61
61
|
triggerElement
|
|
62
62
|
}) => {
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
// Focus first focusable element when the popover opens.
|
|
64
|
+
// The toggle event fires natively after showPopover() completes.
|
|
65
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/toggle_event
|
|
66
|
+
function onToggle(e) {
|
|
67
|
+
if (e.newState !== "open") return;
|
|
68
|
+
const tabster = getTabster(window);
|
|
69
|
+
const firstFocusable = tabster?.focusable.findFirst({
|
|
70
|
+
container: element
|
|
71
|
+
});
|
|
72
|
+
firstFocusable?.focus();
|
|
73
|
+
}
|
|
74
|
+
element.addEventListener("toggle", onToggle);
|
|
69
75
|
// listen for "outside" clicks
|
|
70
76
|
function onDocumentClick(e) {
|
|
71
77
|
if (isOpen.current && e.target && !element.contains(e.target) && !triggerElement.current?.contains(e.target)) {
|
|
@@ -81,6 +87,7 @@ const installContent = modifier((element, _, {
|
|
|
81
87
|
document.addEventListener("click", onDocumentClick);
|
|
82
88
|
document.addEventListener("keydown", onDocumentKeydown);
|
|
83
89
|
return () => {
|
|
90
|
+
element.removeEventListener("toggle", onToggle);
|
|
84
91
|
document.removeEventListener("click", onDocumentClick);
|
|
85
92
|
document.removeEventListener("keydown", onDocumentKeydown);
|
|
86
93
|
};
|
|
@@ -137,7 +144,7 @@ const TriggerElement = () => cell();
|
|
|
137
144
|
class Menu extends Component {
|
|
138
145
|
contentId = guidFor(this);
|
|
139
146
|
static {
|
|
140
|
-
setComponentTemplate(precompileTemplate("{{#let (IsOpen) (TriggerElement) as |isOpen triggerEl|}}\n <Popover @flipOptions={{@flipOptions}} @middleware={{@middleware}} @offsetOptions={{@offsetOptions}} @placement={{@placement}} @shiftOptions={{@shiftOptions}} @strategy={{@strategy}}
|
|
147
|
+
setComponentTemplate(precompileTemplate("{{#let (IsOpen) (TriggerElement) as |isOpen triggerEl|}}\n <Popover @flipOptions={{@flipOptions}} @middleware={{@middleware}} @offsetOptions={{@offsetOptions}} @placement={{@placement}} @shiftOptions={{@shiftOptions}} @strategy={{@strategy}} as |p|>\n {{#let (modifier trigger triggerElement=triggerEl isOpen=isOpen contentId=this.contentId setReference=p.setReference) as |triggerModifier|}}\n {{yield (hash trigger=triggerModifier Trigger=(component Trigger triggerModifier=triggerModifier) Content=(component Content PopoverContent=p.Content isOpen=isOpen triggerElement=triggerEl contentId=this.contentId) arrow=p.arrow isOpen=isOpen.current)}}\n {{/let}}\n </Popover>\n{{/let}}", {
|
|
141
148
|
strictMode: true,
|
|
142
149
|
scope: () => ({
|
|
143
150
|
IsOpen,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu.js","sources":["../../src/components/menu.gts"],"sourcesContent":["import Component from \"@glimmer/component\";\nimport { hash } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\nimport { guidFor } from \"@ember/object/internals\";\n\nimport { modifier as eModifier } from \"ember-modifier\";\nimport { cell } from \"ember-resources\";\nimport { getTabster, getTabsterAttribute, MoverDirections, setTabsterAttribute } from \"tabster\";\n\nimport { Link, type Signature as LinkSignature } from \"./link.gts\";\nimport { Popover, type Signature as PopoverSignature } from \"./popover.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { WithBoundArgs } from \"@glint/template\";\n\ntype Cell<V> = ReturnType<typeof cell<V>>;\ntype LinkArgs = LinkSignature[\"Args\"];\ntype PopoverArgs = PopoverSignature[\"Args\"];\ntype PopoverBlockParams = PopoverSignature[\"Blocks\"][\"default\"][0];\n\nconst TABSTER_CONFIG_CONTENT = getTabsterAttribute(\n {\n mover: {\n direction: MoverDirections.Both,\n cyclic: true,\n },\n deloser: {},\n },\n true,\n);\n\nconst TABSTER_CONFIG_TRIGGER = {\n deloser: {},\n};\n\nexport interface Signature {\n Args: PopoverArgs;\n Blocks: {\n default: [\n {\n arrow: PopoverBlockParams[\"arrow\"];\n trigger: WithBoundArgs<\n typeof trigger,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"setReference\"\n >;\n Trigger: WithBoundArgs<typeof Trigger, \"triggerModifier\">;\n Content: WithBoundArgs<\n typeof Content,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"PopoverContent\"\n >;\n isOpen: boolean;\n },\n ];\n };\n}\n\nexport interface SeparatorSignature {\n Element: HTMLDivElement;\n Blocks: { default: [] };\n}\n\nconst Separator: TOC<SeparatorSignature> = <template>\n <div role=\"separator\" ...attributes>\n {{yield}}\n </div>\n</template>;\n\n/**\n * We focus items on `pointerMove` to achieve the following:\n *\n * - Mouse over an item (it focuses)\n * - Leave mouse where it is and use keyboard to focus a different item\n * - Wiggle mouse without it leaving previously focused item\n * - Previously focused item should re-focus\n *\n * If we used `mouseOver`/`mouseEnter` it would not re-focus when the mouse\n * wiggles. This is to match native menu implementation.\n */\nfunction focusOnHover(e: PointerEvent) {\n const item = e.currentTarget;\n\n if (item instanceof HTMLElement) {\n item?.focus();\n }\n}\n\ninterface PrivateItemSignature {\n Element: HTMLButtonElement;\n Args: { onSelect?: (event: Event) => void; toggle: () => void };\n Blocks: { default: [] };\n}\n\nexport interface ItemSignature {\n Element: PrivateItemSignature[\"Element\"];\n Args: Omit<PrivateItemSignature[\"Args\"], \"toggle\">;\n Blocks: PrivateItemSignature[\"Blocks\"];\n}\n\nconst Item: TOC<PrivateItemSignature> = <template>\n {{! @glint-expect-error }}\n {{#let (if @onSelect (modifier on \"click\" @onSelect)) as |maybeClick|}}\n <button\n type=\"button\"\n role=\"menuitem\"\n {{! @glint-expect-error }}\n {{maybeClick}}\n {{on \"click\" @toggle}}\n {{on \"pointermove\" focusOnHover}}\n ...attributes\n >\n {{yield}}\n </button>\n {{/let}}\n</template>;\n\ninterface LinkItemArgs extends LinkArgs {\n toggle: () => void;\n}\n\ninterface PrivateLinkItemSignature {\n Element: HTMLAnchorElement;\n Args: LinkItemArgs;\n Blocks: { default: [] };\n}\n\nexport interface LinkItemSignature {\n Element: PrivateLinkItemSignature[\"Element\"];\n Args: LinkArgs;\n Blocks: PrivateLinkItemSignature[\"Blocks\"];\n}\n\nconst LinkItem: TOC<PrivateLinkItemSignature> = <template>\n <Link\n role=\"menuitem\"\n @href={{@href}}\n @includeActiveQueryParams={{@includeActiveQueryParams}}\n @activeOnSubPaths={{@activeOnSubPaths}}\n {{on \"click\" @toggle}}\n {{on \"pointermove\" focusOnHover}}\n ...attributes\n >\n {{yield}}\n </Link>\n</template>;\n\nconst installContent = eModifier<{\n Element: HTMLElement;\n Args: {\n Named: {\n isOpen: Cell<boolean>;\n triggerElement: Cell<HTMLElement>;\n };\n };\n}>((element, _: [], { isOpen, triggerElement }) => {\n // focus first focusable element on the content\n const tabster = getTabster(window);\n const firstFocusable = tabster?.focusable.findFirst({\n container: element,\n });\n\n firstFocusable?.focus();\n\n // listen for \"outside\" clicks\n function onDocumentClick(e: MouseEvent) {\n if (\n isOpen.current &&\n e.target &&\n !element.contains(e.target as HTMLElement) &&\n !triggerElement.current?.contains(e.target as HTMLElement)\n ) {\n isOpen.current = false;\n }\n }\n\n // listen for the escape key\n function onDocumentKeydown(e: KeyboardEvent) {\n if (isOpen.current && e.key === \"Escape\") {\n isOpen.current = false;\n }\n }\n\n document.addEventListener(\"click\", onDocumentClick);\n document.addEventListener(\"keydown\", onDocumentKeydown);\n\n return () => {\n document.removeEventListener(\"click\", onDocumentClick);\n document.removeEventListener(\"keydown\", onDocumentKeydown);\n };\n});\n\ninterface PrivateContentSignature {\n Element: HTMLDivElement;\n Args: {\n triggerElement: Cell<HTMLElement>;\n contentId: string;\n isOpen: Cell<boolean>;\n PopoverContent: PopoverBlockParams[\"Content\"];\n };\n Blocks: {\n default: [\n {\n Item: WithBoundArgs<typeof Item, \"toggle\">;\n LinkItem: WithBoundArgs<typeof LinkItem, \"toggle\">;\n Separator: typeof Separator;\n },\n ];\n };\n}\n\nexport interface ContentSignature {\n Element: PrivateContentSignature[\"Element\"];\n Blocks: PrivateContentSignature[\"Blocks\"];\n}\n\nconst Content: TOC<PrivateContentSignature> = <template>\n {{#if @isOpen.current}}\n <@PopoverContent\n id={{@contentId}}\n role=\"menu\"\n data-tabster={{TABSTER_CONFIG_CONTENT}}\n tabindex=\"0\"\n {{installContent isOpen=@isOpen triggerElement=@triggerElement}}\n ...attributes\n >\n {{yield\n (hash\n Item=(component Item toggle=@isOpen.toggle)\n LinkItem=(component LinkItem toggle=@isOpen.toggle)\n Separator=Separator\n )\n }}\n </@PopoverContent>\n {{/if}}\n</template>;\n\ninterface PrivateTriggerModifierSignature {\n Element: HTMLElement;\n Args: {\n Named: {\n triggerElement: Cell<HTMLElement>;\n isOpen: Cell<boolean>;\n contentId: string;\n setReference: PopoverBlockParams[\"setReference\"];\n stopPropagation?: boolean;\n preventDefault?: boolean;\n };\n };\n}\n\nexport interface TriggerModifierSignature {\n Element: PrivateTriggerModifierSignature[\"Element\"];\n}\n\nconst trigger = eModifier<PrivateTriggerModifierSignature>(\n (\n element,\n _: [],\n { triggerElement, isOpen, contentId, setReference, stopPropagation, preventDefault },\n ) => {\n element.setAttribute(\"aria-haspopup\", \"menu\");\n\n if (isOpen.current) {\n element.setAttribute(\"aria-controls\", contentId);\n element.setAttribute(\"aria-expanded\", \"true\");\n } else {\n element.removeAttribute(\"aria-controls\");\n element.setAttribute(\"aria-expanded\", \"false\");\n }\n\n setTabsterAttribute(element, TABSTER_CONFIG_TRIGGER);\n\n const onTriggerClick = (event: MouseEvent) => {\n if (stopPropagation) {\n event.stopPropagation();\n }\n\n if (preventDefault) {\n event.preventDefault();\n }\n\n isOpen.toggle();\n };\n\n element.addEventListener(\"click\", onTriggerClick);\n\n triggerElement.current = element;\n\n setReference(element);\n\n return () => {\n element.removeEventListener(\"click\", onTriggerClick);\n };\n },\n);\n\ninterface PrivateTriggerSignature {\n Element: HTMLButtonElement;\n Args: {\n triggerModifier: WithBoundArgs<\n typeof trigger,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"setReference\"\n >;\n stopPropagation?: boolean;\n preventDefault?: boolean;\n };\n Blocks: { default: [] };\n}\n\nexport interface TriggerSignature {\n Element: PrivateTriggerSignature[\"Element\"];\n Blocks: PrivateTriggerSignature[\"Blocks\"];\n}\n\nconst Trigger: TOC<PrivateTriggerSignature> = <template>\n <button\n type=\"button\"\n {{@triggerModifier stopPropagation=@stopPropagation preventDefault=@preventDefault}}\n ...attributes\n >\n {{yield}}\n </button>\n</template>;\n\nconst IsOpen = () => cell<boolean>(false);\nconst TriggerElement = () => cell<HTMLElement>();\n\nexport class Menu extends Component<Signature> {\n contentId = guidFor(this);\n\n <template>\n {{#let (IsOpen) (TriggerElement) as |isOpen triggerEl|}}\n <Popover\n @flipOptions={{@flipOptions}}\n @middleware={{@middleware}}\n @offsetOptions={{@offsetOptions}}\n @placement={{@placement}}\n @shiftOptions={{@shiftOptions}}\n @strategy={{@strategy}}\n @inline={{@inline}}\n as |p|\n >\n {{#let\n (modifier\n trigger\n triggerElement=triggerEl\n isOpen=isOpen\n contentId=this.contentId\n setReference=p.setReference\n )\n as |triggerModifier|\n }}\n {{yield\n (hash\n trigger=triggerModifier\n Trigger=(component Trigger triggerModifier=triggerModifier)\n Content=(component\n Content\n PopoverContent=p.Content\n isOpen=isOpen\n triggerElement=triggerEl\n contentId=this.contentId\n )\n arrow=p.arrow\n isOpen=isOpen.current\n )\n }}\n {{/let}}\n </Popover>\n {{/let}}\n </template>\n}\n\nexport default Menu;\n"],"names":["TABSTER_CONFIG_CONTENT","getTabsterAttribute","mover","direction","MoverDirections","Both","cyclic","deloser","TABSTER_CONFIG_TRIGGER","Separator","setComponentTemplate","precompileTemplate","strictMode","templateOnly","focusOnHover","e","item","currentTarget","HTMLElement","focus","Item","scope","on","LinkItem","Link","installContent","eModifier","element","_","isOpen","triggerElement","tabster","getTabster","window","firstFocusable","focusable","findFirst","container","onDocumentClick","current","target","contains","onDocumentKeydown","key","document","addEventListener","removeEventListener","Content","hash","trigger","contentId","setReference","stopPropagation","preventDefault","setAttribute","removeAttribute","setTabsterAttribute","onTriggerClick","event","toggle","Trigger","IsOpen","cell","TriggerElement","Menu","Component","guidFor","Popover"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"menu.js","sources":["../../src/components/menu.gts"],"sourcesContent":["import Component from \"@glimmer/component\";\nimport { hash } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\nimport { guidFor } from \"@ember/object/internals\";\n\nimport { modifier as eModifier } from \"ember-modifier\";\nimport { cell } from \"ember-resources\";\nimport { getTabster, getTabsterAttribute, MoverDirections, setTabsterAttribute } from \"tabster\";\n\nimport { Link, type Signature as LinkSignature } from \"./link.gts\";\nimport { Popover, type Signature as PopoverSignature } from \"./popover.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { WithBoundArgs } from \"@glint/template\";\n\ntype Cell<V> = ReturnType<typeof cell<V>>;\ntype LinkArgs = LinkSignature[\"Args\"];\ntype PopoverArgs = PopoverSignature[\"Args\"];\ntype PopoverBlockParams = PopoverSignature[\"Blocks\"][\"default\"][0];\n\nconst TABSTER_CONFIG_CONTENT = getTabsterAttribute(\n {\n mover: {\n direction: MoverDirections.Both,\n cyclic: true,\n },\n deloser: {},\n },\n true,\n);\n\nconst TABSTER_CONFIG_TRIGGER = {\n deloser: {},\n};\n\nexport interface Signature {\n Args: PopoverArgs;\n Blocks: {\n default: [\n {\n arrow: PopoverBlockParams[\"arrow\"];\n trigger: WithBoundArgs<\n typeof trigger,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"setReference\"\n >;\n Trigger: WithBoundArgs<typeof Trigger, \"triggerModifier\">;\n Content: WithBoundArgs<\n typeof Content,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"PopoverContent\"\n >;\n isOpen: boolean;\n },\n ];\n };\n}\n\nexport interface SeparatorSignature {\n Element: HTMLDivElement;\n Blocks: { default: [] };\n}\n\nconst Separator: TOC<SeparatorSignature> = <template>\n <div role=\"separator\" ...attributes>\n {{yield}}\n </div>\n</template>;\n\n/**\n * We focus items on `pointerMove` to achieve the following:\n *\n * - Mouse over an item (it focuses)\n * - Leave mouse where it is and use keyboard to focus a different item\n * - Wiggle mouse without it leaving previously focused item\n * - Previously focused item should re-focus\n *\n * If we used `mouseOver`/`mouseEnter` it would not re-focus when the mouse\n * wiggles. This is to match native menu implementation.\n */\nfunction focusOnHover(e: PointerEvent) {\n const item = e.currentTarget;\n\n if (item instanceof HTMLElement) {\n item?.focus();\n }\n}\n\ninterface PrivateItemSignature {\n Element: HTMLButtonElement;\n Args: { onSelect?: (event: Event) => void; toggle: () => void };\n Blocks: { default: [] };\n}\n\nexport interface ItemSignature {\n Element: PrivateItemSignature[\"Element\"];\n Args: Omit<PrivateItemSignature[\"Args\"], \"toggle\">;\n Blocks: PrivateItemSignature[\"Blocks\"];\n}\n\nconst Item: TOC<PrivateItemSignature> = <template>\n {{! @glint-expect-error }}\n {{#let (if @onSelect (modifier on \"click\" @onSelect)) as |maybeClick|}}\n <button\n type=\"button\"\n role=\"menuitem\"\n {{! @glint-expect-error }}\n {{maybeClick}}\n {{on \"click\" @toggle}}\n {{on \"pointermove\" focusOnHover}}\n ...attributes\n >\n {{yield}}\n </button>\n {{/let}}\n</template>;\n\ninterface LinkItemArgs extends LinkArgs {\n toggle: () => void;\n}\n\ninterface PrivateLinkItemSignature {\n Element: HTMLAnchorElement;\n Args: LinkItemArgs;\n Blocks: { default: [] };\n}\n\nexport interface LinkItemSignature {\n Element: PrivateLinkItemSignature[\"Element\"];\n Args: LinkArgs;\n Blocks: PrivateLinkItemSignature[\"Blocks\"];\n}\n\nconst LinkItem: TOC<PrivateLinkItemSignature> = <template>\n <Link\n role=\"menuitem\"\n @href={{@href}}\n @includeActiveQueryParams={{@includeActiveQueryParams}}\n @activeOnSubPaths={{@activeOnSubPaths}}\n {{on \"click\" @toggle}}\n {{on \"pointermove\" focusOnHover}}\n ...attributes\n >\n {{yield}}\n </Link>\n</template>;\n\nconst installContent = eModifier<{\n Element: HTMLElement;\n Args: {\n Named: {\n isOpen: Cell<boolean>;\n triggerElement: Cell<HTMLElement>;\n };\n };\n}>((element, _: [], { isOpen, triggerElement }) => {\n // Focus first focusable element when the popover opens.\n // The toggle event fires natively after showPopover() completes.\n // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/toggle_event\n function onToggle(e: ToggleEvent) {\n if (e.newState !== \"open\") return;\n\n const tabster = getTabster(window);\n const firstFocusable = tabster?.focusable.findFirst({\n container: element,\n });\n\n firstFocusable?.focus();\n }\n\n element.addEventListener(\"toggle\", onToggle as EventListener);\n\n // listen for \"outside\" clicks\n function onDocumentClick(e: MouseEvent) {\n if (\n isOpen.current &&\n e.target &&\n !element.contains(e.target as HTMLElement) &&\n !triggerElement.current?.contains(e.target as HTMLElement)\n ) {\n isOpen.current = false;\n }\n }\n\n // listen for the escape key\n function onDocumentKeydown(e: KeyboardEvent) {\n if (isOpen.current && e.key === \"Escape\") {\n isOpen.current = false;\n }\n }\n\n document.addEventListener(\"click\", onDocumentClick);\n document.addEventListener(\"keydown\", onDocumentKeydown);\n\n return () => {\n element.removeEventListener(\"toggle\", onToggle as EventListener);\n document.removeEventListener(\"click\", onDocumentClick);\n document.removeEventListener(\"keydown\", onDocumentKeydown);\n };\n});\n\ninterface PrivateContentSignature {\n Element: HTMLDivElement;\n Args: {\n triggerElement: Cell<HTMLElement>;\n contentId: string;\n isOpen: Cell<boolean>;\n PopoverContent: PopoverBlockParams[\"Content\"];\n };\n Blocks: {\n default: [\n {\n Item: WithBoundArgs<typeof Item, \"toggle\">;\n LinkItem: WithBoundArgs<typeof LinkItem, \"toggle\">;\n Separator: typeof Separator;\n },\n ];\n };\n}\n\nexport interface ContentSignature {\n Element: PrivateContentSignature[\"Element\"];\n Blocks: PrivateContentSignature[\"Blocks\"];\n}\n\nconst Content: TOC<PrivateContentSignature> = <template>\n {{#if @isOpen.current}}\n <@PopoverContent\n id={{@contentId}}\n role=\"menu\"\n data-tabster={{TABSTER_CONFIG_CONTENT}}\n tabindex=\"0\"\n {{installContent isOpen=@isOpen triggerElement=@triggerElement}}\n ...attributes\n >\n {{yield\n (hash\n Item=(component Item toggle=@isOpen.toggle)\n LinkItem=(component LinkItem toggle=@isOpen.toggle)\n Separator=Separator\n )\n }}\n </@PopoverContent>\n {{/if}}\n</template>;\n\ninterface PrivateTriggerModifierSignature {\n Element: HTMLElement;\n Args: {\n Named: {\n triggerElement: Cell<HTMLElement>;\n isOpen: Cell<boolean>;\n contentId: string;\n setReference: PopoverBlockParams[\"setReference\"];\n stopPropagation?: boolean;\n preventDefault?: boolean;\n };\n };\n}\n\nexport interface TriggerModifierSignature {\n Element: PrivateTriggerModifierSignature[\"Element\"];\n}\n\nconst trigger = eModifier<PrivateTriggerModifierSignature>(\n (\n element,\n _: [],\n { triggerElement, isOpen, contentId, setReference, stopPropagation, preventDefault },\n ) => {\n element.setAttribute(\"aria-haspopup\", \"menu\");\n\n if (isOpen.current) {\n element.setAttribute(\"aria-controls\", contentId);\n element.setAttribute(\"aria-expanded\", \"true\");\n } else {\n element.removeAttribute(\"aria-controls\");\n element.setAttribute(\"aria-expanded\", \"false\");\n }\n\n setTabsterAttribute(element, TABSTER_CONFIG_TRIGGER);\n\n const onTriggerClick = (event: MouseEvent) => {\n if (stopPropagation) {\n event.stopPropagation();\n }\n\n if (preventDefault) {\n event.preventDefault();\n }\n\n isOpen.toggle();\n };\n\n element.addEventListener(\"click\", onTriggerClick);\n\n triggerElement.current = element;\n\n setReference(element);\n\n return () => {\n element.removeEventListener(\"click\", onTriggerClick);\n };\n },\n);\n\ninterface PrivateTriggerSignature {\n Element: HTMLButtonElement;\n Args: {\n triggerModifier: WithBoundArgs<\n typeof trigger,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"setReference\"\n >;\n stopPropagation?: boolean;\n preventDefault?: boolean;\n };\n Blocks: { default: [] };\n}\n\nexport interface TriggerSignature {\n Element: PrivateTriggerSignature[\"Element\"];\n Blocks: PrivateTriggerSignature[\"Blocks\"];\n}\n\nconst Trigger: TOC<PrivateTriggerSignature> = <template>\n <button\n type=\"button\"\n {{@triggerModifier stopPropagation=@stopPropagation preventDefault=@preventDefault}}\n ...attributes\n >\n {{yield}}\n </button>\n</template>;\n\nconst IsOpen = () => cell<boolean>(false);\nconst TriggerElement = () => cell<HTMLElement>();\n\nexport class Menu extends Component<Signature> {\n contentId = guidFor(this);\n\n <template>\n {{#let (IsOpen) (TriggerElement) as |isOpen triggerEl|}}\n <Popover\n @flipOptions={{@flipOptions}}\n @middleware={{@middleware}}\n @offsetOptions={{@offsetOptions}}\n @placement={{@placement}}\n @shiftOptions={{@shiftOptions}}\n @strategy={{@strategy}}\n as |p|\n >\n {{#let\n (modifier\n trigger\n triggerElement=triggerEl\n isOpen=isOpen\n contentId=this.contentId\n setReference=p.setReference\n )\n as |triggerModifier|\n }}\n {{yield\n (hash\n trigger=triggerModifier\n Trigger=(component Trigger triggerModifier=triggerModifier)\n Content=(component\n Content\n PopoverContent=p.Content\n isOpen=isOpen\n triggerElement=triggerEl\n contentId=this.contentId\n )\n arrow=p.arrow\n isOpen=isOpen.current\n )\n }}\n {{/let}}\n </Popover>\n {{/let}}\n </template>\n}\n\nexport default Menu;\n"],"names":["TABSTER_CONFIG_CONTENT","getTabsterAttribute","mover","direction","MoverDirections","Both","cyclic","deloser","TABSTER_CONFIG_TRIGGER","Separator","setComponentTemplate","precompileTemplate","strictMode","templateOnly","focusOnHover","e","item","currentTarget","HTMLElement","focus","Item","scope","on","LinkItem","Link","installContent","eModifier","element","_","isOpen","triggerElement","onToggle","newState","tabster","getTabster","window","firstFocusable","focusable","findFirst","container","addEventListener","onDocumentClick","current","target","contains","onDocumentKeydown","key","document","removeEventListener","Content","hash","trigger","contentId","setReference","stopPropagation","preventDefault","setAttribute","removeAttribute","setTabsterAttribute","onTriggerClick","event","toggle","Trigger","IsOpen","cell","TriggerElement","Menu","Component","guidFor","Popover"],"mappings":"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"}
|
|
@@ -4,26 +4,49 @@ import { element } from 'ember-element-helper';
|
|
|
4
4
|
import { modifier } from 'ember-modifier';
|
|
5
5
|
import { cell } from 'ember-resources';
|
|
6
6
|
import { F as FloatingUI } from '../component-BXy_iafw.js';
|
|
7
|
-
import { Portal } from './portal.js';
|
|
8
|
-
import { TARGETS } from './portal-targets.js';
|
|
9
7
|
import { precompileTemplate } from '@ember/template-compilation';
|
|
10
8
|
import { setComponentTemplate } from '@ember/component';
|
|
11
9
|
import templateOnly from '@ember/component/template-only';
|
|
12
10
|
|
|
11
|
+
const showPopover = modifier(element => {
|
|
12
|
+
const el = element;
|
|
13
|
+
// Reset [popover] UA overflow default that clips arrows positioned outside
|
|
14
|
+
el.style.setProperty("overflow", "visible");
|
|
15
|
+
// Don't promote to top layer if already inside a popover — the parent
|
|
16
|
+
// popover already handles layering. Adding both to the top layer causes
|
|
17
|
+
// stacking issues where the parent renders on top of the child.
|
|
18
|
+
if (el.parentElement?.closest("[popover]")) {
|
|
19
|
+
el.removeAttribute("popover");
|
|
20
|
+
// <dialog> elements are hidden by default — ensure they're visible
|
|
21
|
+
// when opting out of the top layer.
|
|
22
|
+
if (el instanceof HTMLDialogElement) {
|
|
23
|
+
el.setAttribute("open", "");
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
el.showPopover();
|
|
27
|
+
}
|
|
28
|
+
return () => {
|
|
29
|
+
try {
|
|
30
|
+
el.hidePopover();
|
|
31
|
+
} catch {
|
|
32
|
+
/* already hidden */}
|
|
33
|
+
};
|
|
34
|
+
});
|
|
13
35
|
function getElementTag(tagName) {
|
|
14
36
|
return tagName || "div";
|
|
15
37
|
}
|
|
16
38
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
39
|
+
* Content uses `popover="manual"` + `showPopover()` to promote
|
|
40
|
+
* the element to the browser's top layer. This escapes all ancestor
|
|
41
|
+
* overflow clipping and stacking contexts — the same guarantee that
|
|
42
|
+
* portalling provided, but using the browser's native mechanism.
|
|
19
43
|
*/
|
|
20
|
-
const Content = setComponentTemplate(precompileTemplate("{{#let (element (getElementTag @as)) as |El|}}\n {{
|
|
44
|
+
const Content = setComponentTemplate(precompileTemplate("{{#let (element (getElementTag @as)) as |El|}}\n {{!-- @glint-ignore\n https://github.com/tildeio/ember-element-helper/issues/91\n https://github.com/typed-ember/glint/issues/610\n --}}\n <El popover=\"manual\" {{showPopover}} {{@floating}} ...attributes>\n {{yield}}\n </El>\n{{/let}}", {
|
|
21
45
|
strictMode: true,
|
|
22
46
|
scope: () => ({
|
|
23
47
|
element,
|
|
24
48
|
getElementTag,
|
|
25
|
-
|
|
26
|
-
TARGETS
|
|
49
|
+
showPopover
|
|
27
50
|
})
|
|
28
51
|
}), templateOnly());
|
|
29
52
|
const arrowSides = {
|
|
@@ -80,7 +103,7 @@ function flipOptions(options) {
|
|
|
80
103
|
...options
|
|
81
104
|
};
|
|
82
105
|
}
|
|
83
|
-
const Popover = setComponentTemplate(precompileTemplate("{{#let (ArrowElement) as |arrowElement|}}\n <FloatingUI @placement={{@placement}} @strategy={{@strategy}} @middleware={{maybeAddArrow @middleware arrowElement.current}} @flipOptions={{flipOptions @flipOptions}} @shiftOptions={{@shiftOptions}} @offsetOptions={{@offsetOptions}} as |reference floating extra|>\n {{#let (modifier attachArrow arrowElement=arrowElement data=extra.data) as |arrow|}}\n {{yield (hash reference=reference setReference=extra.setReference Content=(component Content floating=floating
|
|
106
|
+
const Popover = setComponentTemplate(precompileTemplate("{{#let (ArrowElement) as |arrowElement|}}\n <FloatingUI @placement={{@placement}} @strategy={{@strategy}} @middleware={{maybeAddArrow @middleware arrowElement.current}} @flipOptions={{flipOptions @flipOptions}} @shiftOptions={{@shiftOptions}} @offsetOptions={{@offsetOptions}} as |reference floating extra|>\n {{#let (modifier attachArrow arrowElement=arrowElement data=extra.data) as |arrow|}}\n {{yield (hash reference=reference setReference=extra.setReference Content=(component Content floating=floating) data=extra.data arrow=arrow)}}\n {{/let}}\n </FloatingUI>\n{{/let}}", {
|
|
84
107
|
strictMode: true,
|
|
85
108
|
scope: () => ({
|
|
86
109
|
ArrowElement,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover.js","sources":["../../src/components/popover.gts"],"sourcesContent":["import { hash } from \"@ember/helper\";\n\nimport { arrow } from \"@floating-ui/dom\";\nimport { element } from \"ember-element-helper\";\nimport { modifier as eModifier } from \"ember-modifier\";\nimport { cell } from \"ember-resources\";\n\nimport { FloatingUI } from \"../floating-ui.ts\";\nimport { Portal } from \"./portal.gts\";\nimport { TARGETS } from \"./portal-targets.gts\";\n\nimport type { Signature as FloatingUiComponentSignature } from \"../floating-ui/component.ts\";\nimport type { Signature as HookSignature } from \"../floating-ui/modifier.ts\";\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { ElementContext, Middleware } from \"@floating-ui/dom\";\nimport type { ModifierLike, WithBoundArgs } from \"@glint/template\";\n\nexport interface Signature {\n Args: {\n /**\n * See the Floating UI's [flip docs](https://floating-ui.com/docs/flip) for possible values.\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n flipOptions?: HookSignature[\"Args\"][\"Named\"][\"flipOptions\"];\n /**\n * Array of one or more objects to add to Floating UI's list of [middleware](https://floating-ui.com/docs/middleware)\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n middleware?: HookSignature[\"Args\"][\"Named\"][\"middleware\"];\n /**\n * See the Floating UI's [offset docs](https://floating-ui.com/docs/offset) for possible values.\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n offsetOptions?: HookSignature[\"Args\"][\"Named\"][\"offsetOptions\"];\n /**\n * One of the possible [`placements`](https://floating-ui.com/docs/computeposition#placement). The default is 'bottom'.\n *\n * Possible values are\n * - top\n * - bottom\n * - right\n * - left\n *\n * And may optionally have `-start` or `-end` added to adjust position along the side.\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n placement?: `${\"top\" | \"bottom\" | \"left\" | \"right\"}${\"\" | \"-start\" | \"-end\"}`;\n /**\n * See the Floating UI's [shift docs](https://floating-ui.com/docs/shift) for possible values.\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n shiftOptions?: HookSignature[\"Args\"][\"Named\"][\"shiftOptions\"];\n /**\n * CSS position property, either `fixed` or `absolute`.\n *\n * Pros and cons of each strategy are explained on [Floating UI's Docs](https://floating-ui.com/docs/computePosition#strategy)\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n strategy?: HookSignature[\"Args\"][\"Named\"][\"strategy\"];\n\n /**\n * By default, the popover is portaled.\n * If you don't control your CSS, and the positioning of the popover content\n * is misbehaving, you may pass \"@inline={{true}}\" to opt out of portalling.\n *\n * Inline may also be useful in nested menus, where you know exactly how the nesting occurs\n */\n inline?: boolean;\n };\n Blocks: {\n default: [\n {\n reference: FloatingUiComponentSignature[\"Blocks\"][\"default\"][0];\n setReference: FloatingUiComponentSignature[\"Blocks\"][\"default\"][2][\"setReference\"];\n Content: WithBoundArgs<typeof Content, \"floating\">;\n data: FloatingUiComponentSignature[\"Blocks\"][\"default\"][2][\"data\"];\n arrow: ModifierLike<{ Element: HTMLElement }>;\n },\n ];\n };\n}\n\nfunction getElementTag(tagName: undefined | string) {\n return tagName || \"div\";\n}\n\n/**\n * Allows lazy evaluation of the portal target (do nothing until rendered)\n * This is useful because the algorithm for finding the portal target isn't cheap.\n */\nconst Content: TOC<{\n Element: HTMLDivElement;\n Args: {\n floating: ModifierLike<{ Element: HTMLElement }>;\n inline?: boolean;\n /**\n * By default the popover content is wrapped in a div.\n * You may change this by supplying the name of an element here.\n *\n * For example:\n * ```gjs\n * <Popover as |p|>\n * <p.Content @as=\"dialog\">\n * this is now focus trapped\n * </p.Content>\n * </Popover>\n * ```\n */\n as?: string;\n };\n Blocks: { default: [] };\n}> = <template>\n {{#let (element (getElementTag @as)) as |El|}}\n {{#if @inline}}\n {{! @glint-ignore\n https://github.com/tildeio/ember-element-helper/issues/91\n https://github.com/typed-ember/glint/issues/610\n }}\n <El {{@floating}} ...attributes>\n {{yield}}\n </El>\n {{else}}\n <Portal @to={{TARGETS.popover}}>\n {{! @glint-ignore\n https://github.com/tildeio/ember-element-helper/issues/91\n https://github.com/typed-ember/glint/issues/610\n }}\n <El {{@floating}} ...attributes>\n {{yield}}\n </El>\n </Portal>\n {{/if}}\n {{/let}}\n</template>;\n\ninterface AttachArrowSignature {\n Element: HTMLElement;\n Args: {\n Named: {\n arrowElement: ReturnType<typeof ArrowElement>;\n data:\n | undefined\n | {\n placement: string;\n middlewareData?: {\n arrow?: { x?: number; y?: number };\n };\n };\n };\n };\n}\n\nconst arrowSides = {\n top: \"bottom\",\n right: \"left\",\n bottom: \"top\",\n left: \"right\",\n};\n\ntype Direction = \"top\" | \"bottom\" | \"left\" | \"right\";\ntype Placement = `${Direction}${\"\" | \"-start\" | \"-end\"}`;\n\nconst attachArrow: ModifierLike<AttachArrowSignature> = eModifier<AttachArrowSignature>(\n (element, _: [], named) => {\n if (element === named.arrowElement.current) {\n if (!named.data) return;\n if (!named.data.middlewareData) return;\n\n const { arrow } = named.data.middlewareData;\n const { placement } = named.data;\n\n if (!arrow) return;\n if (!placement) return;\n\n const { x: arrowX, y: arrowY } = arrow;\n const otherSide = (placement as Placement).split(\"-\")[0] as Direction;\n const staticSide = arrowSides[otherSide];\n\n Object.assign(named.arrowElement.current.style, {\n left: arrowX != null ? `${arrowX}px` : \"\",\n top: arrowY != null ? `${arrowY}px` : \"\",\n right: \"\",\n bottom: \"\",\n [staticSide]: \"-4px\",\n });\n\n return;\n }\n\n void (async () => {\n await Promise.resolve();\n named.arrowElement.set(element);\n })();\n },\n);\n\nconst ArrowElement: () => ReturnType<typeof cell<HTMLElement>> = () => cell<HTMLElement>();\n\nfunction maybeAddArrow(middleware: Middleware[] | undefined, element: Element | undefined) {\n const result = [...(middleware || [])];\n\n if (element) {\n result.push(arrow({ element }));\n }\n\n return result;\n}\n\nfunction flipOptions(options: HookSignature[\"Args\"][\"Named\"][\"flipOptions\"]) {\n return {\n elementContext: \"reference\" as ElementContext,\n ...options,\n };\n}\n\nexport const Popover: TOC<Signature> = <template>\n {{#let (ArrowElement) as |arrowElement|}}\n <FloatingUI\n @placement={{@placement}}\n @strategy={{@strategy}}\n @middleware={{maybeAddArrow @middleware arrowElement.current}}\n @flipOptions={{flipOptions @flipOptions}}\n @shiftOptions={{@shiftOptions}}\n @offsetOptions={{@offsetOptions}}\n as |reference floating extra|\n >\n {{#let (modifier attachArrow arrowElement=arrowElement data=extra.data) as |arrow|}}\n {{yield\n (hash\n reference=reference\n setReference=extra.setReference\n Content=(component Content floating=floating inline=@inline)\n data=extra.data\n arrow=arrow\n )\n }}\n {{/let}}\n </FloatingUI>\n {{/let}}\n</template>;\n\nexport default Popover;\n"],"names":["getElementTag","tagName","Content","setComponentTemplate","precompileTemplate","strictMode","scope","element","Portal","TARGETS","templateOnly","arrowSides","top","right","bottom","left","attachArrow","eModifier","_","named","arrowElement","current","data","middlewareData","arrow","placement","x","arrowX","y","arrowY","otherSide","split","staticSide","Object","assign","style","Promise","resolve","set","ArrowElement","cell","maybeAddArrow","middleware","result","push","flipOptions","options","elementContext","Popover","FloatingUI","hash"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"popover.js","sources":["../../src/components/popover.gts"],"sourcesContent":["import { hash } from \"@ember/helper\";\n\nimport { arrow } from \"@floating-ui/dom\";\nimport { element } from \"ember-element-helper\";\nimport { modifier as eModifier } from \"ember-modifier\";\nimport { cell } from \"ember-resources\";\n\nimport { FloatingUI } from \"../floating-ui.ts\";\n\nimport type { Signature as FloatingUiComponentSignature } from \"../floating-ui/component.ts\";\nimport type { Signature as HookSignature } from \"../floating-ui/modifier.ts\";\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { ElementContext, Middleware } from \"@floating-ui/dom\";\nimport type { ModifierLike, WithBoundArgs } from \"@glint/template\";\n\nexport interface Signature {\n Args: {\n /**\n * See the Floating UI's [flip docs](https://floating-ui.com/docs/flip) for possible values.\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n flipOptions?: HookSignature[\"Args\"][\"Named\"][\"flipOptions\"];\n /**\n * Array of one or more objects to add to Floating UI's list of [middleware](https://floating-ui.com/docs/middleware)\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n middleware?: HookSignature[\"Args\"][\"Named\"][\"middleware\"];\n /**\n * See the Floating UI's [offset docs](https://floating-ui.com/docs/offset) for possible values.\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n offsetOptions?: HookSignature[\"Args\"][\"Named\"][\"offsetOptions\"];\n /**\n * One of the possible [`placements`](https://floating-ui.com/docs/computeposition#placement). The default is 'bottom'.\n *\n * Possible values are\n * - top\n * - bottom\n * - right\n * - left\n *\n * And may optionally have `-start` or `-end` added to adjust position along the side.\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n placement?: `${\"top\" | \"bottom\" | \"left\" | \"right\"}${\"\" | \"-start\" | \"-end\"}`;\n /**\n * See the Floating UI's [shift docs](https://floating-ui.com/docs/shift) for possible values.\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n shiftOptions?: HookSignature[\"Args\"][\"Named\"][\"shiftOptions\"];\n /**\n * CSS position property, either `fixed` or `absolute`.\n *\n * Pros and cons of each strategy are explained on [Floating UI's Docs](https://floating-ui.com/docs/computePosition#strategy)\n *\n * This argument is forwarded to the `<FloatingUI>` component.\n */\n strategy?: HookSignature[\"Args\"][\"Named\"][\"strategy\"];\n };\n Blocks: {\n default: [\n {\n reference: FloatingUiComponentSignature[\"Blocks\"][\"default\"][0];\n setReference: FloatingUiComponentSignature[\"Blocks\"][\"default\"][2][\"setReference\"];\n Content: WithBoundArgs<typeof Content, \"floating\">;\n data: FloatingUiComponentSignature[\"Blocks\"][\"default\"][2][\"data\"];\n arrow: ModifierLike<{ Element: HTMLElement }>;\n },\n ];\n };\n}\n\nconst showPopover = eModifier<{ Element: Element }>((element) => {\n const el = element as HTMLElement;\n\n // Reset [popover] UA overflow default that clips arrows positioned outside\n el.style.setProperty(\"overflow\", \"visible\");\n\n // Don't promote to top layer if already inside a popover — the parent\n // popover already handles layering. Adding both to the top layer causes\n // stacking issues where the parent renders on top of the child.\n if (el.parentElement?.closest(\"[popover]\")) {\n el.removeAttribute(\"popover\");\n\n // <dialog> elements are hidden by default — ensure they're visible\n // when opting out of the top layer.\n if (el instanceof HTMLDialogElement) {\n el.setAttribute(\"open\", \"\");\n }\n } else {\n el.showPopover();\n }\n\n return () => {\n try {\n el.hidePopover();\n } catch {\n /* already hidden */\n }\n };\n});\n\nfunction getElementTag(tagName: undefined | string) {\n return tagName || \"div\";\n}\n\n/**\n * Content uses `popover=\"manual\"` + `showPopover()` to promote\n * the element to the browser's top layer. This escapes all ancestor\n * overflow clipping and stacking contexts — the same guarantee that\n * portalling provided, but using the browser's native mechanism.\n */\nconst Content: TOC<{\n Element: HTMLDivElement;\n Args: {\n floating: ModifierLike<{ Element: HTMLElement }>;\n /**\n * By default the popover content is wrapped in a div.\n * You may change this by supplying the name of an element here.\n *\n * For example:\n * ```gjs\n * <Popover as |p|>\n * <p.Content @as=\"dialog\">\n * this is now focus trapped\n * </p.Content>\n * </Popover>\n * ```\n */\n as?: string;\n };\n Blocks: { default: [] };\n}> = <template>\n {{#let (element (getElementTag @as)) as |El|}}\n {{! @glint-ignore\n https://github.com/tildeio/ember-element-helper/issues/91\n https://github.com/typed-ember/glint/issues/610\n }}\n <El popover=\"manual\" {{showPopover}} {{@floating}} ...attributes>\n {{yield}}\n </El>\n {{/let}}\n</template>;\n\ninterface AttachArrowSignature {\n Element: HTMLElement;\n Args: {\n Named: {\n arrowElement: ReturnType<typeof ArrowElement>;\n data:\n | undefined\n | {\n placement: string;\n middlewareData?: {\n arrow?: { x?: number; y?: number };\n };\n };\n };\n };\n}\n\nconst arrowSides = {\n top: \"bottom\",\n right: \"left\",\n bottom: \"top\",\n left: \"right\",\n};\n\ntype Direction = \"top\" | \"bottom\" | \"left\" | \"right\";\ntype Placement = `${Direction}${\"\" | \"-start\" | \"-end\"}`;\n\nconst attachArrow: ModifierLike<AttachArrowSignature> = eModifier<AttachArrowSignature>(\n (element, _: [], named) => {\n if (element === named.arrowElement.current) {\n if (!named.data) return;\n if (!named.data.middlewareData) return;\n\n const { arrow } = named.data.middlewareData;\n const { placement } = named.data;\n\n if (!arrow) return;\n if (!placement) return;\n\n const { x: arrowX, y: arrowY } = arrow;\n const otherSide = (placement as Placement).split(\"-\")[0] as Direction;\n const staticSide = arrowSides[otherSide];\n\n Object.assign(named.arrowElement.current.style, {\n left: arrowX != null ? `${arrowX}px` : \"\",\n top: arrowY != null ? `${arrowY}px` : \"\",\n right: \"\",\n bottom: \"\",\n [staticSide]: \"-4px\",\n });\n\n return;\n }\n\n void (async () => {\n await Promise.resolve();\n named.arrowElement.set(element);\n })();\n },\n);\n\nconst ArrowElement: () => ReturnType<typeof cell<HTMLElement>> = () => cell<HTMLElement>();\n\nfunction maybeAddArrow(middleware: Middleware[] | undefined, element: Element | undefined) {\n const result = [...(middleware || [])];\n\n if (element) {\n result.push(arrow({ element }));\n }\n\n return result;\n}\n\nfunction flipOptions(options: HookSignature[\"Args\"][\"Named\"][\"flipOptions\"]) {\n return {\n elementContext: \"reference\" as ElementContext,\n ...options,\n };\n}\n\nexport const Popover: TOC<Signature> = <template>\n {{#let (ArrowElement) as |arrowElement|}}\n <FloatingUI\n @placement={{@placement}}\n @strategy={{@strategy}}\n @middleware={{maybeAddArrow @middleware arrowElement.current}}\n @flipOptions={{flipOptions @flipOptions}}\n @shiftOptions={{@shiftOptions}}\n @offsetOptions={{@offsetOptions}}\n as |reference floating extra|\n >\n {{#let (modifier attachArrow arrowElement=arrowElement data=extra.data) as |arrow|}}\n {{yield\n (hash\n reference=reference\n setReference=extra.setReference\n Content=(component Content floating=floating)\n data=extra.data\n arrow=arrow\n )\n }}\n {{/let}}\n </FloatingUI>\n {{/let}}\n</template>;\n\nexport default Popover;\n"],"names":["showPopover","eModifier","element","el","style","setProperty","parentElement","closest","removeAttribute","HTMLDialogElement","setAttribute","hidePopover","getElementTag","tagName","Content","setComponentTemplate","precompileTemplate","strictMode","scope","templateOnly","arrowSides","top","right","bottom","left","attachArrow","_","named","arrowElement","current","data","middlewareData","arrow","placement","x","arrowX","y","arrowY","otherSide","split","staticSide","Object","assign","Promise","resolve","set","ArrowElement","cell","maybeAddArrow","middleware","result","push","flipOptions","options","elementContext","Popover","FloatingUI","hash"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.js","sources":["../../src/components/tabs.gts"],"sourcesContent":["/**\n * References:\n * - https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/tablist_role\n * - https://www.w3.org/WAI/ARIA/apg/patterns/tabs/\n *\n *\n * Keyboard behaviors (optionally) provided by tabster\n */\n\nimport Component from \"@glimmer/component\";\nimport { tracked } from \"@glimmer/tracking\";\nimport { isDestroyed, isDestroying } from \"@ember/destroyable\";\nimport { fn } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\nimport { next } from \"@ember/runloop\";\n\nimport { getTabsterAttribute, MoverDirections } from \"tabster\";\n\nimport { uniqueId } from \"../utils.ts\";\nimport Portal from \"./portal.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type Owner from \"@ember/owner\";\nimport type { ComponentLike, WithBoundArgs } from \"@glint/template\";\n\nconst UNSET = Symbol.for(\"ember-primitives:tabs:unset\");\n\nconst TABSTER_CONFIG = getTabsterAttribute(\n {\n mover: {\n direction: MoverDirections.Both,\n cyclic: true,\n memorizeCurrent: true,\n },\n deloser: {},\n },\n true,\n);\n\nconst TabLink: TOC<{\n Element: HTMLAnchorElement;\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n panelId: string;\n };\n Blocks: { default: [] };\n}> = <template>\n <a href=\"##missing##\" ...attributes role=\"tab\" aria-controls={{@panelId}} id={{@id}}>\n {{yield}}\n </a>\n</template>;\n\nexport type ButtonType = ComponentLike<ButtonSignature>;\nexport interface ButtonSignature {\n Element: HTMLButtonElement;\n Blocks: {\n default: [];\n };\n}\n\nconst TabButton: TOC<{\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n panelId: string;\n\n /**\n * @internal\n * for managing state\n */\n handleClick: () => void;\n\n /**\n * @internal\n * for managing state\n */\n value: string | undefined;\n\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: {\n default: [];\n };\n}> = <template>\n <button\n ...attributes\n role=\"tab\"\n type=\"button\"\n aria-controls={{@panelId}}\n aria-selected={{String (@state.isActive @id @value)}}\n id={{@id}}\n {{on \"click\" @handleClick}}\n {{! The Types for modifier are wrong }}\n {{! @glint-expect-error}}\n {{(if @state.isAutomatic (modifier on \"focus\" @handleClick))}}\n >\n {{yield}}\n </button>\n</template>;\n\nexport type ContentType = ComponentLike<ContentSignature>;\nexport interface ContentSignature {\n /**\n * the [role=tabpanel] element\n */\n Element: HTMLDivElement;\n Blocks: {\n default: [];\n };\n}\n\nconst TabContent: TOC<{\n Element: HTMLDivElement;\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n tabId: string;\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: {\n default: [];\n };\n}> = <template>\n <Portal @to=\"#{{@state.tabpanelId}}\" @append={{true}}>\n {{#if (@state.isActive @tabId)}}\n <div ...attributes role=\"tabpanel\" aria-labelledby={{@tabId}} id={{@id}}>\n {{yield}}\n </div>\n {{/if}}\n </Portal>\n</template>;\n\nfunction isString(x: unknown): x is string {\n return typeof x === \"string\";\n}\n\nfunction makeTab(tabButton: any, tabLink: any): any {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n tabButton.Link = tabLink;\n\n return tabButton;\n}\n\nexport type ContainerType = ComponentLike<ContainerSignature>;\nexport type ContainerSignature =\n | {\n Blocks: {\n default: [];\n };\n }\n | {\n Args: {\n label: string | ComponentLike;\n content: string | ComponentLike;\n };\n }\n | {\n Args: {\n label: string | ComponentLike;\n };\n Blocks: {\n /**\n * The content for the tab\n */\n default: [];\n };\n };\n\nclass TabContainer extends Component<{\n Args: {\n /**\n * @internal\n */\n state: TabState;\n\n /**\n * When opting for a \"controlled component\",\n * the value will be needed to make sense of the selected tab.\n *\n * The default value used for communication within the Tabs component (and eventually emitted via the @onChange argument) is a unique random id.\n * So while that could still be used for controlling the tabs component, it may be more easy to grok with user-managed values.\n */\n value?: string;\n\n /**\n * optional user-passable label\n */\n label?: string | ComponentLike;\n\n /**\n * optional user-passable content.\n */\n content?: string | ComponentLike;\n };\n Blocks: {\n default: [\n Label: WithBoundArgs<typeof TabButton, \"state\" | \"id\" | \"panelId\" | \"handleClick\" | \"value\">,\n Content: WithBoundArgs<typeof TabContent, \"state\" | \"id\" | \"tabId\">,\n ];\n };\n}> {\n id = `ember-primitives__tab-${uniqueId()}`;\n\n get tabId() {\n return `${this.id}__tab`;\n }\n\n get panelId() {\n return `${this.id}__panel`;\n }\n\n get label() {\n return this.args.label ?? this.tabId;\n }\n\n <template>\n {{#if @label}}\n <TabButton\n @state={{@state}}\n @id={{this.tabId}}\n @value={{@value}}\n @panelId={{this.panelId}}\n @handleClick={{fn @state.handleChange this.tabId @value}}\n >\n {{#if (isString @label)}}\n {{@label}}\n {{else}}\n <@label />\n {{/if}}\n </TabButton>\n\n <TabContent @state={{@state}} @id={{this.panelId}} @tabId={{this.tabId}}>\n {{#if @content}}\n {{#if (isString @content)}}\n {{@content}}\n {{else}}\n <@content />\n {{/if}}\n {{else}}\n {{yield}}\n {{/if}}\n </TabContent>\n {{else}}\n {{yield\n (makeTab\n (component\n TabButton\n state=@state\n value=@value\n id=this.tabId\n panelId=this.panelId\n handleClick=(fn @state.handleChange this.tabId @value)\n )\n (component TabLink state=@state id=this.tabId panelId=this.panelId)\n )\n (component TabContent state=@state id=this.panelId tabId=this.tabId)\n }}\n {{/if}}\n </template>\n}\n\nconst Label: TOC<{\n /**\n * The label wiring (id, aria, etc) are handled for you.\n * If you'd like to use a heading element (h3, etc), place that in the block content\n * when invoking this Label component.\n */\n Element: null;\n Args: {\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: { default: [] };\n}> = <template>\n <Portal @to=\"#{{@state.labelId}}\">\n {{yield}}\n </Portal>\n</template>;\n\nexport interface Signature {\n /**\n * The wrapping element for the overall Tabs component.\n * This should be used for styling the layout of the tabs.\n */\n Element: HTMLDivElement;\n Args: {\n /**\n * Sets the active tab.\n * If not passed, the first tab will be selected\n */\n activeTab?: string;\n\n /**\n * Optional label for the overall TabList\n */\n label?: string | ComponentLike;\n\n /**\n * When the tab changes, this function will be called.\n * The function receives both the newly selected tab as well as the previous tab.\n *\n * However, if the tabs are not configured with names, these values will be null.\n */\n onChange?: (selectedTab: string, previousTab: string | null) => void;\n\n /**\n * When activationMode is set to \"automatic\", tabs are activated when receiving focus. When set to \"manual\", tabs are activated when clicked (or when \"enter\" is pressed via the keyboard).\n */\n activationMode?: \"automatic\" | \"manual\";\n };\n Blocks: {\n default: [\n Tab: WithBoundArgs<typeof TabContainer, \"state\"> & {\n Label: WithBoundArgs<typeof Label, \"state\">;\n },\n ];\n };\n}\n\n/**\n * We're doing old skool hax with this, so we don't need to care about what the types think, really\n */\nfunction makeAPI(tabContainer: any, labelComponent: any): any {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n tabContainer.Label = labelComponent;\n\n return tabContainer;\n}\n\nimport { buildWaiter } from \"@ember/test-waiters\";\n\nconst stateWaiter = buildWaiter(\"ember-primitives:tabs\");\n\n/**\n * State bucket passed around to all the sub-components.\n *\n * Sort of a \"Context\", but with a bit of prop-drilling (which is more efficient than dom-context)\n */\nclass TabState {\n declare args: {\n activeTab?: string;\n activationMode?: \"automatic\" | \"manual\";\n onChange?: (selected: string, previous: string | null) => void;\n };\n\n @tracked _active: string | null = null;\n\n @tracked _label: string | undefined;\n\n #first: string | null = null;\n id: string;\n labelId: string;\n tabpanelId: string;\n #token: unknown;\n\n constructor(args: { activeTab?: string; onChange?: () => void }) {\n this.args = args;\n\n this.id = `ember-primitives-${uniqueId()}`;\n this.labelId = `${this.id}__label`;\n this.tabpanelId = `${this.id}__tabpanel`;\n }\n\n get activationMode() {\n return this.args.activationMode ?? \"automatic\";\n }\n\n get isAutomatic() {\n return this.activationMode === \"automatic\";\n }\n\n /**\n * This function relies on the fact that during rendering,\n * the first component to be rendered will be first,\n * and it will be the one to set the secret first value,\n * which means all other tabs will not be first.\n *\n */\n isActive = (tabId: string, tabValue: undefined | string) => {\n /**\n * When users pass the @value to a tab, we use that for managing\n * the \"active state\" instead of the DOM ID.\n *\n * NOTE: DOM IDs must be unique across the whole document, but @value\n * does not need to be unqiue.\n * `@value` *should* be unique for the Tabs component though\n */\n const isSelected = (x: string) => {\n if (tabValue) return x === tabValue;\n\n return x === tabId;\n };\n\n if (this.active === UNSET) {\n if (this.#first) return isSelected(this.#first);\n\n this.#first = tabValue ?? tabId;\n this.#token = stateWaiter.beginAsync();\n\n // eslint-disable-next-line ember/no-runloop\n next(() => {\n if (!this.#token) return;\n stateWaiter.endAsync(this.#token);\n if (this._active) return;\n if (isDestroyed(this) || isDestroying(this)) return;\n\n this._label = tabValue ?? tabId;\n });\n\n return true;\n }\n\n return isSelected(this.active);\n };\n\n get active() {\n return this._active ?? this.args.activeTab ?? UNSET;\n }\n\n get activeLabel() {\n /**\n * This is only needed during the first set\n * because we prioritize rendering first, and then updating metadata later\n * (next render)\n *\n * NOTE: this does not mean that the a11y tree is updated later.\n * it is correct on initial render\n */\n if (this._label) {\n return this._label;\n }\n\n if (this.active === UNSET) {\n return \"Pending\";\n }\n\n return this.active;\n }\n\n handleChange = (tabId: string, tabValue: string | undefined) => {\n const previous = this.active;\n const next = tabValue ?? tabId;\n\n // No change, no need to be noisy\n if (next === previous) return;\n\n this._active = this._label = next;\n\n this.args.onChange?.(next, previous === UNSET ? null : previous);\n };\n}\n\nexport class Tabs extends Component<Signature> {\n state: TabState;\n\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n constructor(owner: Owner, args: {}) {\n super(owner, args);\n\n this.state = new TabState(args);\n }\n\n <template>\n <div class=\"ember-primitives__tabs\" ...attributes data-active={{this.state.activeLabel}}>\n {{! This element will be portaled in to and replaced if tabs.Label is invoked }}\n <div class=\"ember-primitives__tabs__label\" id={{this.state.labelId}}>\n {{#if (isString @label)}}\n {{@label}}\n {{else}}\n <@label />\n {{/if}}\n </div>\n <div\n class=\"ember-primitives__tabs__tablist\"\n role=\"tablist\"\n aria-labelledby={{this.state.labelId}}\n data-tabster={{TABSTER_CONFIG}}\n >\n {{yield\n (makeAPI (component TabContainer state=this.state) (component Label state=this.state))\n }}\n </div>\n {{!\n Tab's contents are portaled in to this element\n }}\n <div class=\"ember-primitives__tabs__tabpanel\" id={{this.state.tabpanelId}}></div>\n </div>\n </template>\n}\n"],"names":["UNSET","Symbol","for","TABSTER_CONFIG","getTabsterAttribute","mover","direction","MoverDirections","Both","cyclic","memorizeCurrent","deloser","TabLink","setComponentTemplate","precompileTemplate","strictMode","templateOnly","TabButton","scope","String","on","TabContent","Portal","isString","x","makeTab","tabButton","tabLink","Link","TabContainer","Component","id","uniqueId","tabId","panelId","label","args","fn","Label","makeAPI","tabContainer","labelComponent","stateWaiter","buildWaiter","TabState","g","prototype","tracked","i","labelId","tabpanelId","constructor","activationMode","isAutomatic","isActive","tabValue","isSelected","active","beginAsync","next","endAsync","_active","isDestroyed","isDestroying","_label","activeTab","activeLabel","handleChange","previous","onChange","Tabs","state","owner"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tabs.js","sources":["../../src/components/tabs.gts"],"sourcesContent":["/**\n * References:\n * - https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/tablist_role\n * - https://www.w3.org/WAI/ARIA/apg/patterns/tabs/\n *\n *\n * Keyboard behaviors (optionally) provided by tabster\n */\n\nimport Component from \"@glimmer/component\";\nimport { tracked } from \"@glimmer/tracking\";\nimport { isDestroyed, isDestroying } from \"@ember/destroyable\";\nimport { fn } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\nimport { next } from \"@ember/runloop\";\n\nimport { getTabsterAttribute, MoverDirections } from \"tabster\";\n\nimport { uniqueId } from \"../utils.ts\";\nimport Portal from \"./portal.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type Owner from \"@ember/owner\";\nimport type { ComponentLike, WithBoundArgs } from \"@glint/template\";\n\nconst UNSET = Symbol.for(\"ember-primitives:tabs:unset\");\n\nconst TABSTER_CONFIG = getTabsterAttribute(\n {\n mover: {\n direction: MoverDirections.Both,\n cyclic: true,\n memorizeCurrent: true,\n },\n deloser: {},\n },\n true,\n);\n\nconst TabLink: TOC<{\n Element: HTMLAnchorElement;\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n panelId: string;\n };\n Blocks: { default: [] };\n}> = <template>\n <a href=\"##missing##\" ...attributes role=\"tab\" aria-controls={{@panelId}} id={{@id}}>\n {{yield}}\n </a>\n</template>;\n\nexport type ButtonType = ComponentLike<ButtonSignature>;\nexport interface ButtonSignature {\n Element: HTMLButtonElement;\n Blocks: {\n default: [];\n };\n}\n\nconst TabButton: TOC<{\n Element: HTMLButtonElement;\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n panelId: string;\n\n /**\n * @internal\n * for managing state\n */\n handleClick: () => void;\n\n /**\n * @internal\n * for managing state\n */\n value: string | undefined;\n\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: {\n default: [];\n };\n}> = <template>\n <button\n ...attributes\n role=\"tab\"\n type=\"button\"\n aria-controls={{@panelId}}\n aria-selected={{String (@state.isActive @id @value)}}\n id={{@id}}\n {{on \"click\" @handleClick}}\n {{! The Types for modifier are wrong }}\n {{! @glint-expect-error}}\n {{(if @state.isAutomatic (modifier on \"focus\" @handleClick))}}\n >\n {{yield}}\n </button>\n</template>;\n\nexport type ContentType = ComponentLike<ContentSignature>;\nexport interface ContentSignature {\n /**\n * the [role=tabpanel] element\n */\n Element: HTMLDivElement;\n Blocks: {\n default: [];\n };\n}\n\nconst TabContent: TOC<{\n Element: HTMLDivElement;\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n tabId: string;\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: {\n default: [];\n };\n}> = <template>\n <Portal @to=\"#{{@state.tabpanelId}}\" @append={{true}}>\n {{#if (@state.isActive @tabId)}}\n <div ...attributes role=\"tabpanel\" aria-labelledby={{@tabId}} id={{@id}}>\n {{yield}}\n </div>\n {{/if}}\n </Portal>\n</template>;\n\nfunction isString(x: unknown): x is string {\n return typeof x === \"string\";\n}\n\nfunction makeTab(tabButton: any, tabLink: any): any {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n tabButton.Link = tabLink;\n\n return tabButton;\n}\n\nexport type ContainerType = ComponentLike<ContainerSignature>;\nexport type ContainerSignature =\n | {\n Blocks: {\n default: [];\n };\n }\n | {\n Args: {\n label: string | ComponentLike;\n content: string | ComponentLike;\n };\n }\n | {\n Args: {\n label: string | ComponentLike;\n };\n Blocks: {\n /**\n * The content for the tab\n */\n default: [];\n };\n };\n\nclass TabContainer extends Component<{\n Args: {\n /**\n * @internal\n */\n state: TabState;\n\n /**\n * When opting for a \"controlled component\",\n * the value will be needed to make sense of the selected tab.\n *\n * The default value used for communication within the Tabs component (and eventually emitted via the @onChange argument) is a unique random id.\n * So while that could still be used for controlling the tabs component, it may be more easy to grok with user-managed values.\n */\n value?: string;\n\n /**\n * optional user-passable label\n */\n label?: string | ComponentLike;\n\n /**\n * optional user-passable content.\n */\n content?: string | ComponentLike;\n };\n Blocks: {\n default: [\n Label: WithBoundArgs<typeof TabButton, \"state\" | \"id\" | \"panelId\" | \"handleClick\" | \"value\">,\n Content: WithBoundArgs<typeof TabContent, \"state\" | \"id\" | \"tabId\">,\n ];\n };\n}> {\n id = `ember-primitives__tab-${uniqueId()}`;\n\n get tabId() {\n return `${this.id}__tab`;\n }\n\n get panelId() {\n return `${this.id}__panel`;\n }\n\n get label() {\n return this.args.label ?? this.tabId;\n }\n\n <template>\n {{#if @label}}\n <TabButton\n @state={{@state}}\n @id={{this.tabId}}\n @value={{@value}}\n @panelId={{this.panelId}}\n @handleClick={{fn @state.handleChange this.tabId @value}}\n >\n {{#if (isString @label)}}\n {{@label}}\n {{else}}\n <@label />\n {{/if}}\n </TabButton>\n\n <TabContent @state={{@state}} @id={{this.panelId}} @tabId={{this.tabId}}>\n {{#if @content}}\n {{#if (isString @content)}}\n {{@content}}\n {{else}}\n <@content />\n {{/if}}\n {{else}}\n {{yield}}\n {{/if}}\n </TabContent>\n {{else}}\n {{yield\n (makeTab\n (component\n TabButton\n state=@state\n value=@value\n id=this.tabId\n panelId=this.panelId\n handleClick=(fn @state.handleChange this.tabId @value)\n )\n (component TabLink state=@state id=this.tabId panelId=this.panelId)\n )\n (component TabContent state=@state id=this.panelId tabId=this.tabId)\n }}\n {{/if}}\n </template>\n}\n\nconst Label: TOC<{\n /**\n * The label wiring (id, aria, etc) are handled for you.\n * If you'd like to use a heading element (h3, etc), place that in the block content\n * when invoking this Label component.\n */\n Element: null;\n Args: {\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: { default: [] };\n}> = <template>\n <Portal @to=\"#{{@state.labelId}}\">\n {{yield}}\n </Portal>\n</template>;\n\nexport interface Signature {\n /**\n * The wrapping element for the overall Tabs component.\n * This should be used for styling the layout of the tabs.\n */\n Element: HTMLDivElement;\n Args: {\n /**\n * Sets the active tab.\n * If not passed, the first tab will be selected\n */\n activeTab?: string;\n\n /**\n * Optional label for the overall TabList\n */\n label?: string | ComponentLike;\n\n /**\n * When the tab changes, this function will be called.\n * The function receives both the newly selected tab as well as the previous tab.\n *\n * However, if the tabs are not configured with names, these values will be null.\n */\n onChange?: (selectedTab: string, previousTab: string | null) => void;\n\n /**\n * When activationMode is set to \"automatic\", tabs are activated when receiving focus. When set to \"manual\", tabs are activated when clicked (or when \"enter\" is pressed via the keyboard).\n */\n activationMode?: \"automatic\" | \"manual\";\n };\n Blocks: {\n default: [\n Tab: WithBoundArgs<typeof TabContainer, \"state\"> & {\n Label: WithBoundArgs<typeof Label, \"state\">;\n },\n ];\n };\n}\n\n/**\n * We're doing old skool hax with this, so we don't need to care about what the types think, really\n */\nfunction makeAPI(tabContainer: any, labelComponent: any): any {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n tabContainer.Label = labelComponent;\n\n return tabContainer;\n}\n\nimport { buildWaiter } from \"@ember/test-waiters\";\n\nconst stateWaiter = buildWaiter(\"ember-primitives:tabs\");\n\n/**\n * State bucket passed around to all the sub-components.\n *\n * Sort of a \"Context\", but with a bit of prop-drilling (which is more efficient than dom-context)\n */\nclass TabState {\n declare args: {\n activeTab?: string;\n activationMode?: \"automatic\" | \"manual\";\n onChange?: (selected: string, previous: string | null) => void;\n };\n\n @tracked _active: string | null = null;\n\n @tracked _label: string | undefined;\n\n #first: string | null = null;\n id: string;\n labelId: string;\n tabpanelId: string;\n #token: unknown;\n\n constructor(args: { activeTab?: string; onChange?: () => void }) {\n this.args = args;\n\n this.id = `ember-primitives-${uniqueId()}`;\n this.labelId = `${this.id}__label`;\n this.tabpanelId = `${this.id}__tabpanel`;\n }\n\n get activationMode() {\n return this.args.activationMode ?? \"automatic\";\n }\n\n get isAutomatic() {\n return this.activationMode === \"automatic\";\n }\n\n /**\n * This function relies on the fact that during rendering,\n * the first component to be rendered will be first,\n * and it will be the one to set the secret first value,\n * which means all other tabs will not be first.\n *\n */\n isActive = (tabId: string, tabValue: undefined | string) => {\n /**\n * When users pass the @value to a tab, we use that for managing\n * the \"active state\" instead of the DOM ID.\n *\n * NOTE: DOM IDs must be unique across the whole document, but @value\n * does not need to be unqiue.\n * `@value` *should* be unique for the Tabs component though\n */\n const isSelected = (x: string) => {\n if (tabValue) return x === tabValue;\n\n return x === tabId;\n };\n\n if (this.active === UNSET) {\n if (this.#first) return isSelected(this.#first);\n\n this.#first = tabValue ?? tabId;\n this.#token = stateWaiter.beginAsync();\n\n // eslint-disable-next-line ember/no-runloop\n next(() => {\n if (!this.#token) return;\n stateWaiter.endAsync(this.#token);\n if (this._active) return;\n if (isDestroyed(this) || isDestroying(this)) return;\n\n this._label = tabValue ?? tabId;\n });\n\n return true;\n }\n\n return isSelected(this.active);\n };\n\n get active() {\n return this._active ?? this.args.activeTab ?? UNSET;\n }\n\n get activeLabel() {\n /**\n * This is only needed during the first set\n * because we prioritize rendering first, and then updating metadata later\n * (next render)\n *\n * NOTE: this does not mean that the a11y tree is updated later.\n * it is correct on initial render\n */\n if (this._label) {\n return this._label;\n }\n\n if (this.active === UNSET) {\n return \"Pending\";\n }\n\n return this.active;\n }\n\n handleChange = (tabId: string, tabValue: string | undefined) => {\n const previous = this.active;\n const next = tabValue ?? tabId;\n\n // No change, no need to be noisy\n if (next === previous) return;\n\n this._active = this._label = next;\n\n this.args.onChange?.(next, previous === UNSET ? null : previous);\n };\n}\n\nexport class Tabs extends Component<Signature> {\n state: TabState;\n\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n constructor(owner: Owner, args: {}) {\n super(owner, args);\n\n this.state = new TabState(args);\n }\n\n <template>\n <div class=\"ember-primitives__tabs\" ...attributes data-active={{this.state.activeLabel}}>\n {{! This element will be portaled in to and replaced if tabs.Label is invoked }}\n <div class=\"ember-primitives__tabs__label\" id={{this.state.labelId}}>\n {{#if (isString @label)}}\n {{@label}}\n {{else}}\n <@label />\n {{/if}}\n </div>\n <div\n class=\"ember-primitives__tabs__tablist\"\n role=\"tablist\"\n aria-labelledby={{this.state.labelId}}\n data-tabster={{TABSTER_CONFIG}}\n >\n {{yield\n (makeAPI (component TabContainer state=this.state) (component Label state=this.state))\n }}\n </div>\n {{!\n Tab's contents are portaled in to this element\n }}\n <div class=\"ember-primitives__tabs__tabpanel\" id={{this.state.tabpanelId}}></div>\n </div>\n </template>\n}\n"],"names":["UNSET","Symbol","for","TABSTER_CONFIG","getTabsterAttribute","mover","direction","MoverDirections","Both","cyclic","memorizeCurrent","deloser","TabLink","setComponentTemplate","precompileTemplate","strictMode","templateOnly","TabButton","scope","String","on","TabContent","Portal","isString","x","makeTab","tabButton","tabLink","Link","TabContainer","Component","id","uniqueId","tabId","panelId","label","args","fn","Label","makeAPI","tabContainer","labelComponent","stateWaiter","buildWaiter","TabState","g","prototype","tracked","i","labelId","tabpanelId","constructor","activationMode","isAutomatic","isActive","tabValue","isSelected","active","beginAsync","next","endAsync","_active","isDestroyed","isDestroying","_label","activeTab","activeLabel","handleChange","previous","onChange","Tabs","state","owner"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ember-primitives",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.56.0",
|
|
4
4
|
"description": "Making apps easier to build",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ember-addon"
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@babel/runtime": "^7.28.6",
|
|
21
21
|
"@embroider/addon-shim": "^1.10.2",
|
|
22
|
-
"@embroider/macros": "^1.19.7",
|
|
23
22
|
"@floating-ui/dom": "^1.7.5",
|
|
24
23
|
"decorator-transforms": "2.3.1",
|
|
25
24
|
"ember-element-helper": "^0.8.8",
|
|
@@ -29,7 +28,7 @@
|
|
|
29
28
|
"tabster": "^8.7.0",
|
|
30
29
|
"tracked-built-ins": "^4.1.0",
|
|
31
30
|
"tracked-toolbox": "^2.2.0",
|
|
32
|
-
"which-heading-do-i-need": "0.2.
|
|
31
|
+
"which-heading-do-i-need": "0.2.7"
|
|
33
32
|
},
|
|
34
33
|
"devDependencies": {
|
|
35
34
|
"@arethetypeswrong/cli": "^0.18.0",
|
|
@@ -46,13 +45,14 @@
|
|
|
46
45
|
"@ember/test-helpers": "^5.4.1",
|
|
47
46
|
"@ember/test-waiters": "^4.1.0",
|
|
48
47
|
"@embroider/addon-dev": "^8.3.0",
|
|
48
|
+
"@embroider/macros": "^1.19.7",
|
|
49
49
|
"@glimmer/component": "^2.0.0",
|
|
50
50
|
"@glimmer/tracking": "^1.1.2",
|
|
51
51
|
"@glint/ember-tsc": "^1.1.1",
|
|
52
|
-
"@glint/template": "1.7.
|
|
52
|
+
"@glint/template": "1.7.7",
|
|
53
53
|
"@glint/tsserver-plugin": "^2.1.0",
|
|
54
54
|
"@nullvoxpopuli/eslint-configs": "^5.5.0",
|
|
55
|
-
"@rollup/plugin-babel": "^
|
|
55
|
+
"@rollup/plugin-babel": "^7.0.0",
|
|
56
56
|
"@tsconfig/ember": "^3.0.12",
|
|
57
57
|
"babel-plugin-ember-template-compilation": "^4.0.0",
|
|
58
58
|
"concurrently": "^9.2.1",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"publint": "^0.3.17",
|
|
69
69
|
"rollup": "^4.57.1",
|
|
70
70
|
"rollup-plugin-copy": "^3.5.0",
|
|
71
|
-
"typescript": "^
|
|
71
|
+
"typescript": "^6.0.2"
|
|
72
72
|
},
|
|
73
73
|
"publishConfig": {
|
|
74
74
|
"registry": "https://registry.npmjs.org"
|
package/src/color-scheme.ts
CHANGED
package/src/components/menu.gts
CHANGED
|
@@ -152,13 +152,21 @@ const installContent = eModifier<{
|
|
|
152
152
|
};
|
|
153
153
|
};
|
|
154
154
|
}>((element, _: [], { isOpen, triggerElement }) => {
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
// Focus first focusable element when the popover opens.
|
|
156
|
+
// The toggle event fires natively after showPopover() completes.
|
|
157
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/toggle_event
|
|
158
|
+
function onToggle(e: ToggleEvent) {
|
|
159
|
+
if (e.newState !== "open") return;
|
|
160
|
+
|
|
161
|
+
const tabster = getTabster(window);
|
|
162
|
+
const firstFocusable = tabster?.focusable.findFirst({
|
|
163
|
+
container: element,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
firstFocusable?.focus();
|
|
167
|
+
}
|
|
160
168
|
|
|
161
|
-
|
|
169
|
+
element.addEventListener("toggle", onToggle as EventListener);
|
|
162
170
|
|
|
163
171
|
// listen for "outside" clicks
|
|
164
172
|
function onDocumentClick(e: MouseEvent) {
|
|
@@ -183,6 +191,7 @@ const installContent = eModifier<{
|
|
|
183
191
|
document.addEventListener("keydown", onDocumentKeydown);
|
|
184
192
|
|
|
185
193
|
return () => {
|
|
194
|
+
element.removeEventListener("toggle", onToggle as EventListener);
|
|
186
195
|
document.removeEventListener("click", onDocumentClick);
|
|
187
196
|
document.removeEventListener("keydown", onDocumentKeydown);
|
|
188
197
|
};
|
|
@@ -336,7 +345,6 @@ export class Menu extends Component<Signature> {
|
|
|
336
345
|
@placement={{@placement}}
|
|
337
346
|
@shiftOptions={{@shiftOptions}}
|
|
338
347
|
@strategy={{@strategy}}
|
|
339
|
-
@inline={{@inline}}
|
|
340
348
|
as |p|
|
|
341
349
|
>
|
|
342
350
|
{{#let
|
|
@@ -6,8 +6,6 @@ import { modifier as eModifier } from "ember-modifier";
|
|
|
6
6
|
import { cell } from "ember-resources";
|
|
7
7
|
|
|
8
8
|
import { FloatingUI } from "../floating-ui.ts";
|
|
9
|
-
import { Portal } from "./portal.gts";
|
|
10
|
-
import { TARGETS } from "./portal-targets.gts";
|
|
11
9
|
|
|
12
10
|
import type { Signature as FloatingUiComponentSignature } from "../floating-ui/component.ts";
|
|
13
11
|
import type { Signature as HookSignature } from "../floating-ui/modifier.ts";
|
|
@@ -63,15 +61,6 @@ export interface Signature {
|
|
|
63
61
|
* This argument is forwarded to the `<FloatingUI>` component.
|
|
64
62
|
*/
|
|
65
63
|
strategy?: HookSignature["Args"]["Named"]["strategy"];
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* By default, the popover is portaled.
|
|
69
|
-
* If you don't control your CSS, and the positioning of the popover content
|
|
70
|
-
* is misbehaving, you may pass "@inline={{true}}" to opt out of portalling.
|
|
71
|
-
*
|
|
72
|
-
* Inline may also be useful in nested menus, where you know exactly how the nesting occurs
|
|
73
|
-
*/
|
|
74
|
-
inline?: boolean;
|
|
75
64
|
};
|
|
76
65
|
Blocks: {
|
|
77
66
|
default: [
|
|
@@ -86,19 +75,50 @@ export interface Signature {
|
|
|
86
75
|
};
|
|
87
76
|
}
|
|
88
77
|
|
|
78
|
+
const showPopover = eModifier<{ Element: Element }>((element) => {
|
|
79
|
+
const el = element as HTMLElement;
|
|
80
|
+
|
|
81
|
+
// Reset [popover] UA overflow default that clips arrows positioned outside
|
|
82
|
+
el.style.setProperty("overflow", "visible");
|
|
83
|
+
|
|
84
|
+
// Don't promote to top layer if already inside a popover — the parent
|
|
85
|
+
// popover already handles layering. Adding both to the top layer causes
|
|
86
|
+
// stacking issues where the parent renders on top of the child.
|
|
87
|
+
if (el.parentElement?.closest("[popover]")) {
|
|
88
|
+
el.removeAttribute("popover");
|
|
89
|
+
|
|
90
|
+
// <dialog> elements are hidden by default — ensure they're visible
|
|
91
|
+
// when opting out of the top layer.
|
|
92
|
+
if (el instanceof HTMLDialogElement) {
|
|
93
|
+
el.setAttribute("open", "");
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
el.showPopover();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return () => {
|
|
100
|
+
try {
|
|
101
|
+
el.hidePopover();
|
|
102
|
+
} catch {
|
|
103
|
+
/* already hidden */
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
|
|
89
108
|
function getElementTag(tagName: undefined | string) {
|
|
90
109
|
return tagName || "div";
|
|
91
110
|
}
|
|
92
111
|
|
|
93
112
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
113
|
+
* Content uses `popover="manual"` + `showPopover()` to promote
|
|
114
|
+
* the element to the browser's top layer. This escapes all ancestor
|
|
115
|
+
* overflow clipping and stacking contexts — the same guarantee that
|
|
116
|
+
* portalling provided, but using the browser's native mechanism.
|
|
96
117
|
*/
|
|
97
118
|
const Content: TOC<{
|
|
98
119
|
Element: HTMLDivElement;
|
|
99
120
|
Args: {
|
|
100
121
|
floating: ModifierLike<{ Element: HTMLElement }>;
|
|
101
|
-
inline?: boolean;
|
|
102
122
|
/**
|
|
103
123
|
* By default the popover content is wrapped in a div.
|
|
104
124
|
* You may change this by supplying the name of an element here.
|
|
@@ -117,25 +137,13 @@ const Content: TOC<{
|
|
|
117
137
|
Blocks: { default: [] };
|
|
118
138
|
}> = <template>
|
|
119
139
|
{{#let (element (getElementTag @as)) as |El|}}
|
|
120
|
-
{{
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
</El>
|
|
128
|
-
{{else}}
|
|
129
|
-
<Portal @to={{TARGETS.popover}}>
|
|
130
|
-
{{! @glint-ignore
|
|
131
|
-
https://github.com/tildeio/ember-element-helper/issues/91
|
|
132
|
-
https://github.com/typed-ember/glint/issues/610
|
|
133
|
-
}}
|
|
134
|
-
<El {{@floating}} ...attributes>
|
|
135
|
-
{{yield}}
|
|
136
|
-
</El>
|
|
137
|
-
</Portal>
|
|
138
|
-
{{/if}}
|
|
140
|
+
{{! @glint-ignore
|
|
141
|
+
https://github.com/tildeio/ember-element-helper/issues/91
|
|
142
|
+
https://github.com/typed-ember/glint/issues/610
|
|
143
|
+
}}
|
|
144
|
+
<El popover="manual" {{showPopover}} {{@floating}} ...attributes>
|
|
145
|
+
{{yield}}
|
|
146
|
+
</El>
|
|
139
147
|
{{/let}}
|
|
140
148
|
</template>;
|
|
141
149
|
|
|
@@ -235,7 +243,7 @@ export const Popover: TOC<Signature> = <template>
|
|
|
235
243
|
(hash
|
|
236
244
|
reference=reference
|
|
237
245
|
setReference=extra.setReference
|
|
238
|
-
Content=(component Content floating=floating
|
|
246
|
+
Content=(component Content floating=floating)
|
|
239
247
|
data=extra.data
|
|
240
248
|
arrow=arrow
|
|
241
249
|
)
|