noph-ui 0.40.3 → 0.42.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/dist/button/Button.svelte +21 -6
- package/dist/button/IconButton.svelte +20 -8
- package/dist/button/SegmentedButton.svelte +25 -8
- package/dist/card/Card.svelte +5 -1
- package/dist/chip/FilterChip.svelte +17 -8
- package/dist/chip/InputChip.svelte +6 -1
- package/dist/internal/interest.css +4 -0
- package/dist/list/Item.svelte +5 -1
- package/dist/menu/Menu.svelte +32 -4
- package/dist/navigation-drawer/NavigationDrawer.svelte +17 -9
- package/dist/ripple/Ripple.svelte +4 -1
- package/dist/select/NativeSelect.svelte +52 -28
- package/dist/select/Option.svelte +4 -1
- package/dist/select/Select.svelte +13 -4
- package/dist/snackbar/Snackbar.svelte +6 -1
- package/dist/tabs/Tab.svelte +12 -3
- package/dist/tabs/Tabs.svelte +4 -1
- package/dist/text-field/TextField.svelte +19 -25
- package/dist/text-field/types.d.ts +4 -0
- package/dist/tooltip/RichTooltip.svelte +127 -0
- package/dist/tooltip/RichTooltip.svelte.d.ts +7 -0
- package/dist/tooltip/Tooltip.svelte +53 -27
- package/dist/tooltip/Tooltip.svelte.d.ts +1 -0
- package/dist/tooltip/index.d.ts +1 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/tooltip/types.d.ts +15 -0
- package/package.json +1 -1
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
|
|
27
27
|
const uid = $props.id()
|
|
28
28
|
|
|
29
|
+
const tooltipId = $derived(title && !disabled && !loading ? uid : undefined)
|
|
30
|
+
|
|
29
31
|
let pressed = $state(false)
|
|
30
32
|
let pressedTimeout: ReturnType<typeof setTimeout>
|
|
31
33
|
|
|
@@ -79,7 +81,8 @@
|
|
|
79
81
|
}
|
|
80
82
|
attributes.onclick?.(event)
|
|
81
83
|
}}
|
|
82
|
-
aria-describedby={
|
|
84
|
+
aria-describedby={tooltipId ?? attributes['aria-describedby']}
|
|
85
|
+
interestfor={tooltipId ?? attributes['interestfor']}
|
|
83
86
|
aria-label={title || attributes['aria-label']}
|
|
84
87
|
bind:this={element}
|
|
85
88
|
class={[
|
|
@@ -99,7 +102,8 @@
|
|
|
99
102
|
{:else}
|
|
100
103
|
<button
|
|
101
104
|
{...attributes as HTMLButtonAttributes}
|
|
102
|
-
aria-describedby={
|
|
105
|
+
aria-describedby={tooltipId ?? attributes['aria-describedby']}
|
|
106
|
+
interestfor={tooltipId ?? attributes['interestfor']}
|
|
103
107
|
aria-label={title || attributes['aria-label']}
|
|
104
108
|
disabled={disabled || loading}
|
|
105
109
|
aria-pressed={toggle ? selected : undefined}
|
|
@@ -130,8 +134,8 @@
|
|
|
130
134
|
</button>
|
|
131
135
|
{/if}
|
|
132
136
|
|
|
133
|
-
{#if
|
|
134
|
-
<Tooltip id={
|
|
137
|
+
{#if tooltipId}
|
|
138
|
+
<Tooltip id={tooltipId}>{title}</Tooltip>
|
|
135
139
|
{/if}
|
|
136
140
|
|
|
137
141
|
<style>
|
|
@@ -170,9 +174,16 @@
|
|
|
170
174
|
--np-icon-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
|
171
175
|
transition:
|
|
172
176
|
background-color var(--np-motion-expressive-default-effects),
|
|
173
|
-
border-radius var(--np-motion-expressive-default-effects),
|
|
174
177
|
box-shadow var(--np-motion-expressive-default-effects);
|
|
175
178
|
}
|
|
179
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
180
|
+
.np-button {
|
|
181
|
+
transition:
|
|
182
|
+
background-color var(--np-motion-expressive-default-effects),
|
|
183
|
+
border-radius var(--np-motion-expressive-default-effects),
|
|
184
|
+
box-shadow var(--np-motion-expressive-default-effects);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
176
187
|
.xs {
|
|
177
188
|
font-size: 0.875rem;
|
|
178
189
|
height: 2rem;
|
|
@@ -286,7 +297,11 @@
|
|
|
286
297
|
outline-color: var(--np-color-secondary);
|
|
287
298
|
outline-width: 3px;
|
|
288
299
|
outline-offset: 2px;
|
|
289
|
-
|
|
300
|
+
}
|
|
301
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
302
|
+
.enabled:focus-visible {
|
|
303
|
+
animation: focusAnimation var(--np-motion-expressive-slow-effects) forwards;
|
|
304
|
+
}
|
|
290
305
|
}
|
|
291
306
|
.text {
|
|
292
307
|
--np-ripple-hover-color: var(--np-text-button-label-text-color, var(--np-color-primary));
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
}: IconButtonProps = $props()
|
|
26
26
|
|
|
27
27
|
const uid = $props.id()
|
|
28
|
+
const tooltipId = $derived(title && !disabled && !loading ? uid : undefined)
|
|
28
29
|
|
|
29
30
|
let pressed = $state(false)
|
|
30
31
|
let pressedTimeout: ReturnType<typeof setTimeout>
|
|
@@ -70,7 +71,8 @@
|
|
|
70
71
|
}
|
|
71
72
|
attributes.onclick?.(event)
|
|
72
73
|
}}
|
|
73
|
-
aria-describedby={
|
|
74
|
+
aria-describedby={tooltipId ?? attributes['aria-describedby']}
|
|
75
|
+
interestfor={tooltipId ?? attributes['interestfor']}
|
|
74
76
|
aria-label={title || attributes['aria-label']}
|
|
75
77
|
bind:this={element}
|
|
76
78
|
class={[
|
|
@@ -91,7 +93,8 @@
|
|
|
91
93
|
{:else}
|
|
92
94
|
<button
|
|
93
95
|
{...attributes as HTMLButtonAttributes}
|
|
94
|
-
aria-describedby={
|
|
96
|
+
aria-describedby={tooltipId ?? attributes['aria-describedby']}
|
|
97
|
+
interestfor={tooltipId ?? attributes['interestfor']}
|
|
95
98
|
aria-label={title || attributes['aria-label']}
|
|
96
99
|
aria-pressed={toggle ? selected : undefined}
|
|
97
100
|
aria-busy={loading}
|
|
@@ -122,8 +125,8 @@
|
|
|
122
125
|
</button>
|
|
123
126
|
{/if}
|
|
124
127
|
|
|
125
|
-
{#if
|
|
126
|
-
<Tooltip id={
|
|
128
|
+
{#if tooltipId}
|
|
129
|
+
<Tooltip id={tooltipId}>{title}</Tooltip>
|
|
127
130
|
{/if}
|
|
128
131
|
|
|
129
132
|
<style>
|
|
@@ -142,9 +145,14 @@
|
|
|
142
145
|
align-items: center;
|
|
143
146
|
justify-content: center;
|
|
144
147
|
--np-icon-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
|
145
|
-
transition:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
+
transition: background-color var(--np-motion-expressive-default-effects);
|
|
149
|
+
}
|
|
150
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
151
|
+
.np-icon-button {
|
|
152
|
+
transition:
|
|
153
|
+
background-color var(--np-motion-expressive-default-effects),
|
|
154
|
+
border-radius var(--np-motion-expressive-default-effects);
|
|
155
|
+
}
|
|
148
156
|
}
|
|
149
157
|
|
|
150
158
|
:global(.np-icon-button svg) {
|
|
@@ -291,7 +299,11 @@
|
|
|
291
299
|
outline-color: var(--np-color-secondary);
|
|
292
300
|
outline-width: 3px;
|
|
293
301
|
outline-offset: 2px;
|
|
294
|
-
|
|
302
|
+
}
|
|
303
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
304
|
+
.enabled:focus-visible {
|
|
305
|
+
animation: focusAnimation var(--np-motion-expressive-slow-effects) forwards;
|
|
306
|
+
}
|
|
295
307
|
}
|
|
296
308
|
.text {
|
|
297
309
|
--np-ripple-hover-color: var(--np-icon-button-icon-color, var(--np-color-on-surface-variant));
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
align-items: center;
|
|
111
111
|
border-inline-end: 1px solid var(--np-color-outline);
|
|
112
112
|
position: relative;
|
|
113
|
-
transition:
|
|
113
|
+
transition: color var(--np-motion-expressive-fast-effects);
|
|
114
114
|
}
|
|
115
115
|
.np-segmented-button-icon-label {
|
|
116
116
|
display: inline-flex;
|
|
@@ -161,7 +161,6 @@
|
|
|
161
161
|
width: 0;
|
|
162
162
|
overflow: hidden;
|
|
163
163
|
fill: currentColor;
|
|
164
|
-
transition: width var(--np-motion-expressive-slow-effects);
|
|
165
164
|
}
|
|
166
165
|
:global(.check-icon svg) {
|
|
167
166
|
display: block;
|
|
@@ -169,14 +168,12 @@
|
|
|
169
168
|
.check-icon-wrapper {
|
|
170
169
|
width: 0;
|
|
171
170
|
overflow: hidden;
|
|
172
|
-
transition: width var(--np-motion-expressive-fast-effects);
|
|
173
171
|
}
|
|
174
172
|
.alternate-icon {
|
|
175
173
|
display: flex;
|
|
176
174
|
width: 1.5rem;
|
|
177
175
|
overflow: hidden;
|
|
178
176
|
fill: currentColor;
|
|
179
|
-
transition: width var(--np-motion-expressive-slow-effects);
|
|
180
177
|
}
|
|
181
178
|
:global(.alternate-icon svg) {
|
|
182
179
|
display: block;
|
|
@@ -186,9 +183,7 @@
|
|
|
186
183
|
.alternate-icon-wrapper {
|
|
187
184
|
width: 2rem;
|
|
188
185
|
overflow: hidden;
|
|
189
|
-
transition:
|
|
190
|
-
width var(--np-motion-expressive-fast-effects),
|
|
191
|
-
opacity var(--np-motion-expressive-fast-effects);
|
|
186
|
+
transition: opacity var(--np-motion-expressive-fast-effects);
|
|
192
187
|
}
|
|
193
188
|
.np-segmented-button:has(input:checked) :global(.alternate-icon-wrapper) {
|
|
194
189
|
width: 0;
|
|
@@ -213,6 +208,28 @@
|
|
|
213
208
|
outline-color: var(--np-color-secondary);
|
|
214
209
|
outline-width: 3px;
|
|
215
210
|
outline-offset: -3px;
|
|
216
|
-
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
214
|
+
.np-segmented-button {
|
|
215
|
+
transition: all var(--np-motion-expressive-fast-effects);
|
|
216
|
+
}
|
|
217
|
+
.check-icon {
|
|
218
|
+
transition: width var(--np-motion-expressive-slow-effects);
|
|
219
|
+
}
|
|
220
|
+
.check-icon-wrapper {
|
|
221
|
+
transition: width var(--np-motion-expressive-fast-effects);
|
|
222
|
+
}
|
|
223
|
+
.alternate-icon {
|
|
224
|
+
transition: width var(--np-motion-expressive-slow-effects);
|
|
225
|
+
}
|
|
226
|
+
.alternate-icon-wrapper {
|
|
227
|
+
transition:
|
|
228
|
+
width var(--np-motion-expressive-fast-effects),
|
|
229
|
+
opacity var(--np-motion-expressive-fast-effects);
|
|
230
|
+
}
|
|
231
|
+
.np-segmented-button:has(input:focus-visible) {
|
|
232
|
+
animation: focusAnimationInset var(--np-motion-expressive-slow-effects) forwards;
|
|
233
|
+
}
|
|
217
234
|
}
|
|
218
235
|
</style>
|
package/dist/card/Card.svelte
CHANGED
|
@@ -159,7 +159,11 @@
|
|
|
159
159
|
outline-color: var(--np-color-secondary);
|
|
160
160
|
outline-width: 3px;
|
|
161
161
|
outline-offset: 2px;
|
|
162
|
-
|
|
162
|
+
}
|
|
163
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
164
|
+
.np-card-container:focus-visible {
|
|
165
|
+
animation: focusAnimation var(--np-motion-expressive-slow-effects) forwards;
|
|
166
|
+
}
|
|
163
167
|
}
|
|
164
168
|
.np-card-disabled {
|
|
165
169
|
opacity: 0.38;
|
|
@@ -133,7 +133,6 @@
|
|
|
133
133
|
z-index: 1;
|
|
134
134
|
padding-inline: 1rem;
|
|
135
135
|
overflow: hidden;
|
|
136
|
-
transition: padding var(--np-motion-expressive-default-effects);
|
|
137
136
|
}
|
|
138
137
|
.np-chip-icon-checked {
|
|
139
138
|
display: flex;
|
|
@@ -141,17 +140,11 @@
|
|
|
141
140
|
min-width: 0;
|
|
142
141
|
margin-inline-end: -0.5rem;
|
|
143
142
|
overflow: hidden;
|
|
144
|
-
transition:
|
|
145
|
-
width var(--np-motion-expressive-default-effects),
|
|
146
|
-
margin var(--np-motion-expressive-default-effects);
|
|
147
143
|
}
|
|
148
144
|
.np-filter-chip:has(input:checked) .np-chip-icon-checked {
|
|
149
145
|
width: 18px;
|
|
150
146
|
margin-inline-end: 0;
|
|
151
147
|
}
|
|
152
|
-
.np-filter-chip-icon .np-chip-icon-checked {
|
|
153
|
-
transition: none;
|
|
154
|
-
}
|
|
155
148
|
.np-filter-chip:has(input:checked) .np-chip-icon {
|
|
156
149
|
display: none;
|
|
157
150
|
}
|
|
@@ -238,7 +231,6 @@
|
|
|
238
231
|
outline-color: var(--np-color-secondary);
|
|
239
232
|
outline-width: 3px;
|
|
240
233
|
outline-offset: 2px;
|
|
241
|
-
animation: focusAnimation var(--np-motion-expressive-slow-effects) forwards;
|
|
242
234
|
}
|
|
243
235
|
|
|
244
236
|
.np-filter-chip-disabled .np-filter-chip-label {
|
|
@@ -259,4 +251,21 @@
|
|
|
259
251
|
outline-color: transparent;
|
|
260
252
|
background-color: color-mix(in srgb, var(--np-color-on-surface) 12%, transparent);
|
|
261
253
|
}
|
|
254
|
+
|
|
255
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
256
|
+
.np-filter-chip-label {
|
|
257
|
+
transition: padding var(--np-motion-expressive-default-effects);
|
|
258
|
+
}
|
|
259
|
+
.np-chip-icon-checked {
|
|
260
|
+
transition:
|
|
261
|
+
width var(--np-motion-expressive-default-effects),
|
|
262
|
+
margin var(--np-motion-expressive-default-effects);
|
|
263
|
+
}
|
|
264
|
+
.np-filter-chip-icon .np-chip-icon-checked {
|
|
265
|
+
transition: none;
|
|
266
|
+
}
|
|
267
|
+
.np-filter-chip:has(input:focus-visible) {
|
|
268
|
+
animation: focusAnimation var(--np-motion-expressive-slow-effects) forwards;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
262
271
|
</style>
|
|
@@ -150,7 +150,6 @@
|
|
|
150
150
|
outline-color: var(--np-color-secondary);
|
|
151
151
|
outline-width: 3px;
|
|
152
152
|
outline-offset: 2px;
|
|
153
|
-
animation: focusAnimation var(--np-motion-expressive-slow-effects) forwards;
|
|
154
153
|
}
|
|
155
154
|
|
|
156
155
|
.np-input-chip-disabled .np-input-chip-label {
|
|
@@ -166,4 +165,10 @@
|
|
|
166
165
|
outline-color: transparent;
|
|
167
166
|
background-color: color-mix(in srgb, var(--np-color-on-surface) 12%, transparent);
|
|
168
167
|
}
|
|
168
|
+
|
|
169
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
170
|
+
.np-input-chip:has(:focus-visible) {
|
|
171
|
+
animation: focusAnimation var(--np-motion-expressive-slow-effects) forwards;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
169
174
|
</style>
|
package/dist/list/Item.svelte
CHANGED
|
@@ -151,7 +151,11 @@
|
|
|
151
151
|
outline-width: 3px;
|
|
152
152
|
outline-offset: -3px;
|
|
153
153
|
border-radius: var(--np-shape-corner-extra-small);
|
|
154
|
-
|
|
154
|
+
}
|
|
155
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
156
|
+
.np-item:focus-visible {
|
|
157
|
+
animation: focusAnimationInset var(--np-motion-expressive-slow-effects) forwards;
|
|
158
|
+
}
|
|
155
159
|
}
|
|
156
160
|
|
|
157
161
|
div.np-item {
|
package/dist/menu/Menu.svelte
CHANGED
|
@@ -29,6 +29,20 @@
|
|
|
29
29
|
element?.hidePopover()
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
const calculateTransformOrigin = (anchorRect: DOMRect, menuRect: DOMRect) => {
|
|
33
|
+
const pivot = (anchorStart: number, anchorEnd: number, menuStart: number, menuEnd: number) => {
|
|
34
|
+
if (menuStart >= anchorEnd) return 0
|
|
35
|
+
if (menuEnd <= anchorStart) return 1
|
|
36
|
+
if (menuEnd === menuStart) return 0
|
|
37
|
+
const intersectionCenter =
|
|
38
|
+
(Math.max(anchorStart, menuStart) + Math.min(anchorEnd, menuEnd)) / 2
|
|
39
|
+
return (intersectionCenter - menuStart) / (menuEnd - menuStart)
|
|
40
|
+
}
|
|
41
|
+
const x = pivot(anchorRect.left, anchorRect.right, menuRect.left, menuRect.right)
|
|
42
|
+
const y = pivot(anchorRect.top, anchorRect.bottom, menuRect.top, menuRect.bottom)
|
|
43
|
+
return `${x * 100}% ${y * 100}%`
|
|
44
|
+
}
|
|
45
|
+
|
|
32
46
|
const refreshValues = () => {
|
|
33
47
|
if (element && anchor && open) {
|
|
34
48
|
const anchorRect = anchor.getBoundingClientRect()
|
|
@@ -40,6 +54,10 @@
|
|
|
40
54
|
const above = Math.max(anchorRect.top - margin, 0)
|
|
41
55
|
const overAnchor = coverAnchor && wanted > below && wanted > above && wanted <= room
|
|
42
56
|
element.style.maxHeight = `${Math.floor(overAnchor ? room : Math.max(below, above))}px`
|
|
57
|
+
element.style.transformOrigin = calculateTransformOrigin(
|
|
58
|
+
anchorRect,
|
|
59
|
+
element.getBoundingClientRect(),
|
|
60
|
+
)
|
|
43
61
|
}
|
|
44
62
|
}
|
|
45
63
|
$effect(refreshValues)
|
|
@@ -90,6 +108,7 @@
|
|
|
90
108
|
scrollbar-width: thin;
|
|
91
109
|
justify-self: var(--np-menu-justify-self, anchor-center);
|
|
92
110
|
position-area: var(--np-menu-position-area, bottom);
|
|
111
|
+
transform-origin: var(--np-menu-transform-origin, top center);
|
|
93
112
|
position-try-fallbacks:
|
|
94
113
|
flip-block,
|
|
95
114
|
flip-inline,
|
|
@@ -112,14 +131,23 @@
|
|
|
112
131
|
|
|
113
132
|
.np-menu-container:popover-open {
|
|
114
133
|
opacity: 1;
|
|
115
|
-
|
|
134
|
+
scale: 1;
|
|
135
|
+
}
|
|
136
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
137
|
+
.np-menu-container:popover-open {
|
|
138
|
+
animation:
|
|
139
|
+
fadeIn var(--np-motion-expressive-fast-effects),
|
|
140
|
+
scaleIn var(--np-motion-expressive-fast-spatial);
|
|
141
|
+
}
|
|
116
142
|
}
|
|
117
143
|
@keyframes fadeIn {
|
|
118
|
-
|
|
144
|
+
from {
|
|
119
145
|
opacity: 0;
|
|
120
146
|
}
|
|
121
|
-
|
|
122
|
-
|
|
147
|
+
}
|
|
148
|
+
@keyframes scaleIn {
|
|
149
|
+
from {
|
|
150
|
+
scale: 0.8;
|
|
123
151
|
}
|
|
124
152
|
}
|
|
125
153
|
</style>
|
|
@@ -110,19 +110,27 @@
|
|
|
110
110
|
|
|
111
111
|
.np-navigation-drawer-container[popover] .np-navigation-wrapper {
|
|
112
112
|
transform: var(--np-navigation-drawer-start, translateX(-100%));
|
|
113
|
-
transition: transform var(--np-motion-standard-slow-spatial);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.np-navigation-drawer-container[popover] {
|
|
117
|
-
transition:
|
|
118
|
-
overlay var(--np-motion-standard-slow-spatial) allow-discrete,
|
|
119
|
-
display var(--np-motion-standard-slow-spatial) allow-discrete;
|
|
120
113
|
}
|
|
121
114
|
|
|
122
115
|
.np-navigation-drawer-container:popover-open .np-navigation-wrapper {
|
|
123
116
|
transform: translateX(0);
|
|
124
|
-
|
|
125
|
-
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
120
|
+
.np-navigation-drawer-container[popover] .np-navigation-wrapper {
|
|
121
|
+
transition: transform var(--np-motion-standard-slow-spatial);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.np-navigation-drawer-container[popover] {
|
|
125
|
+
transition:
|
|
126
|
+
overlay var(--np-motion-standard-slow-spatial) allow-discrete,
|
|
127
|
+
display var(--np-motion-standard-slow-spatial) allow-discrete;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.np-navigation-drawer-container:popover-open .np-navigation-wrapper {
|
|
131
|
+
@starting-style {
|
|
132
|
+
transform: var(--np-navigation-drawer-start, translateX(-100%));
|
|
133
|
+
}
|
|
126
134
|
}
|
|
127
135
|
}
|
|
128
136
|
.np-navigation-drawer {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { on } from 'svelte/events'
|
|
3
|
+
import { MediaQuery } from 'svelte/reactivity'
|
|
3
4
|
import type { RippleProps } from './types.js'
|
|
4
5
|
|
|
5
6
|
let {
|
|
@@ -22,6 +23,8 @@
|
|
|
22
23
|
const EASING_STANDARD = 'cubic-bezier(0.2, 0, 0, 1)'
|
|
23
24
|
const TOUCH_DELAY_MS = 150
|
|
24
25
|
|
|
26
|
+
const reducedMotion = new MediaQuery('(prefers-reduced-motion: reduce)', false)
|
|
27
|
+
|
|
25
28
|
let rippleSize = $state('')
|
|
26
29
|
let rippleScale = $state('')
|
|
27
30
|
let initialSize = $state(0)
|
|
@@ -128,7 +131,7 @@
|
|
|
128
131
|
},
|
|
129
132
|
{
|
|
130
133
|
pseudoElement: PRESS_PSEUDO,
|
|
131
|
-
duration: PRESS_GROW_MS,
|
|
134
|
+
duration: reducedMotion.current ? 0 : PRESS_GROW_MS,
|
|
132
135
|
easing: EASING_STANDARD,
|
|
133
136
|
fill: ANIMATION_FILL,
|
|
134
137
|
},
|
|
@@ -104,6 +104,9 @@
|
|
|
104
104
|
position: relative;
|
|
105
105
|
font-size: 1rem;
|
|
106
106
|
display: inline-block;
|
|
107
|
+
box-sizing: border-box;
|
|
108
|
+
min-width: var(--np-select-min-width, 210px);
|
|
109
|
+
max-width: var(--np-select-max-width, 100%);
|
|
107
110
|
color: var(--np-color-on-surface-variant);
|
|
108
111
|
}
|
|
109
112
|
|
|
@@ -131,14 +134,17 @@
|
|
|
131
134
|
box-shadow: var(--np-elevation-2);
|
|
132
135
|
border: none;
|
|
133
136
|
opacity: 0;
|
|
137
|
+
scale: 0.8;
|
|
138
|
+
transform-origin: top center;
|
|
134
139
|
transition:
|
|
135
|
-
opacity var(--
|
|
140
|
+
opacity var(--np-motion-expressive-fast-effects),
|
|
136
141
|
display 150ms allow-discrete,
|
|
137
142
|
overlay 150ms allow-discrete;
|
|
138
143
|
}
|
|
139
144
|
|
|
140
145
|
select:open::picker(select) {
|
|
141
146
|
opacity: 1;
|
|
147
|
+
scale: 1;
|
|
142
148
|
@starting-style {
|
|
143
149
|
opacity: 0;
|
|
144
150
|
}
|
|
@@ -176,7 +182,8 @@
|
|
|
176
182
|
|
|
177
183
|
.np-select-outline-start,
|
|
178
184
|
.np-select-outline-notch,
|
|
179
|
-
.np-select-outline-end
|
|
185
|
+
.np-select-outline-end,
|
|
186
|
+
.np-select-filled {
|
|
180
187
|
transition:
|
|
181
188
|
border-color var(--easing-fast),
|
|
182
189
|
border-width var(--easing-fast);
|
|
@@ -205,7 +212,6 @@
|
|
|
205
212
|
pointer-events: none;
|
|
206
213
|
inset-inline-end: 0.75rem;
|
|
207
214
|
inset-block-start: 1rem;
|
|
208
|
-
transition: rotate var(--easing-fast);
|
|
209
215
|
}
|
|
210
216
|
|
|
211
217
|
.np-select-container:has(select:open) .arrow {
|
|
@@ -253,9 +259,6 @@
|
|
|
253
259
|
border-start-start-radius: var(--np-shape-corner-extra-small);
|
|
254
260
|
border-start-end-radius: var(--np-shape-corner-extra-small);
|
|
255
261
|
border-block-end: 1px solid var(--np-color-on-surface-variant);
|
|
256
|
-
transition:
|
|
257
|
-
border-color var(--easing-fast),
|
|
258
|
-
border-width var(--easing-fast);
|
|
259
262
|
}
|
|
260
263
|
|
|
261
264
|
.np-select-container:focus-within .np-select-filled {
|
|
@@ -301,20 +304,10 @@
|
|
|
301
304
|
transform: translateY(0.5rem);
|
|
302
305
|
}
|
|
303
306
|
|
|
304
|
-
.animate-label label {
|
|
305
|
-
transition-property: font-size;
|
|
306
|
-
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
307
|
-
transition-duration: 150ms;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
307
|
.np-select-container:focus-within label {
|
|
311
308
|
color: var(--np-color-primary);
|
|
312
309
|
}
|
|
313
310
|
|
|
314
|
-
.animate-label:not(.is-empty) .np-select-outline label {
|
|
315
|
-
animation: slideUpOutline 150ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
311
|
@keyframes slideUpOutline {
|
|
319
312
|
from {
|
|
320
313
|
transform: translateY(1rem);
|
|
@@ -324,10 +317,6 @@
|
|
|
324
317
|
}
|
|
325
318
|
}
|
|
326
319
|
|
|
327
|
-
.animate-label:not(.is-empty) .np-select-filled label {
|
|
328
|
-
animation: slideUpFilled 150ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
320
|
@keyframes slideUpFilled {
|
|
332
321
|
from {
|
|
333
322
|
transform: translateY(1.25rem);
|
|
@@ -344,10 +333,6 @@
|
|
|
344
333
|
position: absolute;
|
|
345
334
|
}
|
|
346
335
|
|
|
347
|
-
.is-empty.animate-label .np-select-outline label {
|
|
348
|
-
animation: slideDownOutline 150ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
336
|
@keyframes slideDownOutline {
|
|
352
337
|
from {
|
|
353
338
|
transform: translateY(-1.5rem);
|
|
@@ -362,10 +347,6 @@
|
|
|
362
347
|
transform: translateY(1.25rem);
|
|
363
348
|
}
|
|
364
349
|
|
|
365
|
-
.is-empty.animate-label .np-select-filled label {
|
|
366
|
-
animation: slideDownFilled 150ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
350
|
@keyframes slideDownFilled {
|
|
370
351
|
from {
|
|
371
352
|
transform: translateY(0.5rem);
|
|
@@ -428,4 +409,47 @@
|
|
|
428
409
|
.disabled .np-select-outline {
|
|
429
410
|
border-color: color-mix(in srgb, var(--np-color-on-surface) 12%, transparent);
|
|
430
411
|
}
|
|
412
|
+
|
|
413
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
414
|
+
::picker(select) {
|
|
415
|
+
transition:
|
|
416
|
+
opacity var(--np-motion-expressive-fast-effects),
|
|
417
|
+
scale var(--np-motion-expressive-fast-spatial),
|
|
418
|
+
display 150ms allow-discrete,
|
|
419
|
+
overlay 150ms allow-discrete;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
select:open::picker(select) {
|
|
423
|
+
@starting-style {
|
|
424
|
+
opacity: 0;
|
|
425
|
+
scale: 0.8;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.arrow {
|
|
430
|
+
transition: rotate var(--easing-fast);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.animate-label label {
|
|
434
|
+
transition-property: font-size;
|
|
435
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
436
|
+
transition-duration: 150ms;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.animate-label:not(.is-empty) .np-select-outline label {
|
|
440
|
+
animation: slideUpOutline 150ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.animate-label:not(.is-empty) .np-select-filled label {
|
|
444
|
+
animation: slideUpFilled 150ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.is-empty.animate-label .np-select-outline label {
|
|
448
|
+
animation: slideDownOutline 150ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
.is-empty.animate-label .np-select-filled label {
|
|
452
|
+
animation: slideDownFilled 150ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
431
455
|
</style>
|
|
@@ -59,7 +59,10 @@
|
|
|
59
59
|
outline-width: 3px;
|
|
60
60
|
outline-offset: -3px;
|
|
61
61
|
border-radius: var(--np-shape-corner-extra-small);
|
|
62
|
-
|
|
62
|
+
|
|
63
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
64
|
+
animation: focusAnimationInset var(--np-motion-expressive-slow-effects) forwards;
|
|
65
|
+
}
|
|
63
66
|
}
|
|
64
67
|
}
|
|
65
68
|
</style>
|
|
@@ -808,7 +808,6 @@
|
|
|
808
808
|
|
|
809
809
|
.icon .arrow {
|
|
810
810
|
display: flex;
|
|
811
|
-
transition: rotate 150ms cubic-bezier(0.2, 0, 0, 1);
|
|
812
811
|
}
|
|
813
812
|
.field.menu-open .icon .arrow {
|
|
814
813
|
rotate: 180deg;
|
|
@@ -949,9 +948,7 @@
|
|
|
949
948
|
inset-inline-start: var(--floating-label-left, 0);
|
|
950
949
|
}
|
|
951
950
|
.label {
|
|
952
|
-
transition
|
|
953
|
-
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
954
|
-
transition-duration: 150ms;
|
|
951
|
+
transition: color 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
955
952
|
box-sizing: border-box;
|
|
956
953
|
color: var(--np-color-on-surface-variant);
|
|
957
954
|
overflow: hidden;
|
|
@@ -1138,4 +1135,16 @@
|
|
|
1138
1135
|
.disabled .outline-notch {
|
|
1139
1136
|
opacity: 0.12;
|
|
1140
1137
|
}
|
|
1138
|
+
|
|
1139
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
1140
|
+
.icon .arrow {
|
|
1141
|
+
transition: rotate 150ms cubic-bezier(0.2, 0, 0, 1);
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
.label {
|
|
1145
|
+
transition-property: all;
|
|
1146
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
1147
|
+
transition-duration: 150ms;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1141
1150
|
</style>
|
|
@@ -138,7 +138,12 @@
|
|
|
138
138
|
|
|
139
139
|
.np-snackbar:popover-open {
|
|
140
140
|
opacity: 1;
|
|
141
|
-
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
144
|
+
.np-snackbar:popover-open {
|
|
145
|
+
animation: slideIn var(--np-motion-expressive-default-spatial);
|
|
146
|
+
}
|
|
142
147
|
}
|
|
143
148
|
|
|
144
149
|
@keyframes slideIn {
|
package/dist/tabs/Tab.svelte
CHANGED
|
@@ -148,10 +148,11 @@
|
|
|
148
148
|
padding: 0 1rem;
|
|
149
149
|
color: var(--np-color-on-surface-variant);
|
|
150
150
|
height: 3rem;
|
|
151
|
-
transition: color
|
|
151
|
+
transition: color var(--np-motion-expressive-fast-effects);
|
|
152
152
|
}
|
|
153
153
|
.np-tab-content-active {
|
|
154
154
|
--_focus-bottom: 4px;
|
|
155
|
+
transition: color var(--np-motion-expressive-default-effects);
|
|
155
156
|
}
|
|
156
157
|
.np-tab-content-active.primary {
|
|
157
158
|
color: var(--np-color-primary);
|
|
@@ -215,7 +216,6 @@
|
|
|
215
216
|
inset-inline: 0;
|
|
216
217
|
bottom: var(--_focus-bottom, 0);
|
|
217
218
|
border-radius: var(--np-shape-corner-medium);
|
|
218
|
-
transition: height 0.3s ease;
|
|
219
219
|
pointer-events: none;
|
|
220
220
|
}
|
|
221
221
|
.np-tab:focus-visible {
|
|
@@ -227,6 +227,15 @@
|
|
|
227
227
|
outline-color: var(--np-color-secondary);
|
|
228
228
|
outline-width: 3px;
|
|
229
229
|
outline-offset: -3px;
|
|
230
|
-
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
233
|
+
.focus-area {
|
|
234
|
+
transition: height 0.3s ease;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.np-tab:focus-visible .focus-area {
|
|
238
|
+
animation: focusAnimationInset var(--np-motion-expressive-slow-effects) forwards;
|
|
239
|
+
}
|
|
231
240
|
}
|
|
232
241
|
</style>
|
package/dist/tabs/Tabs.svelte
CHANGED
|
@@ -80,7 +80,10 @@
|
|
|
80
80
|
border-start-start-radius: var(--np-indicator-radius, var(--np-shape-corner-full));
|
|
81
81
|
border-start-end-radius: var(--np-indicator-radius, var(--np-shape-corner-full));
|
|
82
82
|
position-anchor: --np-tab-indicator;
|
|
83
|
-
|
|
83
|
+
|
|
84
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
85
|
+
transition: var(--np-motion-expressive-default-spatial);
|
|
86
|
+
}
|
|
84
87
|
}
|
|
85
88
|
}
|
|
86
89
|
</style>
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
populated = false,
|
|
19
19
|
inputElement = $bindable(),
|
|
20
20
|
placeholder = ' ',
|
|
21
|
+
minLines = 1,
|
|
22
|
+
maxLines = 4,
|
|
21
23
|
children,
|
|
22
24
|
focused = $bindable(false),
|
|
23
25
|
clientWidth = $bindable(),
|
|
@@ -31,11 +33,13 @@
|
|
|
31
33
|
|
|
32
34
|
<label
|
|
33
35
|
style={(variant === 'outlined'
|
|
34
|
-
? '--_label-text-color:var(--np-outlined-text-field-label-text-color);--top-space:1rem;--bottom-space:1rem;--floating-label-top:-0.5rem;--floating-label-inline-start:-2.25rem
|
|
36
|
+
? '--_label-text-color:var(--np-outlined-text-field-label-text-color);--top-space:1rem;--bottom-space:1rem;--floating-label-top:-0.5rem;--floating-label-inline-start:-2.25rem;'
|
|
35
37
|
: !label?.length
|
|
36
38
|
? '--_label-text-color:var(--np-filled-text-field-label-text-color);--np-input-chip-outline-color:var(--np-color-outline);--top-space:1rem;--bottom-space:1rem; '
|
|
37
39
|
: '--_label-text-color:var(--np-filled-text-field-label-text-color);--np-input-chip-outline-color:var(--np-color-outline); ' +
|
|
38
|
-
(children ? '--top-space:2rem;--bottom-space:1rem;' : '')) +
|
|
40
|
+
(children ? '--top-space:2rem;--bottom-space:1rem;' : '')) +
|
|
41
|
+
`--_min-height:calc(${minLines} * 1lh);--_max-height:${`calc(${maxLines} * 1lh)`};` +
|
|
42
|
+
style}
|
|
39
43
|
class={['text-field', attributes.class]}
|
|
40
44
|
bind:this={element}
|
|
41
45
|
bind:clientWidth
|
|
@@ -43,7 +47,6 @@
|
|
|
43
47
|
>
|
|
44
48
|
<div
|
|
45
49
|
class="field"
|
|
46
|
-
class:resizable={attributes.type === 'textarea'}
|
|
47
50
|
class:no-label={!label?.length}
|
|
48
51
|
class:with-start={start}
|
|
49
52
|
class:with-end={end}
|
|
@@ -109,8 +112,7 @@
|
|
|
109
112
|
bind:focused
|
|
110
113
|
bind:value
|
|
111
114
|
bind:this={inputElement}
|
|
112
|
-
class="input"
|
|
113
|
-
rows={attributes.rows || 2}></textarea>
|
|
115
|
+
class="input"></textarea>
|
|
114
116
|
{:else}
|
|
115
117
|
<div class="input-wrapper">
|
|
116
118
|
{#if suffixText}
|
|
@@ -272,7 +274,6 @@
|
|
|
272
274
|
}
|
|
273
275
|
.text-field {
|
|
274
276
|
display: inline-flex;
|
|
275
|
-
resize: both;
|
|
276
277
|
text-align: start;
|
|
277
278
|
}
|
|
278
279
|
:global(label) {
|
|
@@ -324,11 +325,6 @@
|
|
|
324
325
|
background: var(--np-color-on-surface);
|
|
325
326
|
opacity: 0.08;
|
|
326
327
|
}
|
|
327
|
-
.resizable .np-container > * {
|
|
328
|
-
top: var(--_focus-outline-width, 3px);
|
|
329
|
-
inset-inline-start: var(--_focus-outline-width, 0);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
328
|
.content * {
|
|
333
329
|
all: unset;
|
|
334
330
|
color: currentColor;
|
|
@@ -418,6 +414,11 @@
|
|
|
418
414
|
.content textarea {
|
|
419
415
|
margin-top: var(--top-space, 1.5rem);
|
|
420
416
|
margin-bottom: var(--bottom-space, 0.5rem);
|
|
417
|
+
field-sizing: content;
|
|
418
|
+
min-inline-size: 20ch;
|
|
419
|
+
max-inline-size: 100%;
|
|
420
|
+
min-height: var(--_min-height, 1lh);
|
|
421
|
+
max-height: var(--_max-height, 4lh);
|
|
421
422
|
}
|
|
422
423
|
|
|
423
424
|
.content .input-wrapper .input,
|
|
@@ -587,7 +588,7 @@
|
|
|
587
588
|
inset-inline-start: var(--floating-label-inline-start, 0);
|
|
588
589
|
}
|
|
589
590
|
.label {
|
|
590
|
-
transition:
|
|
591
|
+
transition: color var(--np-motion-expressive-fast-effects);
|
|
591
592
|
box-sizing: border-box;
|
|
592
593
|
color: var(--np-color-on-surface-variant);
|
|
593
594
|
overflow: hidden;
|
|
@@ -627,10 +628,6 @@
|
|
|
627
628
|
.disabled .label:not(.np-hidden) {
|
|
628
629
|
opacity: 0.38;
|
|
629
630
|
}
|
|
630
|
-
.resizable:not(.disabled) .np-container {
|
|
631
|
-
resize: inherit;
|
|
632
|
-
overflow: hidden;
|
|
633
|
-
}
|
|
634
631
|
.disabled.no-label .content,
|
|
635
632
|
.disabled:has(input:-webkit-autofill) .content,
|
|
636
633
|
.disabled:has(input:not(:placeholder-shown)) .content,
|
|
@@ -638,15 +635,6 @@
|
|
|
638
635
|
.disabled.populated .content {
|
|
639
636
|
opacity: 0.38;
|
|
640
637
|
}
|
|
641
|
-
.field,
|
|
642
|
-
.container-overflow {
|
|
643
|
-
resize: inherit;
|
|
644
|
-
}
|
|
645
|
-
.resizable .np-container {
|
|
646
|
-
bottom: 3px;
|
|
647
|
-
inset-inline-end: var(--_focus-outline-width, 0);
|
|
648
|
-
clip-path: inset(3px 0 0 var(--_focus-outline-width));
|
|
649
|
-
}
|
|
650
638
|
.outline-start,
|
|
651
639
|
.outline-end {
|
|
652
640
|
border: inherit;
|
|
@@ -805,4 +793,10 @@
|
|
|
805
793
|
.disabled .outline-notch {
|
|
806
794
|
opacity: 0.12;
|
|
807
795
|
}
|
|
796
|
+
|
|
797
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
798
|
+
.label {
|
|
799
|
+
transition: all var(--np-motion-expressive-fast-effects);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
808
802
|
</style>
|
|
@@ -26,10 +26,14 @@ export interface InputFieldProps extends HTMLInputAttributes, FieldProps {
|
|
|
26
26
|
}
|
|
27
27
|
export interface TextAreaFieldProps extends HTMLTextareaAttributes, FieldProps {
|
|
28
28
|
type: 'textarea';
|
|
29
|
+
minLines?: number;
|
|
30
|
+
maxLines?: number;
|
|
29
31
|
}
|
|
30
32
|
export interface TextFieldProps extends HTMLAttributes<TextFieldElement>, Omit<HTMLInputAttributes, keyof HTMLAttributes<HTMLInputElement> | 'type' | 'value' | 'defaultValue' | 'defaultvalue'>, Omit<HTMLTextareaAttributes, keyof HTMLAttributes<HTMLTextAreaElement> | 'value' | 'defaultValue' | 'defaultvalue'>, FieldProps {
|
|
31
33
|
type?: TextFieldType | 'textarea';
|
|
32
34
|
value?: string | number | null;
|
|
33
35
|
defaultValue?: string | number | null;
|
|
36
|
+
minLines?: number;
|
|
37
|
+
maxLines?: number;
|
|
34
38
|
}
|
|
35
39
|
export {};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { RichTooltipProps } from './types.js'
|
|
3
|
+
|
|
4
|
+
let {
|
|
5
|
+
children,
|
|
6
|
+
subhead,
|
|
7
|
+
actions,
|
|
8
|
+
open = $bindable(),
|
|
9
|
+
element = $bindable(),
|
|
10
|
+
id,
|
|
11
|
+
ontoggle,
|
|
12
|
+
...attributes
|
|
13
|
+
}: RichTooltipProps = $props()
|
|
14
|
+
|
|
15
|
+
const findControl = () =>
|
|
16
|
+
id ? (document.querySelector<HTMLElement>(`[popovertarget="${id}"]`) ?? undefined) : undefined
|
|
17
|
+
|
|
18
|
+
export const showPopover = () => {
|
|
19
|
+
if (!element || element.matches(':popover-open')) return
|
|
20
|
+
const source = findControl()
|
|
21
|
+
element.showPopover(source ? { source } : undefined)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const hidePopover = () => {
|
|
25
|
+
element?.hidePopover()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
$effect(() => {
|
|
29
|
+
if (!element) return
|
|
30
|
+
if (open === true) showPopover()
|
|
31
|
+
else if (open === false) hidePopover()
|
|
32
|
+
})
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<div
|
|
36
|
+
{...attributes}
|
|
37
|
+
{id}
|
|
38
|
+
class={[
|
|
39
|
+
'np-rich-tooltip',
|
|
40
|
+
subhead && 'np-rich-tooltip-with-subhead',
|
|
41
|
+
actions && 'np-rich-tooltip-with-actions',
|
|
42
|
+
attributes.class,
|
|
43
|
+
]}
|
|
44
|
+
role="tooltip"
|
|
45
|
+
popover="auto"
|
|
46
|
+
bind:this={element}
|
|
47
|
+
ontoggle={(event) => {
|
|
48
|
+
let { newState } = event
|
|
49
|
+
open = newState === 'open'
|
|
50
|
+
ontoggle?.(event)
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
{#if subhead}
|
|
54
|
+
<div class="np-rich-tooltip-subhead">{subhead}</div>
|
|
55
|
+
{/if}
|
|
56
|
+
{#if children}
|
|
57
|
+
<div class="np-rich-tooltip-text">{@render children()}</div>
|
|
58
|
+
{/if}
|
|
59
|
+
{#if actions}
|
|
60
|
+
<div class="np-rich-tooltip-actions">{@render actions()}</div>
|
|
61
|
+
{/if}
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<style>
|
|
65
|
+
.np-rich-tooltip[popover] {
|
|
66
|
+
box-sizing: border-box;
|
|
67
|
+
width: max-content;
|
|
68
|
+
max-width: 20rem;
|
|
69
|
+
word-wrap: break-word;
|
|
70
|
+
overflow-wrap: break-word;
|
|
71
|
+
margin: 4px 0;
|
|
72
|
+
padding: 0.25rem 1rem;
|
|
73
|
+
border: none;
|
|
74
|
+
border-radius: var(--np-shape-corner-medium);
|
|
75
|
+
background: var(--np-color-surface-container);
|
|
76
|
+
color: var(--np-color-on-surface-variant);
|
|
77
|
+
box-shadow: var(--np-elevation-2);
|
|
78
|
+
font-size: 0.875rem;
|
|
79
|
+
line-height: 1.25rem;
|
|
80
|
+
justify-self: var(--np-rich-tooltip-justify-self, anchor-center);
|
|
81
|
+
position-area: var(--np-rich-tooltip-position-area, bottom);
|
|
82
|
+
position-try-fallbacks: flip-block;
|
|
83
|
+
}
|
|
84
|
+
.np-rich-tooltip-with-subhead[popover] {
|
|
85
|
+
padding-block: 0.75rem 1rem;
|
|
86
|
+
}
|
|
87
|
+
.np-rich-tooltip-with-actions[popover] {
|
|
88
|
+
padding-bottom: 0.5rem;
|
|
89
|
+
}
|
|
90
|
+
.np-rich-tooltip-subhead {
|
|
91
|
+
margin-bottom: 0.25rem;
|
|
92
|
+
font-weight: 500;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.np-rich-tooltip-actions {
|
|
96
|
+
display: flex;
|
|
97
|
+
flex-wrap: wrap;
|
|
98
|
+
align-items: center;
|
|
99
|
+
gap: 0.5rem;
|
|
100
|
+
min-height: 2.25rem;
|
|
101
|
+
margin-top: 1rem;
|
|
102
|
+
margin-inline-start: calc(-1 * var(--np-rich-tooltip-action-inset, 1rem));
|
|
103
|
+
padding-inline-end: var(--np-rich-tooltip-action-inset, 1rem);
|
|
104
|
+
}
|
|
105
|
+
.np-rich-tooltip:popover-open {
|
|
106
|
+
opacity: 1;
|
|
107
|
+
scale: 1;
|
|
108
|
+
}
|
|
109
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
110
|
+
.np-rich-tooltip:popover-open {
|
|
111
|
+
animation:
|
|
112
|
+
fadeIn var(--np-motion-expressive-fast-effects),
|
|
113
|
+
scaleIn var(--np-motion-expressive-fast-spatial);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@keyframes fadeIn {
|
|
118
|
+
from {
|
|
119
|
+
opacity: 0;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
@keyframes scaleIn {
|
|
123
|
+
from {
|
|
124
|
+
scale: 0.8;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RichTooltipProps } from './types.ts';
|
|
2
|
+
declare const RichTooltip: import("svelte").Component<RichTooltipProps, {
|
|
3
|
+
showPopover: () => void;
|
|
4
|
+
hidePopover: () => void;
|
|
5
|
+
}, "element" | "open">;
|
|
6
|
+
type RichTooltip = ReturnType<typeof RichTooltip>;
|
|
7
|
+
export default RichTooltip;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import '../internal/interest.css'
|
|
2
3
|
import { on } from 'svelte/events'
|
|
3
4
|
import { MediaQuery } from 'svelte/reactivity'
|
|
4
5
|
import type { TooltipProps } from './types.js'
|
|
@@ -14,16 +15,33 @@
|
|
|
14
15
|
|
|
15
16
|
let isTouch = new MediaQuery('(hover: none) and (pointer: coarse)', false)
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const isInterestInvoker = (anchor: Element) =>
|
|
19
|
+
'interestForElement' in anchor &&
|
|
20
|
+
(!(anchor instanceof HTMLAnchorElement || anchor instanceof HTMLAreaElement) ||
|
|
21
|
+
anchor.hasAttribute('href'))
|
|
22
|
+
|
|
23
|
+
let native = $state(false)
|
|
24
|
+
|
|
25
|
+
const attachAnchor = (el: HTMLDivElement) => {
|
|
26
|
+
if (!id) return
|
|
27
|
+
const anchor = document.querySelector<HTMLElement>(`[aria-describedby="${id}"]`)
|
|
20
28
|
if (!anchor) return
|
|
29
|
+
if (isInterestInvoker(anchor)) {
|
|
30
|
+
native = true
|
|
31
|
+
const wired = anchor.getAttribute('interestfor') === id
|
|
32
|
+
if (!wired) anchor.setAttribute('interestfor', id)
|
|
33
|
+
return () => {
|
|
34
|
+
native = false
|
|
35
|
+
if (!wired) anchor.removeAttribute('interestfor')
|
|
36
|
+
}
|
|
37
|
+
}
|
|
21
38
|
const anchorName = anchor.style.getPropertyValue('anchor-name')
|
|
22
39
|
const generatedId = anchorName || `--${uid}`
|
|
23
40
|
el.style.setProperty('position-anchor', generatedId)
|
|
24
41
|
if (!anchorName) {
|
|
25
42
|
anchor.style.setProperty('anchor-name', generatedId)
|
|
26
43
|
}
|
|
44
|
+
if (isTouch.current) return
|
|
27
45
|
const mouseEnter = on(anchor, 'mouseenter', onAnchorEnter)
|
|
28
46
|
const mouseLeave = on(anchor, 'mouseleave', onAnchorLeave)
|
|
29
47
|
const focus = on(anchor, 'focus', onAnchorFocus)
|
|
@@ -93,6 +111,7 @@
|
|
|
93
111
|
}
|
|
94
112
|
|
|
95
113
|
$effect(() => {
|
|
114
|
+
if (native) return
|
|
96
115
|
const off = on(document, 'keydown', onEscape)
|
|
97
116
|
return () => {
|
|
98
117
|
off()
|
|
@@ -101,25 +120,23 @@
|
|
|
101
120
|
})
|
|
102
121
|
</script>
|
|
103
122
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
</div>
|
|
122
|
-
{/if}
|
|
123
|
+
<div
|
|
124
|
+
{...attributes}
|
|
125
|
+
{id}
|
|
126
|
+
{@attach attachAnchor}
|
|
127
|
+
class={['np-tooltip', attributes.class]}
|
|
128
|
+
role="tooltip"
|
|
129
|
+
popover="hint"
|
|
130
|
+
bind:this={element}
|
|
131
|
+
onmouseenter={native ? undefined : onTooltipEnter}
|
|
132
|
+
onmouseleave={native ? undefined : onTooltipLeave}
|
|
133
|
+
ontoggle={(event) => {
|
|
134
|
+
let { newState } = event
|
|
135
|
+
open = newState === 'open'
|
|
136
|
+
}}
|
|
137
|
+
>
|
|
138
|
+
{#if children}{@render children()}{/if}
|
|
139
|
+
</div>
|
|
123
140
|
|
|
124
141
|
<style>
|
|
125
142
|
.np-tooltip[popover] {
|
|
@@ -141,15 +158,24 @@
|
|
|
141
158
|
}
|
|
142
159
|
.np-tooltip:popover-open {
|
|
143
160
|
opacity: 1;
|
|
144
|
-
|
|
161
|
+
scale: 1;
|
|
162
|
+
}
|
|
163
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
164
|
+
.np-tooltip:popover-open {
|
|
165
|
+
animation:
|
|
166
|
+
fadeIn var(--np-motion-expressive-fast-effects),
|
|
167
|
+
scaleIn var(--np-motion-expressive-fast-spatial);
|
|
168
|
+
}
|
|
145
169
|
}
|
|
146
170
|
|
|
147
|
-
@keyframes
|
|
171
|
+
@keyframes fadeIn {
|
|
148
172
|
from {
|
|
149
|
-
|
|
173
|
+
opacity: 0;
|
|
150
174
|
}
|
|
151
|
-
|
|
152
|
-
|
|
175
|
+
}
|
|
176
|
+
@keyframes scaleIn {
|
|
177
|
+
from {
|
|
178
|
+
scale: 0.8;
|
|
153
179
|
}
|
|
154
180
|
}
|
|
155
181
|
</style>
|
package/dist/tooltip/index.d.ts
CHANGED
package/dist/tooltip/index.js
CHANGED
package/dist/tooltip/types.d.ts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
1
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
declare module 'svelte/elements' {
|
|
4
|
+
interface HTMLAnchorAttributes {
|
|
5
|
+
interestfor?: string | undefined | null;
|
|
6
|
+
}
|
|
7
|
+
interface HTMLButtonAttributes {
|
|
8
|
+
interestfor?: string | undefined | null;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
2
11
|
export interface TooltipProps extends Omit<HTMLAttributes<HTMLDivElement>, 'role'> {
|
|
3
12
|
element?: HTMLDivElement;
|
|
4
13
|
open?: boolean;
|
|
5
14
|
}
|
|
15
|
+
export interface RichTooltipProps extends Omit<HTMLAttributes<HTMLDivElement>, 'role' | 'popover'> {
|
|
16
|
+
subhead?: string;
|
|
17
|
+
actions?: Snippet;
|
|
18
|
+
element?: HTMLDivElement;
|
|
19
|
+
open?: boolean;
|
|
20
|
+
}
|