@noxlovette/material 0.8.3 → 0.9.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.
Files changed (53) hide show
  1. package/claude-skill/material-design/SKILL.md +1 -1
  2. package/claude-skill/material-design/references/component-patterns.md +36 -1
  3. package/dist/animation/presence.svelte.js +37 -1
  4. package/dist/animation/sharedAxisTransition.d.ts +2 -1
  5. package/dist/animation/sharedAxisTransition.js +19 -1
  6. package/dist/components/buttons/FAB.svelte +4 -1
  7. package/dist/components/buttons/theme.d.ts +6 -3
  8. package/dist/components/buttons/theme.js +3 -2
  9. package/dist/components/containers/context-menu/theme.js +4 -4
  10. package/dist/components/containers/list/theme.js +1 -1
  11. package/dist/components/containers/menu/Menu.svelte +2 -5
  12. package/dist/components/containers/menu/theme.js +4 -2
  13. package/dist/components/containers/pane/theme.js +1 -1
  14. package/dist/components/date/theme.js +1 -1
  15. package/dist/components/forms/command/Command.mdx +90 -0
  16. package/dist/components/forms/command/Command.stories.svelte +69 -10
  17. package/dist/components/forms/command/Command.stories.svelte.d.ts +2 -17
  18. package/dist/components/forms/command/CommandDialog.svelte +58 -0
  19. package/dist/components/forms/command/CommandDialog.svelte.d.ts +11 -0
  20. package/dist/components/forms/command/CommandItem.svelte +48 -5
  21. package/dist/components/forms/command/CommandItem.svelte.d.ts +4 -0
  22. package/dist/components/forms/command/index.d.ts +1 -0
  23. package/dist/components/forms/command/index.js +1 -0
  24. package/dist/components/forms/command/theme.d.ts +371 -6
  25. package/dist/components/forms/command/theme.js +32 -1
  26. package/dist/components/forms/command/types.d.ts +27 -1
  27. package/dist/components/forms/search/Search.mdx +9 -0
  28. package/dist/components/forms/search/Search.stories.svelte +14 -2
  29. package/dist/components/forms/search/Search.svelte +41 -9
  30. package/dist/components/forms/search/Search.svelte.d.ts +3 -0
  31. package/dist/components/forms/search/SearchView.svelte +57 -6
  32. package/dist/components/forms/search/SearchView.svelte.d.ts +4 -2
  33. package/dist/components/forms/search/theme.js +4 -2
  34. package/dist/components/forms/search/types.d.ts +14 -1
  35. package/dist/components/forms/slider/theme.js +1 -1
  36. package/dist/components/nav/appbar/AppBar.stories.svelte +30 -2
  37. package/dist/components/nav/appbar/AppBar.svelte +40 -8
  38. package/dist/components/nav/appbar/theme.js +1 -1
  39. package/dist/components/nav/appbar/types.d.ts +14 -0
  40. package/dist/components/nav/navbar/theme.js +1 -1
  41. package/dist/components/nav/rail/Rail.mdx +6 -0
  42. package/dist/components/nav/rail/Rail.svelte +55 -1
  43. package/dist/components/nav/rail/Rail.svelte.d.ts +3 -0
  44. package/dist/components/nav/rail/theme.js +1 -1
  45. package/dist/components/nav/rail/types.d.ts +7 -0
  46. package/dist/components/toolbar/theme.js +4 -1
  47. package/dist/styles/motion.css +26 -0
  48. package/dist/utils/Layer.svelte +3 -1
  49. package/dist/utils/index.d.ts +1 -0
  50. package/dist/utils/index.js +1 -0
  51. package/dist/utils/shortcut.d.ts +26 -0
  52. package/dist/utils/shortcut.js +84 -0
  53. package/package.json +1 -1
