noph-ui 0.45.0 → 0.46.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.
Files changed (47) hide show
  1. package/dist/animation.d.ts +0 -15
  2. package/dist/animation.js +0 -15
  3. package/dist/app-bar/AppBar.svelte +2 -52
  4. package/dist/app-bar/types.d.ts +0 -22
  5. package/dist/button/SplitButton.svelte +0 -17
  6. package/dist/button/types.d.ts +0 -6
  7. package/dist/checkbox/Checkbox.svelte +0 -2
  8. package/dist/chip/FilterChip.svelte +0 -2
  9. package/dist/chip/types.d.ts +0 -8
  10. package/dist/date-picker/DatePickerDialog.svelte +0 -10
  11. package/dist/date-picker/DateRangePicker.svelte +0 -5
  12. package/dist/date-picker/DockedDatePicker.svelte +1 -11
  13. package/dist/date-picker/DockedDateTimePicker.svelte +1 -8
  14. package/dist/date-picker/exitVisibility.svelte.d.ts +0 -5
  15. package/dist/date-picker/exitVisibility.svelte.js +0 -7
  16. package/dist/date-picker/optionList.d.ts +0 -12
  17. package/dist/date-picker/optionList.js +0 -12
  18. package/dist/dialog/Dialog.svelte +0 -22
  19. package/dist/dialog/types.d.ts +0 -1
  20. package/dist/fab/ExtendedFab.svelte +0 -26
  21. package/dist/fab/Fab.svelte +0 -28
  22. package/dist/fab/FabMenu.svelte +0 -48
  23. package/dist/fab/types.d.ts +0 -24
  24. package/dist/loading-indicator/shapes.js +0 -7
  25. package/dist/navigation-bar/NavigationBar.svelte +0 -7
  26. package/dist/navigation-bar/NavigationBarItem.svelte +0 -22
  27. package/dist/navigation-bar/types.d.ts +0 -10
  28. package/dist/navigation-drawer/NavigationDrawer.svelte +0 -21
  29. package/dist/navigation-drawer/types.d.ts +0 -3
  30. package/dist/popover.svelte.d.ts +0 -9
  31. package/dist/popover.svelte.js +0 -9
  32. package/dist/press.svelte.d.ts +0 -13
  33. package/dist/press.svelte.js +0 -13
  34. package/dist/search/Search.svelte +23 -81
  35. package/dist/search/Search.svelte.d.ts +4 -1
  36. package/dist/search/types.d.ts +0 -20
  37. package/dist/sheet/Sheet.svelte +0 -25
  38. package/dist/sheet/types.d.ts +0 -8
  39. package/dist/slider/Slider.svelte +0 -36
  40. package/dist/snackbar/Snackbar.svelte +3 -17
  41. package/dist/tabs/Tab.svelte +0 -4
  42. package/dist/tabs/Tabs.svelte +2 -2
  43. package/dist/text-field/TextField.svelte +0 -2
  44. package/dist/toolbar/Toolbar.svelte +0 -12
  45. package/dist/toolbar/types.d.ts +0 -7
  46. package/dist/tooltip/RichTooltip.svelte +0 -7
  47. package/package.json +1 -1
@@ -109,13 +109,6 @@
109
109
  --np-ripple-pressed-color: var(--np-fab-icon-color, var(--_icon-color));
110
110
  }
111
111
 
112
- /*
113
- * `round` is fully rounded and `square` is the smaller radius, the same way Button reads.
114
- * The FAB box is always square, so `50%` renders identically to `--np-shape-corner-full`
115
- * (9999px) at rest. It matters for the pressed transition below: animating `border-radius`
116
- * from a huge fixed value spends nearly the whole transition on radii that still render as
117
- * fully round, so the morph never becomes visible during a normal, brief click.
118
- */
119
112
  .round {
120
113
  border-radius: var(--np-fab-shape, 50%);
121
114
  }
@@ -123,13 +116,6 @@
123
116
  border-radius: var(--np-fab-shape, var(--_square-radius));
124
117
  }
125
118
 
