noph-ui 0.18.2 → 0.18.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/dist/autocomplete/AutoComplete.svelte +1 -1
- package/dist/chip/ChipSet.svelte +17 -2
- package/dist/chip/FilterChip.svelte +13 -1
- package/dist/chip/InputChip.svelte +11 -3
- package/dist/chip/types.d.ts +7 -0
- package/dist/menu/Menu.svelte +10 -7
- package/dist/ripple/Ripple.svelte +13 -1
- package/dist/select/Select.svelte +9 -3
- package/dist/text-field/TextField.svelte +75 -49
- package/dist/tooltip/Tooltip.svelte +28 -15
- package/package.json +9 -9
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
const uid = $props.id()
|
|
32
32
|
let defaultOptionsFilter = (option: AutoCompleteOption) => {
|
|
33
|
-
return !value || option.label.includes(value)
|
|
33
|
+
return !value || option.label.toLocaleLowerCase().includes(value.toLocaleLowerCase())
|
|
34
34
|
}
|
|
35
35
|
let displayOptions = $derived(options.filter(optionsFilter || defaultOptionsFilter))
|
|
36
36
|
let useVirtualList = $derived(displayOptions.length > 4000)
|
package/dist/chip/ChipSet.svelte
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { setContext } from 'svelte'
|
|
3
|
+
import type { ChipSetContext, ChipSetProps } from './types.ts'
|
|
3
4
|
|
|
4
5
|
let { children, ...attributes }: ChipSetProps = $props()
|
|
6
|
+
let chipSet: ChipSetContext = $state({
|
|
7
|
+
chips: [],
|
|
8
|
+
})
|
|
9
|
+
setContext('chipSet', chipSet)
|
|
5
10
|
</script>
|
|
6
11
|
|
|
7
12
|
{#if children}
|
|
8
|
-
<div
|
|
13
|
+
<div
|
|
14
|
+
class={['np-chip-set', chipSet.chips.length > 0 && 'np-chip-set-has-chips', attributes.class]}
|
|
15
|
+
style={attributes.style}
|
|
16
|
+
role="toolbar"
|
|
17
|
+
>
|
|
9
18
|
{@render children()}
|
|
10
19
|
</div>
|
|
11
20
|
{/if}
|
|
12
21
|
|
|
13
22
|
<style>
|
|
23
|
+
.np-chip-set-has-chips {
|
|
24
|
+
margin-right: 0.5rem;
|
|
25
|
+
padding-block: 2px;
|
|
26
|
+
padding-right: 2px;
|
|
27
|
+
}
|
|
14
28
|
.np-chip-set {
|
|
15
29
|
display: flex;
|
|
16
30
|
flex-wrap: wrap;
|
|
17
31
|
gap: 0.5rem;
|
|
32
|
+
overflow: auto;
|
|
18
33
|
align-items: center;
|
|
19
34
|
min-width: 0;
|
|
20
35
|
}
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import CheckIcon from '../icons/CheckIcon.svelte'
|
|
4
4
|
import CloseIcon from '../icons/CloseIcon.svelte'
|
|
5
5
|
import Ripple from '../ripple/Ripple.svelte'
|
|
6
|
-
import
|
|
6
|
+
import { getContext, onMount } from 'svelte'
|
|
7
|
+
import type { ChipSetContext, FilterChipProps } from './types.ts'
|
|
7
8
|
|
|
8
9
|
let {
|
|
9
10
|
selected = $bindable(),
|
|
@@ -23,6 +24,17 @@
|
|
|
23
24
|
}: FilterChipProps = $props()
|
|
24
25
|
|
|
25
26
|
let chipLabel: HTMLLabelElement | undefined = $state()
|
|
27
|
+
let chipSet: ChipSetContext = getContext('chipSet')
|
|
28
|
+
|
|
29
|
+
onMount(() => {
|
|
30
|
+
chipSet.chips.push({ label: label, name: name, value: value })
|
|
31
|
+
return () => {
|
|
32
|
+
const index = chipSet.chips.findIndex((chip) => chip.value === value)
|
|
33
|
+
if (index !== -1) {
|
|
34
|
+
chipSet.chips.splice(index, 1)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
})
|
|
26
38
|
|
|
27
39
|
$effect(() => {
|
|
28
40
|
if (group && value) {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import IconButton from '../button/IconButton.svelte'
|
|
3
3
|
import CloseIcon from '../icons/CloseIcon.svelte'
|
|
4
4
|
import Ripple from '../ripple/Ripple.svelte'
|
|
5
|
-
import { onMount } from 'svelte'
|
|
6
|
-
import type { InputChipProps } from './types.ts'
|
|
5
|
+
import { getContext, onMount } from 'svelte'
|
|
6
|
+
import type { ChipSetContext, InputChipProps } from './types.ts'
|
|
7
7
|
|
|
8
8
|
let {
|
|
9
9
|
selected = $bindable(),
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
let chipLabel: HTMLDivElement | undefined = $state()
|
|
22
22
|
let visible = $state(false)
|
|
23
|
+
let chipSet: ChipSetContext = getContext('chipSet')
|
|
23
24
|
|
|
24
25
|
onMount(() => {
|
|
25
26
|
const observer = new IntersectionObserver((entries) => {
|
|
@@ -34,8 +35,15 @@
|
|
|
34
35
|
if (element) {
|
|
35
36
|
observer.observe(element)
|
|
36
37
|
}
|
|
38
|
+
chipSet.chips.push({ label: label, name: name, value: value })
|
|
37
39
|
|
|
38
|
-
return () =>
|
|
40
|
+
return () => {
|
|
41
|
+
observer.disconnect()
|
|
42
|
+
const index = chipSet.chips.findIndex((chip) => chip.value === value)
|
|
43
|
+
if (index !== -1) {
|
|
44
|
+
chipSet.chips.splice(index, 1)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
39
47
|
})
|
|
40
48
|
</script>
|
|
41
49
|
|
package/dist/chip/types.d.ts
CHANGED
|
@@ -46,4 +46,11 @@ export interface InputChipProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
46
46
|
currentTarget: EventTarget & HTMLButtonElement;
|
|
47
47
|
}) => void;
|
|
48
48
|
}
|
|
49
|
+
export interface ChipSetContext {
|
|
50
|
+
chips: {
|
|
51
|
+
label: string;
|
|
52
|
+
name: string | undefined;
|
|
53
|
+
value: string | number | undefined;
|
|
54
|
+
}[];
|
|
55
|
+
}
|
|
49
56
|
export {};
|
package/dist/menu/Menu.svelte
CHANGED
|
@@ -78,6 +78,10 @@
|
|
|
78
78
|
return window
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
const onScroll = () => {
|
|
82
|
+
refreshValues()
|
|
83
|
+
}
|
|
84
|
+
|
|
81
85
|
$effect(() => {
|
|
82
86
|
if (anchor && element) {
|
|
83
87
|
if (style) {
|
|
@@ -89,13 +93,7 @@
|
|
|
89
93
|
element?.style.setProperty(key, value)
|
|
90
94
|
})
|
|
91
95
|
}
|
|
92
|
-
getScrollableParent(element).addEventListener(
|
|
93
|
-
'scroll',
|
|
94
|
-
() => {
|
|
95
|
-
refreshValues()
|
|
96
|
-
},
|
|
97
|
-
{ passive: true },
|
|
98
|
-
)
|
|
96
|
+
getScrollableParent(element).addEventListener('scroll', onScroll, { passive: true })
|
|
99
97
|
if (
|
|
100
98
|
'anchorName' in document.documentElement.style &&
|
|
101
99
|
!anchor.style.getPropertyValue('anchor-name')
|
|
@@ -105,6 +103,11 @@
|
|
|
105
103
|
anchor.style.setProperty('anchor-name', generatedId)
|
|
106
104
|
}
|
|
107
105
|
}
|
|
106
|
+
return () => {
|
|
107
|
+
if (element) {
|
|
108
|
+
getScrollableParent(element).removeEventListener('scroll', onScroll)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
108
111
|
})
|
|
109
112
|
</script>
|
|
110
113
|
|
|
@@ -258,7 +258,7 @@
|
|
|
258
258
|
endPressAnimation()
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
const
|
|
261
|
+
const removeEvents = (el: HTMLElement) => {
|
|
262
262
|
el.removeEventListener('click', handleClick)
|
|
263
263
|
el.removeEventListener('contextmenu', handleContextmenu)
|
|
264
264
|
el.removeEventListener('pointercancel', handlePointercancel)
|
|
@@ -266,6 +266,10 @@
|
|
|
266
266
|
el.removeEventListener('pointerenter', handlePointerenter)
|
|
267
267
|
el.removeEventListener('pointerleave', handlePointerleave)
|
|
268
268
|
el.removeEventListener('pointerup', handlePointerup)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const addEvents = (el: HTMLElement) => {
|
|
272
|
+
removeEvents(el)
|
|
269
273
|
|
|
270
274
|
el.addEventListener('click', handleClick)
|
|
271
275
|
el.addEventListener('contextmenu', handleContextmenu)
|
|
@@ -285,6 +289,14 @@
|
|
|
285
289
|
addEvents(element)
|
|
286
290
|
}
|
|
287
291
|
}
|
|
292
|
+
return () => {
|
|
293
|
+
if (forElement) {
|
|
294
|
+
removeEvents(forElement)
|
|
295
|
+
}
|
|
296
|
+
if (element) {
|
|
297
|
+
removeEvents(element)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
288
300
|
})
|
|
289
301
|
</script>
|
|
290
302
|
|
|
@@ -102,11 +102,17 @@
|
|
|
102
102
|
errorTextRaw = errorText
|
|
103
103
|
selectElement?.setCustomValidity(error ? errorText : '')
|
|
104
104
|
})
|
|
105
|
+
const onReset = () => {
|
|
106
|
+
errorRaw = error
|
|
107
|
+
}
|
|
105
108
|
$effect(() => {
|
|
106
109
|
if (selectElement) {
|
|
107
|
-
selectElement.form?.addEventListener('reset',
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
selectElement.form?.addEventListener('reset', onReset)
|
|
111
|
+
}
|
|
112
|
+
return () => {
|
|
113
|
+
if (selectElement) {
|
|
114
|
+
selectElement.form?.removeEventListener('reset', onReset)
|
|
115
|
+
}
|
|
110
116
|
}
|
|
111
117
|
})
|
|
112
118
|
const handleOptionSelect = (event: Event, option: SelectOption) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { isFirstInvalidControlInForm } from './report-validity.js'
|
|
3
|
-
import type { FocusEventHandler } from 'svelte/elements'
|
|
3
|
+
import type { FocusEventHandler, EventHandler } from 'svelte/elements'
|
|
4
4
|
import type { TextFieldProps } from './types.ts'
|
|
5
5
|
|
|
6
6
|
let {
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
reportValidity = $bindable(),
|
|
23
23
|
checkValidity = $bindable(),
|
|
24
24
|
children,
|
|
25
|
+
oninput,
|
|
26
|
+
oninvalid,
|
|
25
27
|
onfocus,
|
|
26
28
|
onblur,
|
|
27
29
|
focused = $bindable(false),
|
|
@@ -60,39 +62,72 @@
|
|
|
60
62
|
inputElement?.setCustomValidity(error ? errorText : '')
|
|
61
63
|
})
|
|
62
64
|
|
|
65
|
+
const onReset = () => {
|
|
66
|
+
errorRaw = error
|
|
67
|
+
value = ''
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const onInputEvent = (
|
|
71
|
+
event: Event & {
|
|
72
|
+
currentTarget: (EventTarget & HTMLInputElement) | HTMLTextAreaElement
|
|
73
|
+
},
|
|
74
|
+
) => {
|
|
75
|
+
doValidity = true
|
|
76
|
+
;(oninput as EventHandler)?.(event)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const onInvalidEvent = (
|
|
80
|
+
event: Event & {
|
|
81
|
+
currentTarget: HTMLInputElement | HTMLTextAreaElement
|
|
82
|
+
},
|
|
83
|
+
) => {
|
|
84
|
+
event.preventDefault()
|
|
85
|
+
const { currentTarget } = event
|
|
86
|
+
errorRaw = true
|
|
87
|
+
if (errorText === '') {
|
|
88
|
+
errorTextRaw = currentTarget.validationMessage
|
|
89
|
+
}
|
|
90
|
+
if (focusOnInvalid && isFirstInvalidControlInForm(currentTarget.form, currentTarget)) {
|
|
91
|
+
currentTarget.focus()
|
|
92
|
+
}
|
|
93
|
+
;(oninvalid as EventHandler)?.(event)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const onFocusEvent = (
|
|
97
|
+
event: FocusEvent & {
|
|
98
|
+
currentTarget: EventTarget & (HTMLInputElement | HTMLTextAreaElement)
|
|
99
|
+
},
|
|
100
|
+
) => {
|
|
101
|
+
focused = true
|
|
102
|
+
;(onfocus as FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>)?.(event)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const onBlurEvent = (
|
|
106
|
+
event: FocusEvent & {
|
|
107
|
+
currentTarget: EventTarget & (HTMLInputElement | HTMLTextAreaElement)
|
|
108
|
+
},
|
|
109
|
+
) => {
|
|
110
|
+
focused = false
|
|
111
|
+
if (doValidity) {
|
|
112
|
+
focusOnInvalid = false
|
|
113
|
+
if (checkValidity()) {
|
|
114
|
+
errorRaw = error
|
|
115
|
+
errorTextRaw = errorText
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
focusOnInvalid = true
|
|
119
|
+
}
|
|
120
|
+
;(onblur as FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>)?.(event)
|
|
121
|
+
}
|
|
122
|
+
|
|
63
123
|
$effect(() => {
|
|
64
124
|
if (inputElement) {
|
|
65
|
-
inputElement.form?.addEventListener('reset',
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
})
|
|
72
|
-
inputElement.addEventListener('invalid', (event) => {
|
|
73
|
-
event.preventDefault()
|
|
74
|
-
const { currentTarget } = event as Event & {
|
|
75
|
-
currentTarget: HTMLInputElement | HTMLTextAreaElement
|
|
76
|
-
}
|
|
77
|
-
errorRaw = true
|
|
78
|
-
if (errorText === '') {
|
|
79
|
-
errorTextRaw = currentTarget.validationMessage
|
|
80
|
-
}
|
|
81
|
-
if (focusOnInvalid && isFirstInvalidControlInForm(currentTarget.form, currentTarget)) {
|
|
82
|
-
currentTarget.focus()
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
inputElement.addEventListener('blur', () => {
|
|
87
|
-
if (doValidity) {
|
|
88
|
-
focusOnInvalid = false
|
|
89
|
-
if (checkValidity()) {
|
|
90
|
-
errorRaw = error
|
|
91
|
-
errorTextRaw = errorText
|
|
92
|
-
}
|
|
93
|
-
focusOnInvalid = true
|
|
94
|
-
}
|
|
95
|
-
})
|
|
125
|
+
inputElement.form?.addEventListener('reset', onReset)
|
|
126
|
+
}
|
|
127
|
+
return () => {
|
|
128
|
+
if (inputElement) {
|
|
129
|
+
inputElement.form?.removeEventListener('reset', onReset)
|
|
130
|
+
}
|
|
96
131
|
}
|
|
97
132
|
})
|
|
98
133
|
</script>
|
|
@@ -175,14 +210,10 @@
|
|
|
175
210
|
<textarea
|
|
176
211
|
aria-label={label}
|
|
177
212
|
{...attributes}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
onblur={(event) => {
|
|
183
|
-
focused = false
|
|
184
|
-
;(onblur as FocusEventHandler<HTMLTextAreaElement>)?.(event)
|
|
185
|
-
}}
|
|
213
|
+
oninput={onInputEvent}
|
|
214
|
+
oninvalid={onInvalidEvent}
|
|
215
|
+
onfocus={onFocusEvent}
|
|
216
|
+
onblur={onBlurEvent}
|
|
186
217
|
bind:value
|
|
187
218
|
bind:this={inputElement}
|
|
188
219
|
class="input"
|
|
@@ -201,14 +232,10 @@
|
|
|
201
232
|
{...attributes}
|
|
202
233
|
bind:value
|
|
203
234
|
bind:this={inputElement}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
onblur={(event) => {
|
|
209
|
-
focused = false
|
|
210
|
-
;(onblur as FocusEventHandler<HTMLInputElement>)?.(event)
|
|
211
|
-
}}
|
|
235
|
+
oninput={onInputEvent}
|
|
236
|
+
oninvalid={onInvalidEvent}
|
|
237
|
+
onfocus={onFocusEvent}
|
|
238
|
+
onblur={onBlurEvent}
|
|
212
239
|
class="input"
|
|
213
240
|
aria-invalid={errorRaw}
|
|
214
241
|
/>
|
|
@@ -497,7 +524,6 @@
|
|
|
497
524
|
}
|
|
498
525
|
:global(.content .input-wrapper .np-chip-set) {
|
|
499
526
|
margin-top: calc(var(--top-space, 1.5rem) - 4px);
|
|
500
|
-
margin-right: 0.5rem;
|
|
501
527
|
}
|
|
502
528
|
|
|
503
529
|
.prefix {
|
|
@@ -41,6 +41,24 @@
|
|
|
41
41
|
return event.pointerType === 'touch'
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
const onPointerenter = (event: PointerEvent) => {
|
|
45
|
+
if (!isTouch(event)) {
|
|
46
|
+
element?.showPopover()
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const onPointerleave = (event: PointerEvent) => {
|
|
51
|
+
if (!isTouch(event)) {
|
|
52
|
+
element?.hidePopover()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const onPointerup = (event: PointerEvent) => {
|
|
57
|
+
if (!isTouch(event)) {
|
|
58
|
+
element?.hidePopover()
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
44
62
|
$effect(() => {
|
|
45
63
|
if (anchor && element) {
|
|
46
64
|
if ('anchorName' in document.documentElement.style) {
|
|
@@ -51,22 +69,17 @@
|
|
|
51
69
|
anchor.style.setProperty('anchor-name', generatedId)
|
|
52
70
|
}
|
|
53
71
|
}
|
|
54
|
-
anchor.addEventListener('pointerenter',
|
|
55
|
-
|
|
56
|
-
element?.showPopover()
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
anchor.addEventListener('pointerleave', (event: PointerEvent) => {
|
|
60
|
-
if (!isTouch(event)) {
|
|
61
|
-
element?.hidePopover()
|
|
62
|
-
}
|
|
63
|
-
})
|
|
72
|
+
anchor.addEventListener('pointerenter', onPointerenter)
|
|
73
|
+
anchor.addEventListener('pointerleave', onPointerleave)
|
|
64
74
|
if (!keepTooltipOnClick) {
|
|
65
|
-
anchor.addEventListener('pointerup',
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
anchor.addEventListener('pointerup', onPointerup)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return () => {
|
|
79
|
+
if (anchor) {
|
|
80
|
+
anchor.removeEventListener('pointerenter', onPointerenter)
|
|
81
|
+
anchor.removeEventListener('pointerleave', onPointerleave)
|
|
82
|
+
anchor.removeEventListener('pointerup', onPointerup)
|
|
70
83
|
}
|
|
71
84
|
}
|
|
72
85
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "noph-ui",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"homepage": "https://noph.dev",
|
|
6
6
|
"repository": {
|
|
@@ -55,25 +55,25 @@
|
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@eslint/js": "^9.29.0",
|
|
57
57
|
"@material/material-color-utilities": "^0.3.0",
|
|
58
|
-
"@playwright/test": "^1.53.
|
|
58
|
+
"@playwright/test": "^1.53.1",
|
|
59
59
|
"@sveltejs/adapter-vercel": "^5.7.2",
|
|
60
|
-
"@sveltejs/kit": "^2.
|
|
60
|
+
"@sveltejs/kit": "^2.22.0",
|
|
61
61
|
"@sveltejs/package": "^2.3.11",
|
|
62
62
|
"@sveltejs/vite-plugin-svelte": "^5.1.0",
|
|
63
63
|
"@types/eslint": "^9.6.1",
|
|
64
64
|
"eslint": "^9.29.0",
|
|
65
65
|
"eslint-config-prettier": "^10.1.5",
|
|
66
|
-
"eslint-plugin-svelte": "^3.9.
|
|
66
|
+
"eslint-plugin-svelte": "^3.9.3",
|
|
67
67
|
"globals": "^16.2.0",
|
|
68
|
-
"prettier": "^3.
|
|
68
|
+
"prettier": "^3.6.0",
|
|
69
69
|
"prettier-plugin-svelte": "^3.4.0",
|
|
70
70
|
"publint": "^0.3.12",
|
|
71
|
-
"svelte": "^5.34.
|
|
72
|
-
"svelte-check": "^4.2.
|
|
71
|
+
"svelte": "^5.34.7",
|
|
72
|
+
"svelte-check": "^4.2.2",
|
|
73
73
|
"typescript": "^5.8.3",
|
|
74
|
-
"typescript-eslint": "^8.
|
|
74
|
+
"typescript-eslint": "^8.35.0",
|
|
75
75
|
"vite": "^6.3.5",
|
|
76
|
-
"vitest": "^3.2.
|
|
76
|
+
"vitest": "^3.2.4"
|
|
77
77
|
},
|
|
78
78
|
"svelte": "./dist/index.js",
|
|
79
79
|
"types": "./dist/index.d.ts",
|