noph-ui 0.22.5 → 0.23.1
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/tabs/Tab.svelte +32 -40
- package/dist/tabs/Tab.svelte.d.ts +1 -1
- package/dist/tabs/Tabs.svelte +73 -12
- package/dist/tabs/types.d.ts +2 -1
- package/package.json +1 -1
package/dist/tabs/Tab.svelte
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import Ripple from '../ripple/Ripple.svelte'
|
|
3
|
-
import {
|
|
3
|
+
import { onMount } from 'svelte'
|
|
4
4
|
import type { TabProps } from './types.ts'
|
|
5
5
|
import Badge from '../badge/Badge.svelte'
|
|
6
6
|
|
|
@@ -15,49 +15,30 @@
|
|
|
15
15
|
variant = 'primary',
|
|
16
16
|
badge = false,
|
|
17
17
|
badgeLabel,
|
|
18
|
+
selected = $bindable(false),
|
|
18
19
|
...attributes
|
|
19
20
|
}: TabProps = $props()
|
|
20
|
-
let activeTab: { value: string | number; node: HTMLElement } = getContext('activeTab')
|
|
21
21
|
let element: HTMLElement | undefined = $state()
|
|
22
|
-
let
|
|
22
|
+
let id = $props.id()
|
|
23
|
+
let parentElement = $derived(element?.parentElement)
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
const onChange = (event: Event) => {
|
|
26
|
+
const { detail } = event as CustomEvent<{ id: string }>
|
|
27
|
+
selected = detail.id === id
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
onMount(() => {
|
|
31
|
+
element?.addEventListener('change', onChange)
|
|
32
|
+
return () => {
|
|
33
|
+
element?.removeEventListener('change', onChange)
|
|
32
34
|
}
|
|
33
35
|
})
|
|
34
36
|
|
|
35
37
|
const setTabActive = (el: HTMLElement) => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const oldIndicatorRect = oldIndicator?.getBoundingClientRect()
|
|
39
|
-
if (oldIndicatorRect) {
|
|
40
|
-
const newIndicator = el.querySelector<HTMLElement>('.np-indicator')
|
|
41
|
-
if (newIndicator) {
|
|
42
|
-
newIndicator.style.setProperty(
|
|
43
|
-
'--np-tab-indicator-start',
|
|
44
|
-
`${oldIndicatorRect.x - newIndicator.getBoundingClientRect().x}px`,
|
|
45
|
-
)
|
|
46
|
-
newIndicator.style.setProperty(
|
|
47
|
-
'--np-tab-indicator-scale',
|
|
48
|
-
`${oldIndicatorRect.width / newIndicator.clientWidth}`,
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
activeTab.value = value
|
|
53
|
-
activeTab.node = el
|
|
38
|
+
parentElement?.dispatchEvent(new CustomEvent('change', { detail: { id: el.id, value } }))
|
|
39
|
+
selected = true
|
|
54
40
|
}
|
|
55
41
|
|
|
56
|
-
const setActiveTab = (el: HTMLElement) => {
|
|
57
|
-
if (isActive) {
|
|
58
|
-
activeTab.node = el
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
42
|
const onClick = (event: MouseEvent & { currentTarget: EventTarget & HTMLElement }) => {
|
|
62
43
|
setTabActive(event.currentTarget)
|
|
63
44
|
if (onclick) {
|
|
@@ -72,6 +53,11 @@
|
|
|
72
53
|
onkeydown(event)
|
|
73
54
|
}
|
|
74
55
|
}
|
|
56
|
+
const setCheckInitialState = (el: HTMLElement) => {
|
|
57
|
+
if (parentElement?.getAttribute('data-value') === value) {
|
|
58
|
+
selected = true
|
|
59
|
+
}
|
|
60
|
+
}
|
|
75
61
|
</script>
|
|
76
62
|
|
|
77
63
|
{#snippet content()}
|
|
@@ -116,15 +102,18 @@
|
|
|
116
102
|
|
|
117
103
|
{#if href}
|
|
118
104
|
<a
|
|
119
|
-
{@attach
|
|
105
|
+
{@attach setCheckInitialState}
|
|
120
106
|
{...attributes}
|
|
121
|
-
|
|
107
|
+
{id}
|
|
108
|
+
tabindex={selected ? 0 : -1}
|
|
122
109
|
role="tab"
|
|
110
|
+
aria-selected={selected}
|
|
111
|
+
data-value={value}
|
|
123
112
|
bind:this={element}
|
|
124
113
|
{href}
|
|
125
114
|
class={[
|
|
126
115
|
'np-tab',
|
|
127
|
-
|
|
116
|
+
selected && 'np-tab-content-active',
|
|
128
117
|
variant === 'primary' ? 'primary' : 'secondary',
|
|
129
118
|
attributes.class,
|
|
130
119
|
]}
|
|
@@ -135,14 +124,17 @@
|
|
|
135
124
|
</a>
|
|
136
125
|
{:else}
|
|
137
126
|
<div
|
|
138
|
-
{@attach
|
|
127
|
+
{@attach setCheckInitialState}
|
|
139
128
|
{...attributes}
|
|
140
|
-
|
|
129
|
+
{id}
|
|
130
|
+
tabindex={selected ? 0 : -1}
|
|
141
131
|
role="tab"
|
|
132
|
+
aria-selected={selected}
|
|
133
|
+
data-value={value}
|
|
142
134
|
bind:this={element}
|
|
143
135
|
class={[
|
|
144
136
|
'np-tab',
|
|
145
|
-
|
|
137
|
+
selected && 'np-tab-content-active',
|
|
146
138
|
variant === 'primary' ? 'primary' : 'secondary',
|
|
147
139
|
attributes.class,
|
|
148
140
|
]}
|
package/dist/tabs/Tabs.svelte
CHANGED
|
@@ -1,32 +1,93 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import Divider from '../divider/Divider.svelte'
|
|
3
|
-
import {
|
|
3
|
+
import { onMount } from 'svelte'
|
|
4
4
|
import type { TabsProps } from './types.ts'
|
|
5
5
|
|
|
6
6
|
let { children, element = $bindable(), value = $bindable(), ...attributes }: TabsProps = $props()
|
|
7
|
-
let
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
})
|
|
11
|
-
setContext('activeTab', active)
|
|
7
|
+
let tabs: HTMLElement[] | undefined = $state()
|
|
8
|
+
let activeTab: HTMLElement | undefined = $state()
|
|
9
|
+
const initialValue = value
|
|
12
10
|
|
|
13
11
|
$effect(() => {
|
|
14
|
-
value
|
|
12
|
+
if (value) {
|
|
13
|
+
const oldTab = activeTab
|
|
14
|
+
const newTab = tabs?.find((tab) => tab.getAttribute('data-value') === value)
|
|
15
|
+
if (newTab && oldTab && newTab !== oldTab) {
|
|
16
|
+
selectTab(newTab, oldTab, { id: newTab.id, value })
|
|
17
|
+
}
|
|
18
|
+
}
|
|
15
19
|
})
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
|
|
21
|
+
const selectTab = (
|
|
22
|
+
newTab: HTMLElement,
|
|
23
|
+
oldTab: HTMLElement,
|
|
24
|
+
detail: { id: string; value: string | number },
|
|
25
|
+
) => {
|
|
26
|
+
const oldIndicator = oldTab.querySelector('.np-indicator') as HTMLElement
|
|
27
|
+
const oldIndicatorRect = oldIndicator.getBoundingClientRect()
|
|
28
|
+
if (oldIndicatorRect) {
|
|
29
|
+
const newIndicator = newTab.querySelector<HTMLElement>('.np-indicator')
|
|
30
|
+
if (newIndicator) {
|
|
31
|
+
newIndicator.style.setProperty(
|
|
32
|
+
'--np-tab-indicator-start',
|
|
33
|
+
`${oldIndicatorRect.x - newIndicator.getBoundingClientRect().x}px`,
|
|
34
|
+
)
|
|
35
|
+
newIndicator.style.setProperty(
|
|
36
|
+
'--np-tab-indicator-scale',
|
|
37
|
+
`${oldIndicatorRect.width / newIndicator.clientWidth}`,
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
value = detail.value
|
|
42
|
+
activeTab = newTab
|
|
43
|
+
tabs?.forEach((tab) => {
|
|
44
|
+
tab.dispatchEvent(new CustomEvent('change', { detail }))
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const onChange = (event: Event) => {
|
|
49
|
+
const { detail } = event as CustomEvent<{ id: string; value: string | number }>
|
|
50
|
+
const oldTab = activeTab
|
|
51
|
+
const newTab = tabs?.find((tab) => tab.id === detail.id)
|
|
52
|
+
if (newTab && oldTab && newTab !== oldTab) {
|
|
53
|
+
selectTab(newTab, oldTab, detail)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
onMount(() => {
|
|
58
|
+
element?.addEventListener('change', onChange)
|
|
59
|
+
return () => {
|
|
60
|
+
element?.removeEventListener('change', onChange)
|
|
61
|
+
}
|
|
18
62
|
})
|
|
63
|
+
const initialSetup = (el: HTMLElement) => {
|
|
64
|
+
if (activeTab === undefined) {
|
|
65
|
+
const childTabs = Array.from(el.querySelectorAll<HTMLElement>('.np-tab'))
|
|
66
|
+
activeTab =
|
|
67
|
+
childTabs && childTabs.length > 0
|
|
68
|
+
? (childTabs.find((t) => {
|
|
69
|
+
return t.getAttribute('data-value') === initialValue
|
|
70
|
+
}) ?? childTabs[0])
|
|
71
|
+
: undefined
|
|
72
|
+
if (initialValue === undefined) {
|
|
73
|
+
value = activeTab?.getAttribute('data-value') ?? undefined
|
|
74
|
+
} else {
|
|
75
|
+
value = initialValue
|
|
76
|
+
}
|
|
77
|
+
tabs = childTabs
|
|
78
|
+
}
|
|
79
|
+
}
|
|
19
80
|
</script>
|
|
20
81
|
|
|
21
|
-
<div {...attributes} class={[attributes.class]}>
|
|
82
|
+
<div {@attach initialSetup} {...attributes} class={[attributes.class]}>
|
|
22
83
|
<div
|
|
23
84
|
class={['np-tabs']}
|
|
24
85
|
role="tablist"
|
|
86
|
+
data-value={value}
|
|
25
87
|
tabindex="-1"
|
|
26
88
|
bind:this={element}
|
|
27
89
|
onkeydown={(event) => {
|
|
28
|
-
if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {
|
|
29
|
-
const tabs: HTMLElement[] = Array.from(event.currentTarget.querySelectorAll('.np-tab'))
|
|
90
|
+
if (tabs && tabs.length > 0 && (event.key === 'ArrowRight' || event.key === 'ArrowLeft')) {
|
|
30
91
|
const focusedTab = event.currentTarget.querySelector('.np-tab:focus') as HTMLElement
|
|
31
92
|
const currentIndex = tabs.indexOf(focusedTab)
|
|
32
93
|
const index = currentIndex + (event.key === 'ArrowRight' ? 1 : -1)
|
package/dist/tabs/types.d.ts
CHANGED
|
@@ -8,8 +8,9 @@ export interface TabProps extends HTMLAttributes<HTMLElement> {
|
|
|
8
8
|
icon?: Snippet;
|
|
9
9
|
badge?: boolean;
|
|
10
10
|
badgeLabel?: string | number;
|
|
11
|
+
selected?: boolean;
|
|
11
12
|
}
|
|
12
13
|
export interface TabsProps extends HTMLAttributes<HTMLDivElement> {
|
|
13
|
-
value
|
|
14
|
+
value?: string | number;
|
|
14
15
|
element?: HTMLElement;
|
|
15
16
|
}
|