@realmorg/ui 2.0.0-alpha.3 → 2.0.0-alpha.4
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 +6 -6
- package/components/accordion.html +22 -1
- package/components/button.html +35 -22
- package/components/combobox.html +13 -0
- package/components/dropdown-menu.html +26 -1
- package/components/hover-card.html +24 -1
- package/components/menubar.html +15 -1
- package/components/popover.html +22 -1
- package/components/tooltip.html +26 -1
- package/dist/ui.html +183 -28
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -5,10 +5,10 @@ About 60 accessible components built with [REALM](https://realm.js.org). Each on
|
|
|
5
5
|
Load REALM, the theme and the components from the CDN. There is no build step.
|
|
6
6
|
|
|
7
7
|
```html
|
|
8
|
-
<link rel="stylesheet" href="https://
|
|
9
|
-
<link rel="stylesheet" href="https://
|
|
10
|
-
<script type="module" src="https://
|
|
11
|
-
<import-element from="https://
|
|
8
|
+
<link rel="stylesheet" href="https://realm.js.org/dist/realm.css">
|
|
9
|
+
<link rel="stylesheet" href="https://realm.js.org/dist/ui/theme.css">
|
|
10
|
+
<script type="module" src="https://realm.js.org/dist/realm.js"></script>
|
|
11
|
+
<import-element from="https://realm.js.org/dist/ui/ui.html"></import-element>
|
|
12
12
|
|
|
13
13
|
<ui-card>
|
|
14
14
|
<ui-card-header>
|
|
@@ -28,8 +28,8 @@ Load REALM, the theme and the components from the CDN. There is no build step.
|
|
|
28
28
|
To load only what you use, import single files instead of `ui.html`:
|
|
29
29
|
|
|
30
30
|
```html
|
|
31
|
-
<import-element from="https://
|
|
32
|
-
<import-element from="https://
|
|
31
|
+
<import-element from="https://realm.js.org/dist/ui/components/button.html"></import-element>
|
|
32
|
+
<import-element from="https://realm.js.org/dist/ui/components/card.html"></import-element>
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
Each file imports its own dependencies (`sheet.html` loads `dialog.html`), and each file is fetched once.
|
|
@@ -89,11 +89,32 @@
|
|
|
89
89
|
width: calc(var(--spacing) * 4);
|
|
90
90
|
height: calc(var(--spacing) * 4);
|
|
91
91
|
color: var(--muted-foreground);
|
|
92
|
-
transition: rotate
|
|
92
|
+
transition: rotate var(--default-transition-duration) var(--default-transition-timing-function);
|
|
93
93
|
}
|
|
94
94
|
details[open] svg {
|
|
95
95
|
rotate: 180deg;
|
|
96
96
|
}
|
|
97
|
+
details::details-content {
|
|
98
|
+
display: grid;
|
|
99
|
+
grid-template-rows: 0fr;
|
|
100
|
+
transition:
|
|
101
|
+
grid-template-rows var(--default-transition-duration) var(--default-transition-timing-function),
|
|
102
|
+
content-visibility var(--default-transition-duration) allow-discrete;
|
|
103
|
+
}
|
|
104
|
+
details[open]::details-content {
|
|
105
|
+
grid-template-rows: 1fr;
|
|
106
|
+
}
|
|
107
|
+
slot:not([name]) {
|
|
108
|
+
display: block;
|
|
109
|
+
min-height: 0;
|
|
110
|
+
overflow: hidden;
|
|
111
|
+
}
|
|
112
|
+
@media (prefers-reduced-motion: reduce) {
|
|
113
|
+
svg,
|
|
114
|
+
details::details-content {
|
|
115
|
+
transition: none;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
97
118
|
</style>
|
|
98
119
|
|
|
99
120
|
<details _open="@open" ontoggle="toggled(this)">
|
package/components/button.html
CHANGED
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
popovertargetaction: prop.enum(["toggle", "show", "hide"]),
|
|
12
12
|
commandfor: prop.string(),
|
|
13
13
|
command: prop.string(),
|
|
14
|
+
href: prop.string(),
|
|
15
|
+
target: prop.string(),
|
|
16
|
+
rel: prop.string(),
|
|
14
17
|
});
|
|
15
18
|
|
|
16
19
|
const NATIVE_COMMANDS = "commandForElement" in HTMLButtonElement.prototype;
|
|
@@ -75,7 +78,11 @@
|
|
|
75
78
|
:host([hidden]) {
|
|
76
79
|
display: none;
|
|
77
80
|
}
|
|
78
|
-
|
|
81
|
+
is-visible,
|
|
82
|
+
is-hidden {
|
|
83
|
+
display: contents;
|
|
84
|
+
}
|
|
85
|
+
.control {
|
|
79
86
|
all: unset;
|
|
80
87
|
box-sizing: border-box;
|
|
81
88
|
display: inline-flex;
|
|
@@ -103,14 +110,15 @@
|
|
|
103
110
|
}
|
|
104
111
|
/* Mixing toward the text colour darkens a light-mode fill and lightens a dark-mode one, so
|
|
105
112
|
hover never lowers the text contrast. */
|
|
106
|
-
|
|
113
|
+
.control:hover {
|
|
107
114
|
background: color-mix(in oklab, var(--primary) 88%, var(--foreground));
|
|
108
115
|
}
|
|
109
|
-
|
|
116
|
+
.control:focus-visible {
|
|
110
117
|
border-color: var(--ring);
|
|
111
118
|
box-shadow: var(--focus-ring);
|
|
112
119
|
}
|
|
113
|
-
|
|
120
|
+
.control:disabled,
|
|
121
|
+
:host([disabled]) a.control {
|
|
114
122
|
pointer-events: none;
|
|
115
123
|
opacity: 0.5;
|
|
116
124
|
}
|
|
@@ -120,75 +128,80 @@
|
|
|
120
128
|
flex-shrink: 0;
|
|
121
129
|
pointer-events: none;
|
|
122
130
|
}
|
|
123
|
-
:host(:state(attr-variant-is-destructive))
|
|
131
|
+
:host(:state(attr-variant-is-destructive)) .control {
|
|
124
132
|
background: var(--destructive);
|
|
125
133
|
color: var(--destructive-foreground);
|
|
126
134
|
}
|
|
127
|
-
:host(:state(attr-variant-is-destructive))
|
|
135
|
+
:host(:state(attr-variant-is-destructive)) .control:hover {
|
|
128
136
|
background: color-mix(in oklab, var(--destructive) 88%, var(--foreground));
|
|
129
137
|
}
|
|
130
|
-
:host(:state(attr-variant-is-outline))
|
|
138
|
+
:host(:state(attr-variant-is-outline)) .control {
|
|
131
139
|
border-color: var(--border);
|
|
132
140
|
background: var(--background);
|
|
133
141
|
color: var(--foreground);
|
|
134
142
|
box-shadow: var(--shadow-xs);
|
|
135
143
|
}
|
|
136
|
-
:host(:state(attr-variant-is-outline))
|
|
137
|
-
:host(:state(attr-variant-is-ghost))
|
|
144
|
+
:host(:state(attr-variant-is-outline)) .control:hover,
|
|
145
|
+
:host(:state(attr-variant-is-ghost)) .control:hover {
|
|
138
146
|
background: var(--accent);
|
|
139
147
|
color: var(--accent-foreground);
|
|
140
148
|
}
|
|
141
|
-
:host(:state(attr-variant-is-secondary))
|
|
149
|
+
:host(:state(attr-variant-is-secondary)) .control {
|
|
142
150
|
background: var(--secondary);
|
|
143
151
|
color: var(--secondary-foreground);
|
|
144
152
|
}
|
|
145
|
-
:host(:state(attr-variant-is-secondary))
|
|
153
|
+
:host(:state(attr-variant-is-secondary)) .control:hover {
|
|
146
154
|
background: color-mix(in oklab, var(--secondary) 80%, transparent);
|
|
147
155
|
}
|
|
148
|
-
:host(:state(attr-variant-is-ghost))
|
|
156
|
+
:host(:state(attr-variant-is-ghost)) .control {
|
|
149
157
|
background: transparent;
|
|
150
158
|
color: var(--foreground);
|
|
151
159
|
}
|
|
152
|
-
:host(:state(attr-variant-is-link))
|
|
160
|
+
:host(:state(attr-variant-is-link)) .control {
|
|
153
161
|
background: transparent;
|
|
154
162
|
color: var(--primary);
|
|
155
163
|
text-underline-offset: 4px;
|
|
156
164
|
}
|
|
157
|
-
:host(:state(attr-variant-is-link))
|
|
165
|
+
:host(:state(attr-variant-is-link)) .control:hover {
|
|
158
166
|
text-decoration: underline;
|
|
159
167
|
}
|
|
160
|
-
:host(:state(attr-size-is-xs))
|
|
168
|
+
:host(:state(attr-size-is-xs)) .control {
|
|
161
169
|
height: calc(var(--spacing) * 6);
|
|
162
170
|
gap: calc(var(--spacing) * 1);
|
|
163
171
|
padding: 0 calc(var(--spacing) * 2);
|
|
164
172
|
font-size: var(--text-xs);
|
|
165
173
|
}
|
|
166
|
-
:host(:state(attr-size-is-sm))
|
|
174
|
+
:host(:state(attr-size-is-sm)) .control {
|
|
167
175
|
height: calc(var(--spacing) * 8);
|
|
168
176
|
gap: calc(var(--spacing) * 1.5);
|
|
169
177
|
padding: 0 calc(var(--spacing) * 3);
|
|
170
178
|
}
|
|
171
|
-
:host(:state(attr-size-is-lg))
|
|
179
|
+
:host(:state(attr-size-is-lg)) .control {
|
|
172
180
|
height: calc(var(--spacing) * 10);
|
|
173
181
|
padding: 0 calc(var(--spacing) * 6);
|
|
174
182
|
}
|
|
175
|
-
:host(:is(:state(attr-size-is-icon), :state(attr-size-is-icon-xs), :state(attr-size-is-icon-sm), :state(attr-size-is-icon-lg)))
|
|
183
|
+
:host(:is(:state(attr-size-is-icon), :state(attr-size-is-icon-xs), :state(attr-size-is-icon-sm), :state(attr-size-is-icon-lg))) .control {
|
|
176
184
|
padding: 0;
|
|
177
185
|
width: calc(var(--spacing) * 9);
|
|
178
186
|
}
|
|
179
|
-
:host(:state(attr-size-is-icon-xs))
|
|
187
|
+
:host(:state(attr-size-is-icon-xs)) .control {
|
|
180
188
|
width: calc(var(--spacing) * 6);
|
|
181
189
|
height: calc(var(--spacing) * 6);
|
|
182
190
|
}
|
|
183
|
-
:host(:state(attr-size-is-icon-sm))
|
|
191
|
+
:host(:state(attr-size-is-icon-sm)) .control {
|
|
184
192
|
width: calc(var(--spacing) * 8);
|
|
185
193
|
height: calc(var(--spacing) * 8);
|
|
186
194
|
}
|
|
187
|
-
:host(:state(attr-size-is-icon-lg))
|
|
195
|
+
:host(:state(attr-size-is-icon-lg)) .control {
|
|
188
196
|
width: calc(var(--spacing) * 10);
|
|
189
197
|
height: calc(var(--spacing) * 10);
|
|
190
198
|
}
|
|
191
199
|
</style>
|
|
192
200
|
|
|
193
|
-
<
|
|
201
|
+
<is-visible when="@href">
|
|
202
|
+
<a class="control" ref="link" part="button" _href="@href" _target="@target" _rel="@rel" _aria-label="@label" _aria-description="@description"><slot></slot></a>
|
|
203
|
+
</is-visible>
|
|
204
|
+
<is-hidden when="@href">
|
|
205
|
+
<button class="control" type="button" ref="button" part="button" _aria-label="@label" _aria-description="@description" _disabled="@disabled" onclick="activate()"><slot></slot></button>
|
|
206
|
+
</is-hidden>
|
|
194
207
|
</custom-element>
|
package/components/combobox.html
CHANGED
|
@@ -55,6 +55,12 @@
|
|
|
55
55
|
combo.query = "";
|
|
56
56
|
combo.active = Math.max(0, combo.visible.findIndex((item) => item.chosen));
|
|
57
57
|
refs.list.showPopover();
|
|
58
|
+
// Once open, the list keeps the side it opened on. Re-deciding while the page scrolls makes
|
|
59
|
+
// it jump, because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
60
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
61
|
+
internals.states.delete("flipped");
|
|
62
|
+
const box = refs.list.getBoundingClientRect();
|
|
63
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
function close() {
|
|
@@ -159,6 +165,13 @@
|
|
|
159
165
|
position-area: bottom span-right;
|
|
160
166
|
position-try-fallbacks: flip-block;
|
|
161
167
|
}
|
|
168
|
+
[role="listbox"]:popover-open {
|
|
169
|
+
position-try-fallbacks: none;
|
|
170
|
+
}
|
|
171
|
+
:host(:state(flipped)) [role="listbox"] {
|
|
172
|
+
position-area: top span-right;
|
|
173
|
+
margin: 0 0 calc(var(--spacing) * 1);
|
|
174
|
+
}
|
|
162
175
|
[role="option"] {
|
|
163
176
|
display: flex;
|
|
164
177
|
align-items: center;
|
|
@@ -56,8 +56,15 @@
|
|
|
56
56
|
|
|
57
57
|
const ITEMS = ":is(ui-menu-item, ui-menu-checkbox-item, ui-menu-radio-item):not([disabled])";
|
|
58
58
|
|
|
59
|
+
// Once open, the menu keeps the side it opened on. Re-deciding while the page scrolls makes it
|
|
60
|
+
// jump, because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
61
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
59
62
|
function opened(event) {
|
|
60
|
-
if (event.newState
|
|
63
|
+
if (event.newState !== "open") return;
|
|
64
|
+
internals.states.delete("flipped");
|
|
65
|
+
const box = host.getBoundingClientRect();
|
|
66
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
67
|
+
host.querySelector(ITEMS)?.focus({ preventScroll: true });
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
function leave(event) {
|
|
@@ -104,6 +111,24 @@
|
|
|
104
111
|
position-area: top span-left;
|
|
105
112
|
margin: 0 0 calc(var(--spacing) * 1);
|
|
106
113
|
}
|
|
114
|
+
:host(:popover-open) {
|
|
115
|
+
position-try-fallbacks: flip-inline;
|
|
116
|
+
}
|
|
117
|
+
:host(:state(flipped)) {
|
|
118
|
+
position-area: top span-right;
|
|
119
|
+
margin: 0 0 calc(var(--spacing) * 1);
|
|
120
|
+
}
|
|
121
|
+
:host(:state(flipped):state(attr-placement-is-bottom-end)) {
|
|
122
|
+
position-area: top span-left;
|
|
123
|
+
}
|
|
124
|
+
:host(:state(flipped):state(attr-placement-is-top-start)) {
|
|
125
|
+
position-area: bottom span-right;
|
|
126
|
+
margin: calc(var(--spacing) * 1) 0 0;
|
|
127
|
+
}
|
|
128
|
+
:host(:state(flipped):state(attr-placement-is-top-end)) {
|
|
129
|
+
position-area: bottom span-left;
|
|
130
|
+
margin: calc(var(--spacing) * 1) 0 0;
|
|
131
|
+
}
|
|
107
132
|
</style>
|
|
108
133
|
|
|
109
134
|
<div part="menu" focusgroup="menu block wrap"><slot></slot></div>
|
|
@@ -61,11 +61,25 @@
|
|
|
61
61
|
|
|
62
62
|
<custom-element name="ui-hover-card-content">
|
|
63
63
|
<script>
|
|
64
|
-
defineProps({
|
|
64
|
+
const props = defineProps({
|
|
65
65
|
placement: prop.enum(["bottom", "top", "left", "right"]).default("bottom"),
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
+
const BLOCK_SIDES = new Set(["bottom", "top"]);
|
|
69
|
+
|
|
70
|
+
// Once open, it keeps the side it opened on. Re-deciding while the page scrolls makes it jump,
|
|
71
|
+
// because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
72
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
73
|
+
function opened(event) {
|
|
74
|
+
internals.states.delete("flipped");
|
|
75
|
+
if (event.newState !== "open" || !BLOCK_SIDES.has(props.placement)) return;
|
|
76
|
+
const box = host.getBoundingClientRect();
|
|
77
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
attrs.popover ??= "manual";
|
|
81
|
+
|
|
82
|
+
listen("toggle", opened);
|
|
69
83
|
</script>
|
|
70
84
|
|
|
71
85
|
<style>
|
|
@@ -90,12 +104,21 @@
|
|
|
90
104
|
position-area: bottom;
|
|
91
105
|
position-try-fallbacks: flip-block, flip-inline;
|
|
92
106
|
}
|
|
107
|
+
:host(:popover-open) {
|
|
108
|
+
position-try-fallbacks: flip-inline;
|
|
109
|
+
}
|
|
93
110
|
:host(:state(attr-width)) {
|
|
94
111
|
width: calc(var(--spacing) * var(--attr-width));
|
|
95
112
|
}
|
|
96
113
|
:host(:state(attr-placement-is-top)) {
|
|
97
114
|
position-area: top;
|
|
98
115
|
}
|
|
116
|
+
:host(:state(flipped)) {
|
|
117
|
+
position-area: top;
|
|
118
|
+
}
|
|
119
|
+
:host(:state(flipped):state(attr-placement-is-top)) {
|
|
120
|
+
position-area: bottom;
|
|
121
|
+
}
|
|
99
122
|
:host(:state(attr-placement-is-left)) {
|
|
100
123
|
position-area: left;
|
|
101
124
|
}
|
package/components/menubar.html
CHANGED
|
@@ -94,8 +94,15 @@
|
|
|
94
94
|
<script>
|
|
95
95
|
const ITEMS = ":is(ui-menu-item, ui-menu-checkbox-item, ui-menu-radio-item):not([disabled])";
|
|
96
96
|
|
|
97
|
+
// Once open, it keeps the side it opened on. Re-deciding while the page scrolls makes it jump,
|
|
98
|
+
// because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
99
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
97
100
|
function opened(event) {
|
|
98
|
-
if (event.newState
|
|
101
|
+
if (event.newState !== "open") return;
|
|
102
|
+
internals.states.delete("flipped");
|
|
103
|
+
const box = host.getBoundingClientRect();
|
|
104
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
105
|
+
host.querySelector(ITEMS)?.focus({ preventScroll: true });
|
|
99
106
|
}
|
|
100
107
|
|
|
101
108
|
function leave(event) {
|
|
@@ -131,6 +138,13 @@
|
|
|
131
138
|
position-area: bottom span-right;
|
|
132
139
|
position-try-fallbacks: flip-block, flip-inline;
|
|
133
140
|
}
|
|
141
|
+
:host(:popover-open) {
|
|
142
|
+
position-try-fallbacks: flip-inline;
|
|
143
|
+
}
|
|
144
|
+
:host(:state(flipped)) {
|
|
145
|
+
position-area: top span-right;
|
|
146
|
+
margin: 0 0 calc(var(--spacing) * 2) calc(var(--spacing) * -1);
|
|
147
|
+
}
|
|
134
148
|
</style>
|
|
135
149
|
|
|
136
150
|
<div part="menu" focusgroup="menu block wrap"><slot></slot></div>
|
package/components/popover.html
CHANGED
|
@@ -50,11 +50,25 @@
|
|
|
50
50
|
|
|
51
51
|
<custom-element name="ui-popover-content">
|
|
52
52
|
<script>
|
|
53
|
-
defineProps({
|
|
53
|
+
const props = defineProps({
|
|
54
54
|
placement: prop.enum(["bottom", "top", "left", "right"]).default("bottom"),
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
const BLOCK_SIDES = new Set(["bottom", "top"]);
|
|
58
|
+
|
|
59
|
+
// Once open, it keeps the side it opened on. Re-deciding while the page scrolls makes it jump,
|
|
60
|
+
// because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
61
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
62
|
+
function opened(event) {
|
|
63
|
+
internals.states.delete("flipped");
|
|
64
|
+
if (event.newState !== "open" || !BLOCK_SIDES.has(props.placement)) return;
|
|
65
|
+
const box = host.getBoundingClientRect();
|
|
66
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
67
|
+
}
|
|
68
|
+
|
|
57
69
|
attrs.popover ??= "auto";
|
|
70
|
+
|
|
71
|
+
listen("toggle", opened);
|
|
58
72
|
</script>
|
|
59
73
|
|
|
60
74
|
<style>
|
|
@@ -80,6 +94,7 @@
|
|
|
80
94
|
position-try-fallbacks: flip-block, flip-inline;
|
|
81
95
|
}
|
|
82
96
|
:host(:popover-open) {
|
|
97
|
+
position-try-fallbacks: flip-inline;
|
|
83
98
|
display: grid;
|
|
84
99
|
/* Safari stretches a grid overlay to its max-height unless the rows are packed at the start. */
|
|
85
100
|
align-content: start;
|
|
@@ -91,6 +106,12 @@
|
|
|
91
106
|
:host(:state(attr-placement-is-top)) {
|
|
92
107
|
position-area: top;
|
|
93
108
|
}
|
|
109
|
+
:host(:state(flipped)) {
|
|
110
|
+
position-area: top;
|
|
111
|
+
}
|
|
112
|
+
:host(:state(flipped):state(attr-placement-is-top)) {
|
|
113
|
+
position-area: bottom;
|
|
114
|
+
}
|
|
94
115
|
:host(:state(attr-placement-is-left)) {
|
|
95
116
|
position-area: left;
|
|
96
117
|
}
|
package/components/tooltip.html
CHANGED
|
@@ -69,11 +69,25 @@
|
|
|
69
69
|
|
|
70
70
|
<custom-element name="ui-tooltip-content" role="tooltip">
|
|
71
71
|
<script>
|
|
72
|
-
defineProps({
|
|
72
|
+
const props = defineProps({
|
|
73
73
|
placement: prop.enum(["top", "bottom", "left", "right"]).default("top"),
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
const BLOCK_SIDES = new Set(["top", "bottom"]);
|
|
77
|
+
|
|
78
|
+
// Once open, it keeps the side it opened on. Re-deciding while the page scrolls makes it jump,
|
|
79
|
+
// because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
80
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
81
|
+
function opened(event) {
|
|
82
|
+
internals.states.delete("flipped");
|
|
83
|
+
if (event.newState !== "open" || !BLOCK_SIDES.has(props.placement)) return;
|
|
84
|
+
const box = host.getBoundingClientRect();
|
|
85
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
86
|
+
}
|
|
87
|
+
|
|
76
88
|
attrs.popover ??= "manual";
|
|
89
|
+
|
|
90
|
+
listen("toggle", opened);
|
|
77
91
|
</script>
|
|
78
92
|
|
|
79
93
|
<style>
|
|
@@ -100,6 +114,17 @@
|
|
|
100
114
|
position-area: bottom;
|
|
101
115
|
margin: calc(var(--spacing) * 1) 0 0;
|
|
102
116
|
}
|
|
117
|
+
:host(:popover-open) {
|
|
118
|
+
position-try-fallbacks: none;
|
|
119
|
+
}
|
|
120
|
+
:host(:state(flipped)) {
|
|
121
|
+
position-area: bottom;
|
|
122
|
+
margin: calc(var(--spacing) * 1) 0 0;
|
|
123
|
+
}
|
|
124
|
+
:host(:state(flipped):state(attr-placement-is-bottom)) {
|
|
125
|
+
position-area: top;
|
|
126
|
+
margin: 0 0 calc(var(--spacing) * 1);
|
|
127
|
+
}
|
|
103
128
|
:host(:state(attr-placement-is-left)) {
|
|
104
129
|
position-area: left;
|
|
105
130
|
margin: 0 calc(var(--spacing) * 1) 0 0;
|
package/dist/ui.html
CHANGED
|
@@ -89,11 +89,32 @@
|
|
|
89
89
|
width: calc(var(--spacing) * 4);
|
|
90
90
|
height: calc(var(--spacing) * 4);
|
|
91
91
|
color: var(--muted-foreground);
|
|
92
|
-
transition: rotate
|
|
92
|
+
transition: rotate var(--default-transition-duration) var(--default-transition-timing-function);
|
|
93
93
|
}
|
|
94
94
|
details[open] svg {
|
|
95
95
|
rotate: 180deg;
|
|
96
96
|
}
|
|
97
|
+
details::details-content {
|
|
98
|
+
display: grid;
|
|
99
|
+
grid-template-rows: 0fr;
|
|
100
|
+
transition:
|
|
101
|
+
grid-template-rows var(--default-transition-duration) var(--default-transition-timing-function),
|
|
102
|
+
content-visibility var(--default-transition-duration) allow-discrete;
|
|
103
|
+
}
|
|
104
|
+
details[open]::details-content {
|
|
105
|
+
grid-template-rows: 1fr;
|
|
106
|
+
}
|
|
107
|
+
slot:not([name]) {
|
|
108
|
+
display: block;
|
|
109
|
+
min-height: 0;
|
|
110
|
+
overflow: hidden;
|
|
111
|
+
}
|
|
112
|
+
@media (prefers-reduced-motion: reduce) {
|
|
113
|
+
svg,
|
|
114
|
+
details::details-content {
|
|
115
|
+
transition: none;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
97
118
|
</style>
|
|
98
119
|
|
|
99
120
|
<details _open="@open" ontoggle="toggled(this)">
|
|
@@ -1149,6 +1170,9 @@
|
|
|
1149
1170
|
popovertargetaction: prop.enum(["toggle", "show", "hide"]),
|
|
1150
1171
|
commandfor: prop.string(),
|
|
1151
1172
|
command: prop.string(),
|
|
1173
|
+
href: prop.string(),
|
|
1174
|
+
target: prop.string(),
|
|
1175
|
+
rel: prop.string(),
|
|
1152
1176
|
});
|
|
1153
1177
|
|
|
1154
1178
|
const NATIVE_COMMANDS = "commandForElement" in HTMLButtonElement.prototype;
|
|
@@ -1213,7 +1237,11 @@
|
|
|
1213
1237
|
:host([hidden]) {
|
|
1214
1238
|
display: none;
|
|
1215
1239
|
}
|
|
1216
|
-
|
|
1240
|
+
is-visible,
|
|
1241
|
+
is-hidden {
|
|
1242
|
+
display: contents;
|
|
1243
|
+
}
|
|
1244
|
+
.control {
|
|
1217
1245
|
all: unset;
|
|
1218
1246
|
box-sizing: border-box;
|
|
1219
1247
|
display: inline-flex;
|
|
@@ -1241,14 +1269,15 @@
|
|
|
1241
1269
|
}
|
|
1242
1270
|
/* Mixing toward the text colour darkens a light-mode fill and lightens a dark-mode one, so
|
|
1243
1271
|
hover never lowers the text contrast. */
|
|
1244
|
-
|
|
1272
|
+
.control:hover {
|
|
1245
1273
|
background: color-mix(in oklab, var(--primary) 88%, var(--foreground));
|
|
1246
1274
|
}
|
|
1247
|
-
|
|
1275
|
+
.control:focus-visible {
|
|
1248
1276
|
border-color: var(--ring);
|
|
1249
1277
|
box-shadow: var(--focus-ring);
|
|
1250
1278
|
}
|
|
1251
|
-
|
|
1279
|
+
.control:disabled,
|
|
1280
|
+
:host([disabled]) a.control {
|
|
1252
1281
|
pointer-events: none;
|
|
1253
1282
|
opacity: 0.5;
|
|
1254
1283
|
}
|
|
@@ -1258,77 +1287,82 @@
|
|
|
1258
1287
|
flex-shrink: 0;
|
|
1259
1288
|
pointer-events: none;
|
|
1260
1289
|
}
|
|
1261
|
-
:host(:state(attr-variant-is-destructive))
|
|
1290
|
+
:host(:state(attr-variant-is-destructive)) .control {
|
|
1262
1291
|
background: var(--destructive);
|
|
1263
1292
|
color: var(--destructive-foreground);
|
|
1264
1293
|
}
|
|
1265
|
-
:host(:state(attr-variant-is-destructive))
|
|
1294
|
+
:host(:state(attr-variant-is-destructive)) .control:hover {
|
|
1266
1295
|
background: color-mix(in oklab, var(--destructive) 88%, var(--foreground));
|
|
1267
1296
|
}
|
|
1268
|
-
:host(:state(attr-variant-is-outline))
|
|
1297
|
+
:host(:state(attr-variant-is-outline)) .control {
|
|
1269
1298
|
border-color: var(--border);
|
|
1270
1299
|
background: var(--background);
|
|
1271
1300
|
color: var(--foreground);
|
|
1272
1301
|
box-shadow: var(--shadow-xs);
|
|
1273
1302
|
}
|
|
1274
|
-
:host(:state(attr-variant-is-outline))
|
|
1275
|
-
:host(:state(attr-variant-is-ghost))
|
|
1303
|
+
:host(:state(attr-variant-is-outline)) .control:hover,
|
|
1304
|
+
:host(:state(attr-variant-is-ghost)) .control:hover {
|
|
1276
1305
|
background: var(--accent);
|
|
1277
1306
|
color: var(--accent-foreground);
|
|
1278
1307
|
}
|
|
1279
|
-
:host(:state(attr-variant-is-secondary))
|
|
1308
|
+
:host(:state(attr-variant-is-secondary)) .control {
|
|
1280
1309
|
background: var(--secondary);
|
|
1281
1310
|
color: var(--secondary-foreground);
|
|
1282
1311
|
}
|
|
1283
|
-
:host(:state(attr-variant-is-secondary))
|
|
1312
|
+
:host(:state(attr-variant-is-secondary)) .control:hover {
|
|
1284
1313
|
background: color-mix(in oklab, var(--secondary) 80%, transparent);
|
|
1285
1314
|
}
|
|
1286
|
-
:host(:state(attr-variant-is-ghost))
|
|
1315
|
+
:host(:state(attr-variant-is-ghost)) .control {
|
|
1287
1316
|
background: transparent;
|
|
1288
1317
|
color: var(--foreground);
|
|
1289
1318
|
}
|
|
1290
|
-
:host(:state(attr-variant-is-link))
|
|
1319
|
+
:host(:state(attr-variant-is-link)) .control {
|
|
1291
1320
|
background: transparent;
|
|
1292
1321
|
color: var(--primary);
|
|
1293
1322
|
text-underline-offset: 4px;
|
|
1294
1323
|
}
|
|
1295
|
-
:host(:state(attr-variant-is-link))
|
|
1324
|
+
:host(:state(attr-variant-is-link)) .control:hover {
|
|
1296
1325
|
text-decoration: underline;
|
|
1297
1326
|
}
|
|
1298
|
-
:host(:state(attr-size-is-xs))
|
|
1327
|
+
:host(:state(attr-size-is-xs)) .control {
|
|
1299
1328
|
height: calc(var(--spacing) * 6);
|
|
1300
1329
|
gap: calc(var(--spacing) * 1);
|
|
1301
1330
|
padding: 0 calc(var(--spacing) * 2);
|
|
1302
1331
|
font-size: var(--text-xs);
|
|
1303
1332
|
}
|
|
1304
|
-
:host(:state(attr-size-is-sm))
|
|
1333
|
+
:host(:state(attr-size-is-sm)) .control {
|
|
1305
1334
|
height: calc(var(--spacing) * 8);
|
|
1306
1335
|
gap: calc(var(--spacing) * 1.5);
|
|
1307
1336
|
padding: 0 calc(var(--spacing) * 3);
|
|
1308
1337
|
}
|
|
1309
|
-
:host(:state(attr-size-is-lg))
|
|
1338
|
+
:host(:state(attr-size-is-lg)) .control {
|
|
1310
1339
|
height: calc(var(--spacing) * 10);
|
|
1311
1340
|
padding: 0 calc(var(--spacing) * 6);
|
|
1312
1341
|
}
|
|
1313
|
-
:host(:is(:state(attr-size-is-icon), :state(attr-size-is-icon-xs), :state(attr-size-is-icon-sm), :state(attr-size-is-icon-lg)))
|
|
1342
|
+
:host(:is(:state(attr-size-is-icon), :state(attr-size-is-icon-xs), :state(attr-size-is-icon-sm), :state(attr-size-is-icon-lg))) .control {
|
|
1314
1343
|
padding: 0;
|
|
1315
1344
|
width: calc(var(--spacing) * 9);
|
|
1316
1345
|
}
|
|
1317
|
-
:host(:state(attr-size-is-icon-xs))
|
|
1346
|
+
:host(:state(attr-size-is-icon-xs)) .control {
|
|
1318
1347
|
width: calc(var(--spacing) * 6);
|
|
1319
1348
|
height: calc(var(--spacing) * 6);
|
|
1320
1349
|
}
|
|
1321
|
-
:host(:state(attr-size-is-icon-sm))
|
|
1350
|
+
:host(:state(attr-size-is-icon-sm)) .control {
|
|
1322
1351
|
width: calc(var(--spacing) * 8);
|
|
1323
1352
|
height: calc(var(--spacing) * 8);
|
|
1324
1353
|
}
|
|
1325
|
-
:host(:state(attr-size-is-icon-lg))
|
|
1354
|
+
:host(:state(attr-size-is-icon-lg)) .control {
|
|
1326
1355
|
width: calc(var(--spacing) * 10);
|
|
1327
1356
|
height: calc(var(--spacing) * 10);
|
|
1328
1357
|
}
|
|
1329
1358
|
</style>
|
|
1330
1359
|
|
|
1331
|
-
<
|
|
1360
|
+
<is-visible when="@href">
|
|
1361
|
+
<a class="control" ref="link" part="button" _href="@href" _target="@target" _rel="@rel" _aria-label="@label" _aria-description="@description"><slot></slot></a>
|
|
1362
|
+
</is-visible>
|
|
1363
|
+
<is-hidden when="@href">
|
|
1364
|
+
<button class="control" type="button" ref="button" part="button" _aria-label="@label" _aria-description="@description" _disabled="@disabled" onclick="activate()"><slot></slot></button>
|
|
1365
|
+
</is-hidden>
|
|
1332
1366
|
</custom-element>
|
|
1333
1367
|
|
|
1334
1368
|
<custom-element name="ui-calendar" form-associated>
|
|
@@ -2337,6 +2371,12 @@
|
|
|
2337
2371
|
combo.query = "";
|
|
2338
2372
|
combo.active = Math.max(0, combo.visible.findIndex((item) => item.chosen));
|
|
2339
2373
|
refs.list.showPopover();
|
|
2374
|
+
// Once open, the list keeps the side it opened on. Re-deciding while the page scrolls makes
|
|
2375
|
+
// it jump, because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
2376
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
2377
|
+
internals.states.delete("flipped");
|
|
2378
|
+
const box = refs.list.getBoundingClientRect();
|
|
2379
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
2340
2380
|
}
|
|
2341
2381
|
|
|
2342
2382
|
function close() {
|
|
@@ -2441,6 +2481,13 @@
|
|
|
2441
2481
|
position-area: bottom span-right;
|
|
2442
2482
|
position-try-fallbacks: flip-block;
|
|
2443
2483
|
}
|
|
2484
|
+
[role="listbox"]:popover-open {
|
|
2485
|
+
position-try-fallbacks: none;
|
|
2486
|
+
}
|
|
2487
|
+
:host(:state(flipped)) [role="listbox"] {
|
|
2488
|
+
position-area: top span-right;
|
|
2489
|
+
margin: 0 0 calc(var(--spacing) * 1);
|
|
2490
|
+
}
|
|
2444
2491
|
[role="option"] {
|
|
2445
2492
|
display: flex;
|
|
2446
2493
|
align-items: center;
|
|
@@ -3480,8 +3527,15 @@
|
|
|
3480
3527
|
|
|
3481
3528
|
const ITEMS = ":is(ui-menu-item, ui-menu-checkbox-item, ui-menu-radio-item):not([disabled])";
|
|
3482
3529
|
|
|
3530
|
+
// Once open, the menu keeps the side it opened on. Re-deciding while the page scrolls makes it
|
|
3531
|
+
// jump, because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
3532
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
3483
3533
|
function opened(event) {
|
|
3484
|
-
if (event.newState
|
|
3534
|
+
if (event.newState !== "open") return;
|
|
3535
|
+
internals.states.delete("flipped");
|
|
3536
|
+
const box = host.getBoundingClientRect();
|
|
3537
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
3538
|
+
host.querySelector(ITEMS)?.focus({ preventScroll: true });
|
|
3485
3539
|
}
|
|
3486
3540
|
|
|
3487
3541
|
function leave(event) {
|
|
@@ -3528,6 +3582,24 @@
|
|
|
3528
3582
|
position-area: top span-left;
|
|
3529
3583
|
margin: 0 0 calc(var(--spacing) * 1);
|
|
3530
3584
|
}
|
|
3585
|
+
:host(:popover-open) {
|
|
3586
|
+
position-try-fallbacks: flip-inline;
|
|
3587
|
+
}
|
|
3588
|
+
:host(:state(flipped)) {
|
|
3589
|
+
position-area: top span-right;
|
|
3590
|
+
margin: 0 0 calc(var(--spacing) * 1);
|
|
3591
|
+
}
|
|
3592
|
+
:host(:state(flipped):state(attr-placement-is-bottom-end)) {
|
|
3593
|
+
position-area: top span-left;
|
|
3594
|
+
}
|
|
3595
|
+
:host(:state(flipped):state(attr-placement-is-top-start)) {
|
|
3596
|
+
position-area: bottom span-right;
|
|
3597
|
+
margin: calc(var(--spacing) * 1) 0 0;
|
|
3598
|
+
}
|
|
3599
|
+
:host(:state(flipped):state(attr-placement-is-top-end)) {
|
|
3600
|
+
position-area: bottom span-left;
|
|
3601
|
+
margin: calc(var(--spacing) * 1) 0 0;
|
|
3602
|
+
}
|
|
3531
3603
|
</style>
|
|
3532
3604
|
|
|
3533
3605
|
<div part="menu" focusgroup="menu block wrap"><slot></slot></div>
|
|
@@ -4184,11 +4256,25 @@
|
|
|
4184
4256
|
|
|
4185
4257
|
<custom-element name="ui-hover-card-content">
|
|
4186
4258
|
<script>
|
|
4187
|
-
defineProps({
|
|
4259
|
+
const props = defineProps({
|
|
4188
4260
|
placement: prop.enum(["bottom", "top", "left", "right"]).default("bottom"),
|
|
4189
4261
|
});
|
|
4190
4262
|
|
|
4263
|
+
const BLOCK_SIDES = new Set(["bottom", "top"]);
|
|
4264
|
+
|
|
4265
|
+
// Once open, it keeps the side it opened on. Re-deciding while the page scrolls makes it jump,
|
|
4266
|
+
// because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
4267
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
4268
|
+
function opened(event) {
|
|
4269
|
+
internals.states.delete("flipped");
|
|
4270
|
+
if (event.newState !== "open" || !BLOCK_SIDES.has(props.placement)) return;
|
|
4271
|
+
const box = host.getBoundingClientRect();
|
|
4272
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
4273
|
+
}
|
|
4274
|
+
|
|
4191
4275
|
attrs.popover ??= "manual";
|
|
4276
|
+
|
|
4277
|
+
listen("toggle", opened);
|
|
4192
4278
|
</script>
|
|
4193
4279
|
|
|
4194
4280
|
<style>
|
|
@@ -4213,12 +4299,21 @@
|
|
|
4213
4299
|
position-area: bottom;
|
|
4214
4300
|
position-try-fallbacks: flip-block, flip-inline;
|
|
4215
4301
|
}
|
|
4302
|
+
:host(:popover-open) {
|
|
4303
|
+
position-try-fallbacks: flip-inline;
|
|
4304
|
+
}
|
|
4216
4305
|
:host(:state(attr-width)) {
|
|
4217
4306
|
width: calc(var(--spacing) * var(--attr-width));
|
|
4218
4307
|
}
|
|
4219
4308
|
:host(:state(attr-placement-is-top)) {
|
|
4220
4309
|
position-area: top;
|
|
4221
4310
|
}
|
|
4311
|
+
:host(:state(flipped)) {
|
|
4312
|
+
position-area: top;
|
|
4313
|
+
}
|
|
4314
|
+
:host(:state(flipped):state(attr-placement-is-top)) {
|
|
4315
|
+
position-area: bottom;
|
|
4316
|
+
}
|
|
4222
4317
|
:host(:state(attr-placement-is-left)) {
|
|
4223
4318
|
position-area: left;
|
|
4224
4319
|
}
|
|
@@ -5012,8 +5107,15 @@
|
|
|
5012
5107
|
<script>
|
|
5013
5108
|
const ITEMS = ":is(ui-menu-item, ui-menu-checkbox-item, ui-menu-radio-item):not([disabled])";
|
|
5014
5109
|
|
|
5110
|
+
// Once open, it keeps the side it opened on. Re-deciding while the page scrolls makes it jump,
|
|
5111
|
+
// because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
5112
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
5015
5113
|
function opened(event) {
|
|
5016
|
-
if (event.newState
|
|
5114
|
+
if (event.newState !== "open") return;
|
|
5115
|
+
internals.states.delete("flipped");
|
|
5116
|
+
const box = host.getBoundingClientRect();
|
|
5117
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
5118
|
+
host.querySelector(ITEMS)?.focus({ preventScroll: true });
|
|
5017
5119
|
}
|
|
5018
5120
|
|
|
5019
5121
|
function leave(event) {
|
|
@@ -5049,6 +5151,13 @@
|
|
|
5049
5151
|
position-area: bottom span-right;
|
|
5050
5152
|
position-try-fallbacks: flip-block, flip-inline;
|
|
5051
5153
|
}
|
|
5154
|
+
:host(:popover-open) {
|
|
5155
|
+
position-try-fallbacks: flip-inline;
|
|
5156
|
+
}
|
|
5157
|
+
:host(:state(flipped)) {
|
|
5158
|
+
position-area: top span-right;
|
|
5159
|
+
margin: 0 0 calc(var(--spacing) * 2) calc(var(--spacing) * -1);
|
|
5160
|
+
}
|
|
5052
5161
|
</style>
|
|
5053
5162
|
|
|
5054
5163
|
<div part="menu" focusgroup="menu block wrap"><slot></slot></div>
|
|
@@ -5664,11 +5773,25 @@
|
|
|
5664
5773
|
|
|
5665
5774
|
<custom-element name="ui-popover-content">
|
|
5666
5775
|
<script>
|
|
5667
|
-
defineProps({
|
|
5776
|
+
const props = defineProps({
|
|
5668
5777
|
placement: prop.enum(["bottom", "top", "left", "right"]).default("bottom"),
|
|
5669
5778
|
});
|
|
5670
5779
|
|
|
5780
|
+
const BLOCK_SIDES = new Set(["bottom", "top"]);
|
|
5781
|
+
|
|
5782
|
+
// Once open, it keeps the side it opened on. Re-deciding while the page scrolls makes it jump,
|
|
5783
|
+
// because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
5784
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
5785
|
+
function opened(event) {
|
|
5786
|
+
internals.states.delete("flipped");
|
|
5787
|
+
if (event.newState !== "open" || !BLOCK_SIDES.has(props.placement)) return;
|
|
5788
|
+
const box = host.getBoundingClientRect();
|
|
5789
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
5790
|
+
}
|
|
5791
|
+
|
|
5671
5792
|
attrs.popover ??= "auto";
|
|
5793
|
+
|
|
5794
|
+
listen("toggle", opened);
|
|
5672
5795
|
</script>
|
|
5673
5796
|
|
|
5674
5797
|
<style>
|
|
@@ -5694,6 +5817,7 @@
|
|
|
5694
5817
|
position-try-fallbacks: flip-block, flip-inline;
|
|
5695
5818
|
}
|
|
5696
5819
|
:host(:popover-open) {
|
|
5820
|
+
position-try-fallbacks: flip-inline;
|
|
5697
5821
|
display: grid;
|
|
5698
5822
|
/* Safari stretches a grid overlay to its max-height unless the rows are packed at the start. */
|
|
5699
5823
|
align-content: start;
|
|
@@ -5705,6 +5829,12 @@
|
|
|
5705
5829
|
:host(:state(attr-placement-is-top)) {
|
|
5706
5830
|
position-area: top;
|
|
5707
5831
|
}
|
|
5832
|
+
:host(:state(flipped)) {
|
|
5833
|
+
position-area: top;
|
|
5834
|
+
}
|
|
5835
|
+
:host(:state(flipped):state(attr-placement-is-top)) {
|
|
5836
|
+
position-area: bottom;
|
|
5837
|
+
}
|
|
5708
5838
|
:host(:state(attr-placement-is-left)) {
|
|
5709
5839
|
position-area: left;
|
|
5710
5840
|
}
|
|
@@ -7878,11 +8008,25 @@
|
|
|
7878
8008
|
|
|
7879
8009
|
<custom-element name="ui-tooltip-content" role="tooltip">
|
|
7880
8010
|
<script>
|
|
7881
|
-
defineProps({
|
|
8011
|
+
const props = defineProps({
|
|
7882
8012
|
placement: prop.enum(["top", "bottom", "left", "right"]).default("top"),
|
|
7883
8013
|
});
|
|
7884
8014
|
|
|
8015
|
+
const BLOCK_SIDES = new Set(["top", "bottom"]);
|
|
8016
|
+
|
|
8017
|
+
// Once open, it keeps the side it opened on. Re-deciding while the page scrolls makes it jump,
|
|
8018
|
+
// because iOS Safari's toolbar changes the viewport height mid-scroll.
|
|
8019
|
+
// Firefox holds a box that does not fit against the screen edge, so touching it counts too.
|
|
8020
|
+
function opened(event) {
|
|
8021
|
+
internals.states.delete("flipped");
|
|
8022
|
+
if (event.newState !== "open" || !BLOCK_SIDES.has(props.placement)) return;
|
|
8023
|
+
const box = host.getBoundingClientRect();
|
|
8024
|
+
if (box.bottom >= innerHeight || box.top <= 0) internals.states.add("flipped");
|
|
8025
|
+
}
|
|
8026
|
+
|
|
7885
8027
|
attrs.popover ??= "manual";
|
|
8028
|
+
|
|
8029
|
+
listen("toggle", opened);
|
|
7886
8030
|
</script>
|
|
7887
8031
|
|
|
7888
8032
|
<style>
|
|
@@ -7909,6 +8053,17 @@
|
|
|
7909
8053
|
position-area: bottom;
|
|
7910
8054
|
margin: calc(var(--spacing) * 1) 0 0;
|
|
7911
8055
|
}
|
|
8056
|
+
:host(:popover-open) {
|
|
8057
|
+
position-try-fallbacks: none;
|
|
8058
|
+
}
|
|
8059
|
+
:host(:state(flipped)) {
|
|
8060
|
+
position-area: bottom;
|
|
8061
|
+
margin: calc(var(--spacing) * 1) 0 0;
|
|
8062
|
+
}
|
|
8063
|
+
:host(:state(flipped):state(attr-placement-is-bottom)) {
|
|
8064
|
+
position-area: top;
|
|
8065
|
+
margin: 0 0 calc(var(--spacing) * 1);
|
|
8066
|
+
}
|
|
7912
8067
|
:host(:state(attr-placement-is-left)) {
|
|
7913
8068
|
position-area: left;
|
|
7914
8069
|
margin: 0 calc(var(--spacing) * 1) 0 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@realmorg/ui",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.4",
|
|
4
4
|
"description": "About 60 accessible UI components built with REALM.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,16 +22,17 @@
|
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@vitest/browser-playwright": "5.0.5",
|
|
24
24
|
"playwright": "1.64.1",
|
|
25
|
+
"typescript": "7.0.2",
|
|
25
26
|
"vite": "8.3.4",
|
|
26
27
|
"vitest": "5.0.5",
|
|
27
|
-
"@realmorg/realm": "2.0.0-alpha.
|
|
28
|
+
"@realmorg/realm": "2.0.0-alpha.5",
|
|
28
29
|
"tsconfig": "0.0.0"
|
|
29
30
|
},
|
|
30
31
|
"publishConfig": {
|
|
31
32
|
"access": "public"
|
|
32
33
|
},
|
|
33
34
|
"peerDependencies": {
|
|
34
|
-
"@realmorg/realm": "^2.0.0-alpha.
|
|
35
|
+
"@realmorg/realm": "^2.0.0-alpha.5"
|
|
35
36
|
},
|
|
36
37
|
"scripts": {
|
|
37
38
|
"build": "node scripts/bundle.mjs",
|