noph-ui 0.24.15 → 0.24.16

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.
@@ -212,15 +212,14 @@
212
212
  ? 'var(--np-outlined-select-text-field-container-shape)'
213
213
  : 'var(--np-filled-select-text-field-container-shape)'}
214
214
  anchor={element}
215
+ bind:open={menuOpen}
215
216
  ontoggle={(e) => {
216
217
  if (e.newState === 'closed') {
217
- menuOpen = false
218
218
  activeIndex = NO_INDEX
219
219
  if (!populated && finalPopulated && !value) {
220
220
  finalPopulated = false
221
221
  }
222
222
  } else {
223
- menuOpen = true
224
223
  if (activeIndex >= displayOptions.length) {
225
224
  activeIndex = NO_INDEX
226
225
  }
@@ -34,7 +34,7 @@
34
34
  <span class="np-touch" bind:this={touchEl}></span>
35
35
  {/if}
36
36
  {#if loading}
37
- <div class="circular-progress">
37
+ <div class="np-icon-button-circular-progress">
38
38
  <CircularProgress aria-label={loadingAriaLabel} indeterminate />
39
39
  </div>
40
40
  {/if}
@@ -365,7 +365,7 @@
365
365
  width: max(calc(var(--_button-width, 40px) + 8px), 100%);
366
366
  }
367
367
 
368
- .circular-progress {
368
+ .np-icon-button-circular-progress {
369
369
  --np-circular-progress-color: color-mix(in srgb, var(--np-color-on-surface) 38%, transparent);
370
370
  position: absolute;
371
371
  }
@@ -6,6 +6,8 @@
6
6
  element = $bindable(),
7
7
  showPopover = $bindable(),
8
8
  hidePopover = $bindable(),
9
+ open = $bindable(),
10
+ quick = false,
9
11
  style,
10
12
  popover = 'auto',
11
13
  anchor,
@@ -15,7 +17,6 @@
15
17
  let clientWidth = $state(0)
16
18
  let clientHeight = $state(0)
17
19
  let innerHeight = $state(0)
18
- let menuOpen = $state(false)
19
20
 
20
21
  showPopover = () => {
21
22
  element?.showPopover()
@@ -25,7 +26,7 @@
25
26
  element?.hidePopover()
26
27
  }
27
28
  const refreshValues = () => {
28
- if (element && anchor && menuOpen) {
29
+ if (element && anchor && open) {
29
30
  const anchorRect = anchor.getBoundingClientRect()
30
31
  let maxHeight: number
31
32
  if (innerHeight - anchorRect.bottom > anchorRect.top) {
@@ -102,11 +103,11 @@
102
103
  bind:clientHeight
103
104
  ontoggle={(event) => {
104
105
  let { newState } = event
105
- menuOpen = newState === 'open'
106
+ open = newState === 'open'
106
107
  attributes.ontoggle?.(event)
107
108
  }}
108
109
  {popover}
109
- class={['np-menu-container', attributes.class]}
110
+ class={['np-menu-container', !quick && 'np-animate', attributes.class]}
110
111
  {style}
111
112
  >
112
113
  <div class="np-menu">
@@ -115,18 +116,7 @@
115
116
  </div>
116
117
 
117
118
  <style>
118
- .np-menu {
119
- overflow-y: auto;
120
- overflow-x: hidden;
121
- flex: 1;
122
- padding: 0.5rem 0;
123
- scrollbar-color: var(--np-color-on-surface-variant) transparent;
124
- scrollbar-width: thin;
125
- }
126
- :global(.np-menu .np-divider) {
127
- margin-block: 0.5rem;
128
- }
129
- .np-menu-container[popover] {
119
+ .np-menu-container {
130
120
  color: var(--np-menu-text-color, var(--np-color-on-surface));
131
121
  background-color: var(--np-menu-container-color, var(--np-color-surface-container));
132
122
  border: none;
@@ -135,21 +125,35 @@
135
125
  box-shadow: var(--np-elevation-2);
136
126
  margin: var(--np-menu-margin, 2px);
137
127
  inset: auto;
138
- transition:
139
- display 0.2s allow-discrete,
140
- opacity 0.2s linear;
141
- opacity: 0;
142
128
  justify-self: var(--np-menu-justify-self, anchor-center);
143
129
  position-area: var(--np-menu-position-area, bottom center);
144
130
  position-try: normal flip-block;
145
131
  z-index: 1000;
146
132
  }
147
133
 
148
- .np-menu-container:popover-open {
134
+ .np-animate[popover] {
135
+ transition:
136
+ opacity 0.2s ease,
137
+ display 0.2s allow-discrete,
138
+ overlay 0.2s allow-discrete;
139
+ opacity: 0;
140
+ }
141
+ .np-animate[popover]:popover-open {
149
142
  opacity: 1;
150
- display: flex;
151
143
  @starting-style {
152
144
  opacity: 0;
153
145
  }
154
146
  }
147
+
148
+ .np-menu {
149
+ overflow-y: auto;
150
+ overflow-x: hidden;
151
+ flex: 1;
152
+ padding: 0.5rem 0;
153
+ scrollbar-color: var(--np-color-on-surface-variant) transparent;
154
+ scrollbar-width: thin;
155
+ }
156
+ :global(.np-menu .np-divider) {
157
+ margin-block: 0.5rem;
158
+ }
155
159
  </style>
@@ -1,4 +1,4 @@
1
1
  import type { MenuProps } from './types.ts';
2
- declare const Menu: import("svelte").Component<MenuProps, {}, "element" | "showPopover" | "hidePopover">;
2
+ declare const Menu: import("svelte").Component<MenuProps, {}, "element" | "showPopover" | "hidePopover" | "open">;
3
3
  type Menu = ReturnType<typeof Menu>;
4
4
  export default Menu;
@@ -6,6 +6,8 @@ export interface MenuProps extends HTMLAttributes<HTMLDivElement> {
6
6
  showPopover?: () => void;
7
7
  hidePopover?: () => void;
8
8
  element?: HTMLDivElement;
9
+ quick?: boolean;
10
+ open?: boolean;
9
11
  }
10
12
  interface ButtonProps extends HTMLButtonAttributes {
11
13
  selected?: boolean;
@@ -31,6 +31,7 @@
31
31
  selected && 'np-navigation-drawer-item-selected',
32
32
  attributes.class,
33
33
  ]}
34
+ aria-current={selected ? 'page' : undefined}
34
35
  >
35
36
  {@render content()}
36
37
  </a>
@@ -42,6 +43,8 @@
42
43
  selected && 'np-navigation-drawer-item-selected',
43
44
  attributes.class,
44
45
  ]}
46
+ type="button"
47
+ aria-pressed={selected ? 'true' : undefined}
45
48
  >
46
49
  {@render content()}
47
50
  </button>
@@ -577,9 +577,9 @@
577
577
  ? 'var(--np-outlined-select-text-field-container-shape)'
578
578
  : 'var(--np-filled-select-text-field-container-shape)'}
579
579
  anchor={anchorElement}
580
+ bind:open={menuOpen}
580
581
  ontoggle={async ({ newState }) => {
581
582
  if (newState === 'open') {
582
- menuOpen = true
583
583
  let idx = -1
584
584
  if (multiple) {
585
585
  if (Array.isArray(value) && value.length) {
@@ -594,7 +594,6 @@
594
594
  if (idx < 0) idx = 0
595
595
  focusIndex = idx
596
596
  } else {
597
- menuOpen = false
598
597
  focusIndex = -1
599
598
  }
600
599
  }}
@@ -1,5 +1,7 @@
1
1
  <script lang="ts">
2
+ import { MediaQuery } from 'svelte/reactivity'
2
3
  import type { TooltipProps } from './types.ts'
4
+ import { onMount } from 'svelte'
3
5
 
4
6
  let {
5
7
  children,
@@ -8,34 +10,11 @@
8
10
  keepTooltipOnClick = false,
9
11
  ...attributes
10
12
  }: TooltipProps = $props()
11
- let clientWidth = $state(0)
12
- let clientHeight = $state(0)
13
- let innerHeight = $state(0)
14
- let anchor: HTMLElement | undefined = $state()
15
13
 
16
- const refreshValues = () => {
17
- if (element && anchor && !('positionArea' in document.documentElement.style)) {
18
- const docClientWidth = document.documentElement.clientWidth
19
- const anchorRect = anchor.getBoundingClientRect()
20
- if (anchorRect.bottom + clientHeight > innerHeight && anchorRect.top - clientHeight > 0) {
21
- element.style.top = `${anchorRect.top - clientHeight - 8}px`
22
- } else {
23
- element.style.top = `${anchorRect.bottom}px`
24
- }
25
- const left = anchorRect.left + anchorRect.width / 2 - clientWidth / 2
26
- if (left < 2) {
27
- element.style.left = '2px'
28
- } else if (left > docClientWidth - clientWidth) {
29
- element.style.left = `${docClientWidth - clientWidth - 2}px`
30
- } else {
31
- element.style.left = `${anchorRect.left + anchorRect.width / 2 - clientWidth / 2}px`
32
- }
33
- }
34
- }
35
- $effect(refreshValues)
36
- let setAnchor = (document: Document) => {
37
- anchor = (document.querySelector(`[aria-describedby="${id}"]`) as HTMLElement) ?? undefined
38
- }
14
+ const anchorNameFallback = $props.id()
15
+
16
+ let touch = new MediaQuery('(pointer: coarse) and (hover: none)', false)
17
+ let anchor = $state<HTMLElement>()
39
18
 
40
19
  const isTouch = (event: PointerEvent) => {
41
20
  return event.pointerType === 'touch'
@@ -58,25 +37,10 @@
58
37
  element?.hidePopover()
59
38
  }
60
39
  }
61
-
62
- $effect(() => {
63
- if (anchor && element) {
64
- if ('anchorName' in document.documentElement.style) {
65
- const anchorName = anchor.style.getPropertyValue('anchor-name')
66
- const generatedId = anchorName || `--${crypto.randomUUID()}`
67
- element.style.setProperty('position-anchor', generatedId)
68
- if (!anchorName) {
69
- anchor.style.setProperty('anchor-name', generatedId)
70
- }
71
- }
72
- anchor.addEventListener('pointerenter', onPointerenter)
73
- anchor.addEventListener('pointerleave', onPointerleave)
74
- if (!keepTooltipOnClick) {
75
- anchor.addEventListener('pointerup', onPointerup)
76
- }
77
- }
40
+ onMount(() => {
78
41
  return () => {
79
42
  if (anchor) {
43
+ anchor.style.removeProperty('anchor-name')
80
44
  anchor.removeEventListener('pointerenter', onPointerenter)
81
45
  anchor.removeEventListener('pointerleave', onPointerleave)
82
46
  anchor.removeEventListener('pointerup', onPointerup)
@@ -85,21 +49,38 @@
85
49
  })
86
50
  </script>
87
51
 
88
- <svelte:document use:setAnchor />
89
- <svelte:window bind:innerHeight />
52
+ {#if !touch.current}
53
+ <div
54
+ {...attributes}
55
+ {@attach (element) => {
56
+ if (id && 'positionArea' in document.documentElement.style) {
57
+ anchor = (document.querySelector(`[aria-describedby="${id}"]`) as HTMLElement) ?? undefined
90
58
 
91
- <div
92
- {...attributes}
93
- {id}
94
- class={['np-tooltip', attributes.class]}
95
- role="tooltip"
96
- popover="manual"
97
- bind:this={element}
98
- bind:clientWidth
99
- bind:clientHeight
100
- >
101
- {#if children}{@render children()}{/if}
102
- </div>
59
+ if ('anchorName' in document.documentElement.style) {
60
+ const anchorName = anchor.style.getPropertyValue('anchor-name')
61
+ const generatedId = anchorName || `--${anchorNameFallback}`
62
+ element.style.setProperty('position-anchor', generatedId)
63
+ if (!anchorName) {
64
+ anchor.style.setProperty('anchor-name', generatedId)
65
+ }
66
+ }
67
+ anchor.addEventListener('pointerenter', onPointerenter)
68
+ anchor.addEventListener('pointerleave', onPointerleave)
69
+ if (!keepTooltipOnClick) {
70
+ anchor.addEventListener('pointerup', onPointerup)
71
+ }
72
+ }
73
+ }}
74
+ {id}
75
+ class={['np-tooltip', attributes.class]}
76
+ role="tooltip"
77
+ aria-live="polite"
78
+ popover="manual"
79
+ bind:this={element}
80
+ >
81
+ {#if children}{@render children()}{/if}
82
+ </div>
83
+ {/if}
103
84
 
104
85
  <style>
105
86
  .np-tooltip[popover] {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noph-ui",
3
- "version": "0.24.15",
3
+ "version": "0.24.16",
4
4
  "license": "MIT",
5
5
  "homepage": "https://noph.dev",
6
6
  "repository": {