126
- /*
127
- * A press morphs the corner towards the other shape. `:active` alone drops the moment the
128
- * pointer lifts, which on a normal click is long before the morph has played, so the short
129
- * `pressed` class holds the shape until the whole round trip is visible, the way Button does
130
- * it. Both are gated on the motion preference, since without the transition below this is
131
- * only an instant snap.
132
- */
133
119
  @media (prefers-reduced-motion: no-preference) {
134
120
  .round:not(:disabled):is(:active, .pressed) {
135
121
  border-radius: var(--np-fab-pressed-shape, var(--_square-radius));
@@ -148,11 +134,6 @@
148
134
  }
149
135
  }
150
136
 
151
- /*
152
- * M3's three recommended sizes, matching the extended FAB's. The 40px FAB it used to also
153
- * define is gone: M3 Expressive no longer recommends it. Each square radius is the shape token
154
- * that goes with the size, large, large-increased and extra-large.
155
- */
156
137
  .s {
157
138
  width: 3.5rem;
158
139
  height: 3.5rem;
@@ -172,10 +153,6 @@
172
153
  --np-icon-size: 2.25rem;
173
154
  }
174
155
 
175
- /*
176
- * M3's colour styles, named after the tokens they map to. The tone styles are the stronger
177
- * pair, the container styles the softer one. The surface style M3 Expressive dropped is gone.
178
- */
179
156
  .np-fab-primary {
180
157
  --_container-color: var(--np-color-primary);
181
158
  --_icon-color: var(--np-color-on-primary);
@@ -226,11 +203,6 @@
226
203
  color: color-mix(in srgb, var(--np-color-on-surface) 38%, transparent);
227
204
  }
228
205
 