@@ -33,7 +33,10 @@ export const toolbar = tv({
33
33
  },
34
34
  variant: {
35
35
  floating: { root: 'inline-flex', segment: 'rounded-full shadow-elevation-1' },
36
- docked: { root: 'fixed left-spacing-0 z-layer-bar w-full', segment: 'w-full rounded-none' }
36
+ docked: {
37
+ root: 'md-vt-persist fixed left-spacing-0 z-layer-bar w-full',
38
+ segment: 'w-full rounded-none'
39
+ }
37
40
  },
38
41
  color: {
39
42
  standard: { segment: 'bg-md-sys-color-surface-container' },
@@ -371,3 +371,29 @@
371
371
  background-color: var(--md-container-transform-color, transparent);
372
372
  box-shadow: var(--md-container-transform-shadow, none);
373
373
  }
374
+
375
+ /*
376
+ App chrome stays put through navigation transitions (#50). Motion's `animateView` puts the
377
+ `target` region (or the root) in its own layer, and the whole `::view-transition` tree paints
378
+ over the live page, so a fixed bar outside `main` was covered by `main`'s snapshots and a fixed
379
+ toolbar or FAB inside it faded and scaled with the page. `md-vt-persist` lifts an element
380
+ into its own layer that is drawn above the page's and never animates: the old snapshot is
381
+ hidden and the new one is the live element.
382
+
383
+ Scoped to the navigation helpers (sharedAxis, lateral, fadeThrough), which set
384
+ `md-navigation-transition` on the root while they run, so a container transform (the search
385
+ view) still grows over the Navbar instead of under it. Built into Navbar, viewport-anchored
386
+ Rail, AppBar and docked Toolbar; add the class to an app-positioned floating Toolbar or FAB.
387
+ Browsers without `match-element` fall back to the old behaviour.
388
+ */
389
+ :root.md-navigation-transition .md-vt-persist {
390
+ view-transition-name: match-element;
391
+ view-transition-class: md-persist;
392
+ }
393
+ ::view-transition-group(*.md-persist),
394
+ ::view-transition-new(*.md-persist) {
395
+ animation: none !important;
396
+ }
397
+ ::view-transition-old(*.md-persist) {
398
+ display: none;
399
+ }
@@ -194,7 +194,9 @@
194
194
  :global(input:disabled + .layer-container) > .tint,
195
195
  :global(:disabled) > .tint
196
196
  ) {
197
- @media (hover: hover) {
197
+ /* pointer: fine too — some touch phones report hover: hover, and a
198
+ tapped element keeps :hover until the next tap elsewhere (#48). */
199
+ @media (hover: hover) and (pointer: fine) {
198
200
  &:is(:global(:hover) > .tint, :global(:active) > .tint) {
199
201
  opacity: 0.08;
200
202
  }
@@ -1,4 +1,5 @@
1
1
  export * from './icon/index.js';
2
+ export * from './shortcut.js';
2
3
  export * from './theme.svelte.js';
3
4
  export * from './types.js';
4
5
  export * from './ui.js';
@@ -1,4 +1,5 @@
1
1
  export * from './icon/index.js';
2
+ export * from './shortcut.js';
2
3
  export * from './theme.svelte.js';
3
4
  export * from './types.js';
4
5
  export * from './ui.js';
@@ -0,0 +1,26 @@
1
+ /**
2
+ * A keyboard shortcut, written as `aria-keyshortcuts` writes one: modifiers, then the key, joined
3
+ * by `+`. `'/'`, `'Mod+K'`, `'Alt+Shift+P'`. `Mod` is ⌘ on Apple platforms and Ctrl elsewhere,
4
+ * the key each platform's apps use for their own shortcuts.
5
+ */
6
+ export type Shortcut = string;
7
+ /** Whether this is an Apple platform, where `Mod` is ⌘. False during SSR. */
8
+ export declare function isApplePlatform(): boolean;
9
+ /**
10
+ * Whether a keydown is this shortcut. Modifiers must match exactly. Digits match by physical key,
11
+ * since Alt+1 types `¡` on a Mac; letters match by the character typed, falling back to the
12
+ * physical key on non-Latin layouts, so ⌘K still works with a Cyrillic layout on.
13
+ */
14
+ export declare function matchesShortcut(e: KeyboardEvent, shortcut: Shortcut, apple?: boolean): boolean;
15
+ /** Whether a keydown's target takes text, where a bare `/` is typing, not a shortcut. */
16
+ export declare function isEditableTarget(target: EventTarget | null): boolean;
17
+ /**
18
+ * Whether a page-wide shortcut should fire for this keydown: it matches, nothing handled the key
19
+ * first, no IME is composing, a shortcut without ⌘/Ctrl/Alt isn't being typed into a field, and
20
+ * no modal dialog other than the one holding `owner` is open.
21
+ */
22
+ export declare function triggersShortcut(e: KeyboardEvent, shortcut: Shortcut | null | undefined, owner?: Element | null): boolean;
23
+ /** The shortcut for `aria-keyshortcuts`, with `Mod` resolved for this platform. */
24
+ export declare function ariaKeyShortcut(shortcut: Shortcut, apple?: boolean): string;
25
+ /** The shortcut as people read it on this platform: `⌘K` on a Mac, `Ctrl+K` elsewhere. */
26
+ export declare function shortcutLabel(shortcut: Shortcut, apple?: boolean): string;
@@ -0,0 +1,84 @@
1
+ /** Whether this is an Apple platform, where `Mod` is ⌘. False during SSR. */
2
+ export function isApplePlatform() {
3
+ if (typeof navigator === 'undefined')
4
+ return false;
5
+ const platform = navigator.userAgentData?.platform ??
6
+ navigator.platform;
7
+ return /mac|iphone|ipad|ipod/i.test(platform ?? '');
8
+ }
9
+ function parse(shortcut, apple) {
10
+ const parts = shortcut.split('+');
11
+ const key = parts.pop() ?? '';
12
+ const modifiers = new Set(parts.map((m) => (m === 'Mod' ? (apple ? 'Meta' : 'Control') : m)));
13
+ return { key, modifiers };
14
+ }
15
+ /**
16
+ * Whether a keydown is this shortcut. Modifiers must match exactly. Digits match by physical key,
17
+ * since Alt+1 types `¡` on a Mac; letters match by the character typed, falling back to the
18
+ * physical key on non-Latin layouts, so ⌘K still works with a Cyrillic layout on.
19
+ */
20
+ export function matchesShortcut(e, shortcut, apple = isApplePlatform()) {
21
+ const { key, modifiers } = parse(shortcut, apple);
22
+ if (e.metaKey !== modifiers.has('Meta') ||
23
+ e.ctrlKey !== modifiers.has('Control') ||
24
+ e.altKey !== modifiers.has('Alt'))
25
+ return false;
26
+ const alphanumeric = /^[a-z0-9]$/i.test(key);
27
+ // Shift is part of typing a symbol like `?`, so it's only checked for letters and digits.
28
+ if (modifiers.has('Shift') ? !e.shiftKey : alphanumeric && e.shiftKey)
29
+ return false;
30
+ if (/^[0-9]$/.test(key))
31
+ return e.code === `Digit${key}` || e.code === `Numpad${key}`;
32
+ if (/^[a-z]$/i.test(key)) {
33
+ return /^[a-z]$/i.test(e.key)
34
+ ? e.key.toLowerCase() === key.toLowerCase()
35
+ : e.code === `Key${key.toUpperCase()}`;
36
+ }
37
+ return e.key === key;
38
+ }
39
+ /** Whether a keydown's target takes text, where a bare `/` is typing, not a shortcut. */
40
+ export function isEditableTarget(target) {
41
+ if (!(target instanceof HTMLElement))
42
+ return false;
43
+ if (target.isContentEditable || target instanceof HTMLTextAreaElement)
44
+ return true;
45
+ if (target instanceof HTMLSelectElement)
46
+ return true;
47
+ return (target instanceof HTMLInputElement &&
48
+ !/^(button|checkbox|color|file|hidden|image|radio|range|reset|submit)$/.test(target.type));
49
+ }
50
+ /**
51
+ * Whether a page-wide shortcut should fire for this keydown: it matches, nothing handled the key
52
+ * first, no IME is composing, a shortcut without ⌘/Ctrl/Alt isn't being typed into a field, and
53
+ * no modal dialog other than the one holding `owner` is open.
54
+ */
55
+ export function triggersShortcut(e, shortcut, owner) {
56
+ if (!shortcut || e.defaultPrevented || e.isComposing || e.repeat)
57
+ return false;
58
+ if (!matchesShortcut(e, shortcut))
59
+ return false;
60
+ if (!/(^|\+)(Mod|Meta|Control|Alt)\+/.test(shortcut) && isEditableTarget(e.target))
61
+ return false;
62
+ const modal = document.querySelector('[aria-modal="true"]');
63
+ return !modal || (!!owner && modal.contains(owner));
64
+ }
65
+ /** The shortcut for `aria-keyshortcuts`, with `Mod` resolved for this platform. */
66
+ export function ariaKeyShortcut(shortcut, apple = isApplePlatform()) {
67
+ const { key, modifiers } = parse(shortcut, apple);
68
+ return [...modifiers, key.length === 1 ? key.toUpperCase() : key].join('+');
69
+ }
70
+ const SYMBOLS = { Meta: '⌘', Control: '⌃', Alt: '⌥', Shift: '⇧' };
71
+ const NAMES = {
72
+ Meta: 'Win',
73
+ Control: 'Ctrl',
74
+ Alt: 'Alt',
75
+ Shift: 'Shift'
76
+ };
77
+ /** The shortcut as people read it on this platform: `⌘K` on a Mac, `Ctrl+K` elsewhere. */
78
+ export function shortcutLabel(shortcut, apple = isApplePlatform()) {
79
+ const { key, modifiers } = parse(shortcut, apple);
80
+ const k = key.length === 1 ? key.toUpperCase() : key;
81
+ return apple
82
+ ? [...modifiers].map((m) => SYMBOLS[m]).join('') + k
83
+ : [...[...modifiers].map((m) => NAMES[m]), k].join('+');
84
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noxlovette/material",
3
- "version": "0.8.3",
3
+ "version": "0.9.1",
4
4
  "type": "module",
5
5
  "description": "A Material Design 3 component library for Svelte, built on Bits UI.",
6
6
  "keywords": [