229
- /*
230
- * The icon is never a hit target, matching `Button`'s. Otherwise swapping it out from under
231
- * the pointer, which `FabMenu`'s trigger does when it opens, moves the pointer to a different
232
- * element; the browser hands the button fresh interest on the way and reopens its tooltip.
233
- */
234
206
  .np-fab-icon {
235
207
  display: flex;
236
208
  fill: currentColor;
@@ -24,18 +24,11 @@
24
24
 
25
25
  const uid = $props.id()
26
26
  const menuId = `np-fab-menu-${uid}`
27
- /*
28
- * One anchor name per instance. A fixed name in the stylesheet is shared by every FabMenu on
29
- * the page, and a duplicated anchor name resolves to the last one in tree order, so every menu
30
- * would open on the last trigger.
31
- */
32
27
  const anchorName = `--np-fab-menu-${uid}`
33
28
 
34
29
  let menuElement: HTMLDivElement | undefined = $state()
35
30
  const reducedMotion = new MediaQuery('(prefers-reduced-motion: reduce)', false)
36
31
 
37
- // Declaring `role="menu"` means owing the keyboard model that goes with it: one tab stop, the
38
- // arrows moving between actions. The same attachments the toolbar and the bars use.
39
32
  const ITEMS = 'button, a[href], [role="menuitem"]'
40
33
  const attach = rovingTabindex(ITEMS)
41
34
  const arrowHandler = $derived(
@@ -51,12 +44,6 @@
51
44
  controller.close()
52
45
  }
53
46
 
54
- /*
55
- * An item runs its own press animation on click, the corner morph a Button or a FAB does. The
56
- * menu is a popover, so closing it means `display: none`, which would cut that off before a
57
- * frame of it is seen. Holding the close for the length of the press lets the item finish.
58
- * Matched to Button's own timer, and skipped entirely when there is no animation to wait for.
59
- */
60
47
  let closeTimeout: ReturnType<typeof setTimeout>
61
48
 
62
49
  const closeAfterPress = () => {
@@ -82,10 +69,6 @@
82
69
  )
83
70
  </script>
84
71
 
85
- <!--
86
- Both icons stay mounted and turn into each other. Swapping one for the other cannot animate:
87
- the icon arriving has no previous state to move from, so it can only appear.
88
- -->
89
72
  {#snippet triggerIcon()}
90
73
  <span class="np-fab-menu-icons" aria-hidden="true">
91
74
  <span class="np-fab-menu-icon" class:np-fab-menu-icon-away={open}>
@@ -103,12 +86,6 @@
103
86
  style="anchor-name: {anchorName}; {attributes.style ?? ''}"
104
87
  class={['np-fab-menu', `np-fab-menu-${placement}`, attributes.class]}
105
88
  >
106
- <!--
107
- The tooltip is dropped while the menu is open, and the name given directly instead. A
108
- tooltip is a `hint` popover, which the browser closes when the menu's `auto` popover opens,
109
- and the trigger still holds interest at that point, so it would come straight back and sit
110
- over the open menu. There is nothing to hint at anyway once the actions are on screen.
111
- -->
112
89
  <Fab
113
90
  {variant}
114
91
  {size}
@@ -134,8 +111,6 @@
134
111
  {@attach attach}
135
112
  onkeydown={arrowHandler}
136
113
  onclick={(event) => {
137
- // Picking an action closes the menu. `closeOnSelect={false}` keeps it open for a menu
138
- // whose items toggle something instead of navigating away.
139
114
  if (!closeOnSelect) return
140
115
  const target = event.target as HTMLElement
141
116
  if (target.closest(ITEMS)) closeAfterPress()
@@ -154,7 +129,6 @@
154
129
  display: inline-flex;
155
130
  }
156
131
 
157
- /* One grid cell holds both icons, so they sit on top of each other rather than side by side. */
158
132
  .np-fab-menu-icons {
159
133
  display: grid;
160
134
  }
@@ -172,11 +146,6 @@
172
146
  opacity var(--np-motion-expressive-fast-effects),
173
147
  rotate var(--np-motion-expressive-default-spatial);
174
148
  }
175
- /*
176
- * Both turn the same way, so the pair reads as one icon rotating rather than two crossing
177
- * over. The close icon spends its hidden time at -45deg, where an X sits square like the
178
- * plus it replaces, so opening rotates the plus away and the X into place behind it.
179
- */
180
149
  .np-fab-menu-icon-away {
181
150
  rotate: -45deg;
182
151
  }
@@ -194,16 +163,10 @@
194
163
  overflow: visible;
195
164
  }
196
165
 
197
- /*
198
- * `display` only while open. Setting it on the base rule would beat the user agent's
199
- * `display: none` for a closed popover, because author styles win over user agent styles
200
- * whatever the specificity, leaving an invisible sheet over the page that swallows clicks.
201
- */
202
166
  .np-fab-menu-list:popover-open {
203
167
  display: flex;
204
168
  }
205
169
 
206
- /* Which side the items fan out to, and which end they stack from. */
207
170
  .np-fab-menu-block-start .np-fab-menu-list {
208
171
  position-area: block-start;
209
172
  margin-block-end: 0.75rem;
@@ -226,17 +189,6 @@
226
189
  align-items: center;
227
190
  }
228
191
 
229
- /*
230
- * The items rise into place one after another. Keyframes rather than a transition: a popover
231
- * goes from `display: none` to shown in one step, and a transition has no start value to run
232
- * from, so the items would simply appear. An animation runs when the element becomes displayed.
233
- *
234
- * The whole stagger fits one window, `--_stagger-window`, however many actions there are. That
235
- * is what `sibling-count()` buys over a fixed step: eight actions land in the same time two do,
236
- * each one just following the last a little sooner, rather than the menu taking four times as
237
- * long to finish arriving. Item one starts at 0ms, so the action nearest the trigger moves
238
- * first, and the last one starts as the window closes.
239
- */
240
192
  @media (prefers-reduced-motion: no-preference) {
241
193
  .np-fab-menu-list:popover-open > :global(*) {
242
194
  --_stagger-window: 210ms;
@@ -4,16 +4,7 @@ import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes } from
4
4
  export type FabElement = ButtonElement;
5
5
  interface BaseFabProps extends HTMLAttributes<FabElement>, Omit<HTMLButtonAttributes, keyof HTMLAttributes<HTMLButtonElement> | 'type'>, Omit<HTMLAnchorAttributes, keyof HTMLAttributes<HTMLAnchorElement> | 'type'> {
6
6
  element?: FabElement;
7
- /**
8
- * Colour style, named after the tokens it maps to. The three tone styles are the stronger
9
- * pair, the three container styles the softer one. M3 Expressive no longer recommends a
10
- * surface-coloured FAB, so there is no `surface`.
11
- */
12
7
  variant?: 'primary' | 'secondary' | 'tertiary' | 'primary-container' | 'secondary-container' | 'tertiary-container';
13
- /**
14
- * 56, 80 and 96 pixels, the same three `Fab` and `ExtendedFab` share. `s` is M3's baseline FAB
15
- * and the default. The 40 pixel FAB is not here: M3 Expressive no longer recommends it.
16
- */
17
8
  size?: 's' | 'm' | 'l';
18
9
  shape?: 'round' | 'square';
19
10
  lowered?: boolean;
@@ -22,36 +13,21 @@ interface BaseFabProps extends HTMLAttributes<FabElement>, Omit<HTMLButtonAttrib
22
13
  }
23
14
  export interface FabProps extends BaseFabProps {
24
15
  icon?: Snippet;
25
- /**
26
- * A FAB shows no text, so its accessible name has to come from somewhere. Sets both
27
- * `aria-label` and a plain tooltip, the way `Button` treats `title`.
28
- */
29
16
  label?: string;
30
17
  }
31
18
  export interface ExtendedFabProps extends BaseFabProps {
32
19
  icon?: Snippet;
33
- /** Visible text. An extended FAB is named by it, so it needs no `aria-label`. */
34
20
  label?: string;
35
- /**
36
- * Collapses to an icon-only FAB, animating the width. Drive it from a scroll or a media query
37
- * to get M3's collapsing FAB.
38
- */
39
21
  collapsed?: boolean;
40
22
  }
41
23
  export interface FabMenuProps extends HTMLAttributes<HTMLDivElement> {
42
- /** Names the trigger and the menu. The trigger shows no text. */
43
24
  label?: string;
44
- /** Trigger icon while the menu is closed. */
45
25
  icon?: Snippet;
46
- /** Trigger icon while the menu is open. Defaults to a close icon. */
47
26
  closeIcon?: Snippet;
48
27
  variant?: FabProps['variant'];
49
28
  size?: FabProps['size'];
50
- /** Which side the items fan out to. */
51
29
  placement?: 'block-start' | 'block-end' | 'inline-start' | 'inline-end';
52
- /** Bindable. Whether the menu is open. */
53
30
  open?: boolean;
54
- /** Closes the menu when an action is picked, which is what M3 does. */
55
31
  closeOnSelect?: boolean;
56
32
  element?: HTMLDivElement;
57
33
  }
@@ -7,19 +7,12 @@ const decode = (encoded) => {
7
7
  return radii;
8
8
  };
9
9
  export const SHAPES = [
10
- // MaterialShapes.SoftBurst
11
10
  '2zl30r3533bb3ik3pq3se3s33oh3gs39u33v30a2zn31b3693co3k53qk3sk3ro3n53fb38k32t2zz2zr32037h3e23ls3r83sm3r43lj3dv37c31y2zr30032w38p3fi3ne3rq3sj3qf3jw3ch3653192zm30b33y39z3h03oo3s53sd3pk3ib3b534z30q2zl30r3533bb3ik3pq3se3s33oh3gs39u33v30a2zn31b3693co3k53qk3sk3ro3n53fb38k32t2zz2zr32037h3e23ls3r83sm3r43lj3dv37c31y2zr30032w38p3fi3ne3rq3sj3qf3jw3ch3653192zm30b33y39z3h03oo3s53sd3pk3ib3b534z30q',
12
- // MaterialShapes.Cookie9Sided
13
11
  '3ne3kp3hr3g53fr3gl3iq3m33ot3qq3rw3sa3rz3qx3p33mg3jc3hi3gz3hn3jn3my3pp3rn3st3t73sv3rs3pw3n73jz3i23hg3i23jz3n73pw3rs3sv3t73st3rn3pp3my3jn3hn3gz3hi3jc3mg3p33qx3rz3sa3rw3qq3ot3m33iq3gl3fr3g53hr3kp3ne3pb3qg3qw3qm3pm3nv3lc3i13fk3eg3ei3fr3ie3lc3nh3ov3pk3pk3ou3ne3l83i93fb3dr3df3e83gb3jh3lz3nr3os3p53os3nr3lz3jh3gb3e83df3dr3fb3i93l83ne3ou3pk3pk3ov3nh3lc3ie3fr3ei3eg3fk3i13lc3nv3pm3qm3qw3qg3pb',
14
- // MaterialShapes.Pentagon
15
12
  '3ng3lh3jw3im3ho3h23gq3gq3h03hl3ih3jp3l93n63ph3s73vc3y23zz41241e40z3zr3xr3uz3se3q73od3mx3lt3l13kk3kf3kk3l13lt3mx3od3q73se3uz3xr3zr40z41e4123zz3y23vc3s73ph3n63l93jp3ih3hl3h03gq3gq3h23ho3im3jw3lh3ng3pp3rf3se3sp3sb3r93pg3mx3jm3gc3dh3b138z37935u34r33x33e33533533f33y34s35w37b3913b43df3f93gk3hb3hl3hb3gk3f93df3b439137b35w34s33y33f33533533e33x34r35u37938z3b13dh3gc3jm3mx3pg3r93sb3sp3se3rf3pp',
16
- // MaterialShapes.Pill
17
13
  '3t53rz3qr3pj3o93mz3lo3kd3j13hp3gd3f13dq3cp3by3bj3be3bj3by3cp3dq3f13gd3hp3j13kd3lo3mz3o93pj3qr3rz3t53ua3vd3wc3wu3xm3yg3z83zx40k41341j41x42842f42k42l42k42f42841x41j41340k3zx3z83yg3xm3wu3wc3vd3ua3t53rz3qr3pj3o93mz3lo3kd3j13hp3gd3f13dq3cp3by3bj3be3bj3by3cp3dq3f13gd3hp3j13kd3lo3mz3o93pj3qr3rz3t53ua3vd3wc3wu3xm3yg3z83zx40k41341j41x42842f42k42l42k42f42841x41j41340k3zx3z83yg3xm3wu3wc3vd3ua',
18
- // MaterialShapes.Sunny
19
14
  '3t63sa3pe3l73hi3ea3bj3973893973bj3ea3hi3l73pe3sa3t63sa3pe3l73hi3ea3bj3973893973bj3ea3hi3l73pe3sa3t63sa3pe3l73hi3ea3bj3973893973bj3ea3hi3l73pe3sa3t63sa3pe3l73hi3ea3bj3973893973bj3ea3hi3l73pe3sa3t63sa3pe3l73hi3ea3bj3973893973bj3ea3hi3l73pe3sa3t63sa3pe3l73hi3ea3bj3973893973bj3ea3hi3l73pe3sa3t63sa3pe3l73hi3ea3bj3973893973bj3ea3hi3l73pe3sa3t63sa3pe3l73hi3ea3bj3973893973bj3ea3hi3l73pe3sa',
20
- // MaterialShapes.Cookie4Sided
21
15
  '2yr2z530a32b35g39l3ea3iv3mz3qk3tm3w53y73zr40v41j41r41i40u3zr3y63w43tk3qi3mw3it3e739j35f32a3092z42yr2z530a32b35g39l3ea3iv3mz3qk3tm3w53y73zr40v41j41r41i40u3zr3y63w43tk3qi3mw3it3e739j35f32a3092z42yr2z530a32b35g39l3ea3iv3mz3qk3tm3w53y73zr40v41j41r41i40u3zr3y63w43tk3qi3mw3it3e739j35f32a3092z42yr2z530a32b35g39l3ea3iv3mz3qk3tm3w53y73zr40v41j41r41i40u3zr3y63w43tk3qi3mw3it3e739j35f32a3092z4',
22
- // MaterialShapes.Oval
23
16
  '3ec3bw39m37i35k33s32630q2zg2yb2xc2wj2vv2vd2uz2ur2up2ur2uz2vd2vv2wj2xc2yb2zg30q32633s35k37i39m3bw3ec3gx3jn3mi3ph3sj3vn3yr41t44r47j4a14c84e14fd4g64gg4g64fd4e14c84a147j44r41t3yr3vn3sj3ph3mi3jn3gx3ec3bw39m37i35k33s32630q2zg2yb2xc2wj2vv2vd2uz2ur2up2ur2uz2vd2vv2wj2xc2yb2zg30q32633s35k37i39m3bw3ec3gx3jn3mi3ph3sj3vn3yr41t44r47j4a14c84e14fd4g64gg4g64fd4e14c84a147j44r41t3yr3vn3sj3ph3mi3jn3gx',
24
17
  ].map(decode);
25
18
  export const CIRCLE = decode('3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so3so');
@@ -10,7 +10,6 @@
10
10
  ...attributes
11
11
  }: NavigationBarProps = $props()
12
12
 
13
- // The same attachments the rail uses. They read no reactive state, so they never tear down.
14
13
  const attach = rovingTabindex('.np-navigation-bar-item')
15
14
  const arrowHandler = arrowKeyNav('.np-navigation-bar-item', 'horizontal')
16
15
 
@@ -45,20 +44,14 @@
45
44
  padding-block: 0.75rem;
46
45
  padding-inline: 0.5rem;
47
46
  background-color: var(--np-navigation-bar-container-color, var(--np-color-surface-container));
48
- /* Sits above page content the way a rail does, and clears the home inset on a phone. */
49
47
  padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
50
48
  z-index: 8;
51
49
  }
52
50
 
53
- /* Items keep their own content width instead of stretching, and group in the middle. */
54
51
  .np-navigation-bar-centered {
55
52
  justify-content: center;
56
53
  gap: 0.5rem;
57
54
  }
58
- /*
59
- * Doubled selector to outrank the item's own `.svelte-*`-scoped `flex: 1` rule, which has the
60
- * same specificity and would otherwise win or lose depending on CSS bundle order.
61
- */
62
55
  :global(.np-navigation-bar-centered .np-navigation-bar-item.np-navigation-bar-item) {
63
56
  flex: 0 0 auto;
64
57
  min-width: 0;
@@ -32,7 +32,6 @@
32
32
 
33
33
  {#snippet content()}
34
34
  {#if orientation === 'horizontal'}
35
- <!-- Sized off its own parent, so it has to sit on the whole pill rather than the icon alone. -->
36
35
  <Ripple forElement={touchEl} />
37
36
  {/if}
38
37
  <span class="np-navigation-bar-item-icon">
@@ -104,7 +103,6 @@
104
103
  z-index: 1;
105
104
  }
106
105
 
107
- /* The active-indicator pill, grown from the selected class rather than measured. */
108
106
  .np-navigation-bar-item-icon::before {
109
107
  content: '';
110
108
  position: absolute;
@@ -144,10 +142,6 @@
144
142
  color: var(--np-color-on-surface);
145
143
  }
146
144
 
147
- /*
148
- * `labelBehavior="selected"` keeps the label in the layout but hides it, so the row does not
149
- * reflow as the selection moves.
150
- */
151
145
  .np-navigation-bar-item-label-selected .np-navigation-bar-item-label {
152
146
  visibility: hidden;
153
147
  }
@@ -156,28 +150,13 @@
156
150
  visibility: visible;
157
151
  }
158
152
 
159
- /*
160
- * The icon sits beside the label instead of above it, for a bar with room to spare. Unlike the
161
- * stacked layout, the active-indicator pill wraps the icon and label together, like a chip,
162
- * rather than just the icon.
163
- */
164
153
  .np-navigation-bar-item-horizontal {
165
154
  flex-direction: row;
166
155
  justify-content: center;
167
- /* M3's "icon label space" token: 4dp between the icon and the label. */
168
156
  gap: 0.25rem;
169
- /*
170
- * M3's "leading/trailing space" token (16dp) sets the inline padding, and the block padding
171
- * is picked so a 1.5rem icon plus padding adds up to the "active indicator height" token
172
- * (40dp).
173
- */
174
157
  padding: 0.5rem 1rem;
175
158
  border-radius: var(--np-shape-corner-full);
176
- /* The bar stretches items to its own height by default; a pill sizes to its own content and
177
- * centers in the bar instead. */
178
159
  align-self: center;
179
- /* Gives the item its own stacking context, so the pill's z-index: -1 stays behind the icon
180
- * and label instead of escaping to sit behind the bar's own background. */
181
160
  z-index: 0;
182
161
  }
183
162
  .np-navigation-bar-item-horizontal::before {
@@ -197,7 +176,6 @@
197
176
  opacity: 1;
198
177
  transform: scaleX(1);
199
178
  }
200
- /* The wrapping item now supplies the pill, so the icon's own is switched off. */
201
179
  .np-navigation-bar-item-horizontal .np-navigation-bar-item-icon {
202
180
  width: 1.5rem;
203
181
  height: 1.5rem;
@@ -1,11 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
3
3
  export interface NavigationBarProps extends HTMLAttributes<HTMLElement> {
4
- /**
5
- * `'equal-weight'` stretches every item to the same width, which M3 recommends for compact
6
- * screens. `'centered'` sizes each item to its content and groups them in the middle, which M3
7
- * recommends once the bar has room to spare on a medium-width screen.
8
- */
9
4
  arrangement?: 'equal-weight' | 'centered';
10
5
  element?: HTMLElement;
11
6
  }
@@ -17,12 +12,7 @@ export interface NavigationBarItemProps extends HTMLAttributes<NavigationBarItem
17
12
  badge?: boolean;
18
13
  badgeLabel?: string | number;
19
14
  badgeAriaLabel?: string;
20
- /** Hides the label until the item is selected, which M3 allows for four or five items. */
21
15
  labelBehavior?: 'always' | 'selected';
22
- /**
23
- * `'vertical'` stacks the icon above the label. `'horizontal'` puts it beside the label instead,
24
- * which M3 pairs with `arrangement="centered"` once a bar has room to spare.
25
- */
26
16
  orientation?: 'vertical' | 'horizontal';
27
17
  type?: 'submit' | 'reset' | 'button' | (string & {}) | null;
28
18
  element?: NavigationBarItemElement;
@@ -23,7 +23,6 @@
23
23
  if (!event.defaultPrevented) arrowHandler(event)
24
24
  }
25
25
 
26
- /* Only a modal drawer is a dialog; a standard one is a nav that is always in the layout. */
27
26
  const asDialog = () => (element instanceof HTMLDialogElement ? element : undefined)
28
27
 
29
28
  export const show = () => {
@@ -45,12 +44,6 @@
45
44
  const start = $derived(direction === 'ltr' ? 'translateX(-100%)' : 'translateX(100%)')
46
45
  </script>
47
46
 
48
- <!--
49
- A modal drawer is a `dialog` holding a nav landmark, so the browser keeps the page behind it
50
- inert for as long as it is open and hands focus back on close. `::backdrop` is the scrim and
51
- `closedby="any"` the tap-outside-to-close. Where `closedby` is unsupported the click handler
52
- below covers it: a click on the backdrop is reported against the dialog itself.
53
- -->
54
47
  {#if modal}
55
48
  <dialog
56
49
  {...attributes}
@@ -70,11 +63,6 @@
70
63
  onkeydown={handleKeydown}
71
64
  ontoggle={(event) => {
72
65
  open = event.newState === 'open'
73
- /*
74
- * Without this the browser autofocuses the first focusable descendant, the first nav
75
- * item. Focus the drawer itself instead, so nothing is focused that the user didn't
76
- * choose to interact with.
77
- */
78
66
  if (event.newState === 'open') element?.focus()
79
67
  ontoggle?.(event)
80
68
  }}
@@ -83,12 +71,6 @@
83
71
  if (event.target === element) close()
84
72
  }}
85
73
  >
86
- <!--
87
- The label belongs to the navigation landmark, not to the dialog wrapping it, so it is
88
- pulled back off the dialog above and put here. Everything else stays on the dialog: it
89
- is the container the layout and the custom properties are written against, and the
90
- element `commandfor` has to reach.
91
- -->
92
74
  <nav
93
75
  aria-label={attributes['aria-label']}
94
76
  aria-labelledby={attributes['aria-labelledby']}
@@ -120,7 +102,6 @@
120
102
  color: var(--np-color-on-surface-variant);
121
103
  width: calc(var(--np-navigation-drawer-width, 22.5rem) + 3px);
122
104
  border: 0;
123
- /* Focus lands here on open only to stay off the first nav item, not as something to show. */
124
105
  outline: none;
125
106
  margin: 0;
126
107
  padding: 0;
@@ -129,7 +110,6 @@
129
110
  max-height: none;
130
111
  }
131
112
 
132
- /* The modal drawer is docked to the inline edge rather than centred as a dialog would be. */
133
113
  .np-navigation-drawer-container-modal {
134
114
  position: fixed;
135
115
  inset-block: 0;
@@ -183,7 +163,6 @@
183
163
  box-shadow: var(--np-elevation-1);
184
164
  }
185
165
 
186
- /* `backdrop` decides whether the scrim is painted; a modal dialog always has the layer. */
187
166
  .np-navigation-drawer-container-modal::backdrop {
188
167
  background-color: transparent;
189
168
  }
@@ -1,11 +1,8 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
3
3
  export interface NavigationDrawerProps extends HTMLAttributes<HTMLElement> {
4
- /** A modal drawer is a `dialog` over the page; a standard one is part of the layout. */
5
4
  modal?: boolean;
6
- /** Paints the scrim behind a modal drawer. */
7
5
  backdrop?: boolean;
8
- /** Bindable. Whether a modal drawer is showing. Ignored by a standard drawer. */
9
6
  open?: boolean;
10
7
  element?: HTMLElement;
11
8
  direction?: 'rtl' | 'ltr';
@@ -1,14 +1,5 @@
1
- /**
2
- * `show()`/`close()` for a popover-backed overlay, guarded both ways. `showPopover()` throws if
3
- * the popover is already showing and `hidePopover()` throws if it is already hidden, so both
4
- * directions need the `:popover-open` check, not just the one that happens to get exercised first.
5
- */
6
1
  export declare const popoverController: (getElement: () => HTMLElement | undefined) => {
7
2
  show: () => void;
8
3
  close: () => void;
9
4
  };
10
- /**
11
- * Keeps a bindable `open` prop in sync with an overlay's own `show`/`close`, so a caller can drive
12
- * the overlay either by calling the exported methods or by writing to the bound prop.
13
- */
14
5
  export declare const syncOpenEffect: (getElement: () => HTMLElement | undefined, getOpen: () => boolean | undefined, show: () => void, close: () => void) => void;
@@ -1,8 +1,3 @@
1
- /**
2
- * `show()`/`close()` for a popover-backed overlay, guarded both ways. `showPopover()` throws if
3
- * the popover is already showing and `hidePopover()` throws if it is already hidden, so both
4
- * directions need the `:popover-open` check, not just the one that happens to get exercised first.
5
- */
6
1
  export const popoverController = (getElement) => ({
7
2
  show: () => {
8
3
  const element = getElement();
@@ -15,10 +10,6 @@ export const popoverController = (getElement) => ({
15
10
  element.hidePopover();
16
11
  },
17
12
  });
18
- /**
19
- * Keeps a bindable `open` prop in sync with an overlay's own `show`/`close`, so a caller can drive
20
- * the overlay either by calling the exported methods or by writing to the bound prop.
21
- */
22
13
  export const syncOpenEffect = (getElement, getOpen, show, close) => {
23
14
  $effect(() => {
24
15
  if (!getElement())
@@ -1,19 +1,6 @@
1
1
  export declare const PRESS_DURATION = 100;
2
- /**
3
- * The corner morph a Button, an IconButton or a FAB plays when it is activated. `:active` covers
4
- * the press itself, but it drops the moment the pointer lifts, so a quick click would show only a
5
- * frame or two of the morph. The `pressed` this returns is held for as long as the round trip
6
- * takes to be seen, and is set from `click`, which arrives for the keyboard as well as the pointer.
7
- */
8
2
  export declare const pressMorph: () => {
9
3
  readonly pressed: boolean;
10
4
  press: () => void;
11
- /**
12
- * A change of `shape` supersedes the morph. Both describe the same corner, and the pressed
13
- * radius is the shape the element is not, so holding the press across a shape change cancels
14
- * the change out and stalls it until the timer runs down. FabMenu's trigger does exactly
15
- * that, flipping to `square` on the click that opens the menu; dropping the press there
16
- * leaves that click one continuous morph.
17
- */
18
5
  supersededBy: (shape: () => unknown) => void;
19
6
  };
@@ -1,11 +1,5 @@
1
1
  import { onMount } from 'svelte';
2
2
  export const PRESS_DURATION = 100;
3
- /**
4
- * The corner morph a Button, an IconButton or a FAB plays when it is activated. `:active` covers
5
- * the press itself, but it drops the moment the pointer lifts, so a quick click would show only a
6
- * frame or two of the morph. The `pressed` this returns is held for as long as the round trip
7
- * takes to be seen, and is set from `click`, which arrives for the keyboard as well as the pointer.
8
- */
9
3
  export const pressMorph = () => {
10
4
  let pressed = $state(false);
11
5
  let timeout;
@@ -23,13 +17,6 @@ export const pressMorph = () => {
23
17
  pressed = true;
24
18
  timeout = setTimeout(() => (pressed = false), PRESS_DURATION);
25
19
  },
26
- /**
27
- * A change of `shape` supersedes the morph. Both describe the same corner, and the pressed
28
- * radius is the shape the element is not, so holding the press across a shape change cancels
29
- * the change out and stalls it until the timer runs down. FabMenu's trigger does exactly
30
- * that, flipping to `square` on the click that opens the menu; dropping the press there
31
- * leaves that click one continuous morph.
32
- */
33
20
  supersededBy: (shape) => {
34
21
  let previous;
35
22
  $effect(() => {