@dryui/ui 1.5.1 → 1.6.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 (85) hide show
  1. package/dist/button-group/context.svelte.js +4 -7
  2. package/dist/calendar/calendar-root.svelte +15 -32
  3. package/dist/chip-group/context.svelte.d.ts +2 -4
  4. package/dist/chip-group/context.svelte.js +2 -9
  5. package/dist/context-menu/context-menu-content.svelte +24 -12
  6. package/dist/context-menu/context-menu-group.svelte +3 -2
  7. package/dist/context-menu/context-menu-item.svelte +8 -61
  8. package/dist/context-menu/context-menu-label.svelte +3 -11
  9. package/dist/context-menu/context-menu-root.svelte +10 -29
  10. package/dist/context-menu/context-menu-separator.svelte +2 -9
  11. package/dist/context-menu/context.svelte.d.ts +2 -12
  12. package/dist/date-picker/datepicker-content.svelte +11 -81
  13. package/dist/date-picker/datepicker-content.svelte.d.ts +1 -1
  14. package/dist/date-picker/datepicker-input-root.svelte +39 -47
  15. package/dist/date-range-picker/date-range-picker-content.svelte +11 -75
  16. package/dist/date-range-picker/date-range-picker-content.svelte.d.ts +1 -1
  17. package/dist/date-range-picker/date-range-picker-root.svelte +44 -49
  18. package/dist/drag-and-drop/group-context.svelte.d.ts +1 -1
  19. package/dist/drag-and-drop/group-context.svelte.js +4 -4
  20. package/dist/dropdown-menu/context.svelte.d.ts +2 -8
  21. package/dist/dropdown-menu/dropdown-menu-content.svelte +15 -3
  22. package/dist/dropdown-menu/dropdown-menu-group.svelte +3 -2
  23. package/dist/dropdown-menu/dropdown-menu-item.svelte +8 -61
  24. package/dist/dropdown-menu/dropdown-menu-label.svelte +3 -11
  25. package/dist/dropdown-menu/dropdown-menu-root.svelte +10 -21
  26. package/dist/dropdown-menu/dropdown-menu-separator.svelte +2 -9
  27. package/dist/flip-card/context.svelte.d.ts +5 -0
  28. package/dist/flip-card/context.svelte.js +2 -0
  29. package/dist/flip-card/flip-card-back.svelte +2 -2
  30. package/dist/flip-card/flip-card-root.svelte +42 -15
  31. package/dist/heading/heading.svelte +10 -1
  32. package/dist/heading/heading.svelte.d.ts +1 -0
  33. package/dist/heading/index.d.ts +1 -0
  34. package/dist/hover-card/hover-card-content.svelte +9 -21
  35. package/dist/hover-card/hover-card-root.svelte +2 -2
  36. package/dist/hover-card/hover-card-root.svelte.d.ts +4 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.js +1 -0
  39. package/dist/internal/anchored-overlay-content.svelte.d.ts +20 -0
  40. package/dist/internal/anchored-overlay-content.svelte.js +28 -0
  41. package/dist/internal/date-family-controller.svelte.d.ts +45 -0
  42. package/dist/internal/date-family-controller.svelte.js +99 -0
  43. package/dist/internal/menu-group.svelte +15 -0
  44. package/dist/internal/menu-group.svelte.d.ts +9 -0
  45. package/dist/internal/menu-item.svelte +82 -0
  46. package/dist/internal/menu-item.svelte.d.ts +11 -0
  47. package/dist/internal/menu-label.svelte +24 -0
  48. package/dist/internal/menu-label.svelte.d.ts +9 -0
  49. package/dist/internal/menu-root-state.svelte.d.ts +24 -0
  50. package/dist/internal/menu-root-state.svelte.js +42 -0
  51. package/dist/internal/menu-separator.svelte +19 -0
  52. package/dist/internal/menu-separator.svelte.d.ts +7 -0
  53. package/dist/internal/motion.js +12 -1
  54. package/dist/internal/picker-popover-content.svelte +112 -0
  55. package/dist/internal/picker-popover-content.svelte.d.ts +16 -0
  56. package/dist/link-preview/link-preview-content.svelte +7 -10
  57. package/dist/list/list-item-icon.svelte +3 -3
  58. package/dist/list/list-item-icon.svelte.d.ts +1 -1
  59. package/dist/list/list-item-text.svelte +3 -3
  60. package/dist/list/list-item-text.svelte.d.ts +1 -1
  61. package/dist/list/list-item.svelte +58 -35
  62. package/dist/list/list-item.svelte.d.ts +8 -2
  63. package/dist/popover/popover-content.svelte +9 -11
  64. package/dist/range-calendar/range-calendar-root.svelte +13 -19
  65. package/dist/text/index.d.ts +1 -0
  66. package/dist/text/text.svelte +3 -1
  67. package/dist/text/text.svelte.d.ts +1 -0
  68. package/dist/theme-toggle/index.d.ts +18 -0
  69. package/dist/theme-toggle/index.js +3 -0
  70. package/dist/theme-toggle/theme-controller.svelte.d.ts +54 -0
  71. package/dist/theme-toggle/theme-controller.svelte.js +121 -0
  72. package/dist/theme-toggle/theme-flash.d.ts +16 -0
  73. package/dist/theme-toggle/theme-flash.js +38 -0
  74. package/dist/theme-toggle/theme-toggle.svelte +189 -0
  75. package/dist/theme-toggle/theme-toggle.svelte.d.ts +40 -0
  76. package/dist/tooltip/tooltip-content.svelte +8 -10
  77. package/dist/typography/heading.svelte +13 -89
  78. package/dist/typography/heading.svelte.d.ts +3 -8
  79. package/dist/typography/index.d.ts +8 -7
  80. package/dist/typography/text.svelte +12 -84
  81. package/dist/typography/text.svelte.d.ts +3 -10
  82. package/package.json +7 -2
  83. package/skills/dryui/SKILL.md +18 -5
  84. package/skills/dryui/rules/composition.md +1 -1
  85. package/skills/dryui/rules/theming.md +1 -2
@@ -0,0 +1,121 @@
1
+ export const DARK_MEDIA_QUERY = '(prefers-color-scheme: dark)';
2
+ export const DEFAULT_STORAGE_KEY = 'dryui-theme';
3
+ function isBrowser() {
4
+ return typeof window !== 'undefined' && typeof document !== 'undefined';
5
+ }
6
+ /**
7
+ * Read the stored theme mode. Exported for testing; production callers
8
+ * should go through `createThemeController`.
9
+ */
10
+ export function readStoredMode(storageKey) {
11
+ if (!isBrowser())
12
+ return 'system';
13
+ try {
14
+ const stored = window.localStorage.getItem(storageKey);
15
+ if (stored === 'light' || stored === 'dark') {
16
+ return stored;
17
+ }
18
+ if (stored !== null) {
19
+ window.localStorage.removeItem(storageKey);
20
+ }
21
+ }
22
+ catch {
23
+ // Storage access can fail in private browsing contexts, so fall back to system mode.
24
+ }
25
+ return 'system';
26
+ }
27
+ /**
28
+ * Persist the theme mode. When `mode === 'system'`, removes the key.
29
+ * Exported for testing.
30
+ */
31
+ export function writeStoredMode(storageKey, mode) {
32
+ if (!isBrowser())
33
+ return;
34
+ try {
35
+ if (mode === 'system') {
36
+ window.localStorage.removeItem(storageKey);
37
+ return;
38
+ }
39
+ window.localStorage.setItem(storageKey, mode);
40
+ }
41
+ catch {
42
+ // Ignore storage failures; the in-memory state still reflects the choice.
43
+ }
44
+ }
45
+ /**
46
+ * Apply the mode to `<html>` via `classList.theme-auto` and `dataset.theme`.
47
+ * Exported for testing.
48
+ */
49
+ export function applyModeToDom(mode) {
50
+ if (!isBrowser())
51
+ return;
52
+ const root = document.documentElement;
53
+ if (mode === 'system') {
54
+ root.classList.add('theme-auto');
55
+ delete root.dataset.theme;
56
+ return;
57
+ }
58
+ root.classList.remove('theme-auto');
59
+ root.dataset.theme = mode;
60
+ }
61
+ /**
62
+ * Create a theme controller that reads the current preference from storage,
63
+ * applies it to `<html>`, and watches the system color-scheme for changes.
64
+ *
65
+ * The returned object exposes reactive `mode`, `isDark`, and `systemPrefersDark`
66
+ * properties backed by Svelte 5 `$state`, plus imperative methods for changing
67
+ * or resetting the mode.
68
+ */
69
+ export function createThemeController(options = {}) {
70
+ const storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;
71
+ const initialMode = readStoredMode(storageKey);
72
+ let mode = $state(initialMode);
73
+ let systemPrefersDark = $state(false);
74
+ let mediaQuery = null;
75
+ let stopWatching = null;
76
+ if (isBrowser()) {
77
+ mediaQuery = window.matchMedia(DARK_MEDIA_QUERY);
78
+ systemPrefersDark = mediaQuery.matches;
79
+ // Align the DOM with the stored preference in case the app-level flash
80
+ // script was skipped or the key changed between renders.
81
+ applyModeToDom(initialMode);
82
+ const handleChange = (event) => {
83
+ systemPrefersDark = event.matches;
84
+ };
85
+ mediaQuery.addEventListener('change', handleChange);
86
+ stopWatching = () => {
87
+ mediaQuery?.removeEventListener('change', handleChange);
88
+ stopWatching = null;
89
+ };
90
+ }
91
+ const isDark = $derived(mode === 'dark' || (mode === 'system' && systemPrefersDark));
92
+ function setMode(next) {
93
+ mode = next;
94
+ applyModeToDom(next);
95
+ writeStoredMode(storageKey, next);
96
+ }
97
+ function cycle() {
98
+ setMode(isDark ? 'light' : 'dark');
99
+ }
100
+ function reset() {
101
+ setMode('system');
102
+ }
103
+ function destroy() {
104
+ stopWatching?.();
105
+ }
106
+ return {
107
+ get mode() {
108
+ return mode;
109
+ },
110
+ get isDark() {
111
+ return isDark;
112
+ },
113
+ get systemPrefersDark() {
114
+ return systemPrefersDark;
115
+ },
116
+ setMode,
117
+ cycle,
118
+ reset,
119
+ destroy
120
+ };
121
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Build an IIFE string that synchronously applies the stored theme preference
3
+ * to `<html>` before the first paint. Embed the result inside a `<script>` tag
4
+ * in the document head, above any stylesheet imports, to prevent a flash of
5
+ * the wrong theme when a user has explicitly chosen light or dark.
6
+ *
7
+ * Usage:
8
+ * ```html
9
+ * <script>{@html themeFlashScript('dryui-theme')}</script>
10
+ * ```
11
+ *
12
+ * The script reads the given storage key, sets `html.classList.theme-auto`
13
+ * when no explicit preference is stored, and sets `html.dataset.theme` to
14
+ * `'light'` or `'dark'` otherwise. Invalid stored values are removed.
15
+ */
16
+ export declare function themeFlashScript(storageKey?: string): string;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Build an IIFE string that synchronously applies the stored theme preference
3
+ * to `<html>` before the first paint. Embed the result inside a `<script>` tag
4
+ * in the document head, above any stylesheet imports, to prevent a flash of
5
+ * the wrong theme when a user has explicitly chosen light or dark.
6
+ *
7
+ * Usage:
8
+ * ```html
9
+ * <script>{@html themeFlashScript('dryui-theme')}</script>
10
+ * ```
11
+ *
12
+ * The script reads the given storage key, sets `html.classList.theme-auto`
13
+ * when no explicit preference is stored, and sets `html.dataset.theme` to
14
+ * `'light'` or `'dark'` otherwise. Invalid stored values are removed.
15
+ */
16
+ export function themeFlashScript(storageKey = 'dryui-theme') {
17
+ // Escape the storage key so it's safe to embed between JSON-style quotes.
18
+ const key = JSON.stringify(storageKey);
19
+ return `(() => {
20
+ const root = document.documentElement;
21
+ try {
22
+ const stored = window.localStorage.getItem(${key});
23
+ const explicit = stored === 'light' || stored === 'dark' ? stored : null;
24
+ if (!explicit && stored !== null) {
25
+ window.localStorage.removeItem(${key});
26
+ }
27
+ root.classList.toggle('theme-auto', explicit === null);
28
+ if (explicit) {
29
+ root.dataset.theme = explicit;
30
+ } else {
31
+ delete root.dataset.theme;
32
+ }
33
+ } catch {
34
+ delete root.dataset.theme;
35
+ root.classList.add('theme-auto');
36
+ }
37
+ })();`;
38
+ }
@@ -0,0 +1,189 @@
1
+ <script lang="ts">
2
+ import { onDestroy, type Snippet } from 'svelte';
3
+ import type { ClassValue, HTMLButtonAttributes } from 'svelte/elements';
4
+ import Toggle from '../toggle/toggle-button.svelte';
5
+ import {
6
+ createThemeController,
7
+ type ThemeController,
8
+ type ThemeMode
9
+ } from './theme-controller.svelte.js';
10
+
11
+ interface Props extends Omit<
12
+ HTMLButtonAttributes,
13
+ 'onclick' | 'onkeydown' | 'disabled' | 'class'
14
+ > {
15
+ disabled?: boolean;
16
+ class?: ClassValue;
17
+ /**
18
+ * Storage key used to persist the explicit theme preference.
19
+ * Defaults to `'dryui-theme'`.
20
+ */
21
+ storageKey?: string;
22
+ /** Toggle size forwarded to the underlying Toggle. */
23
+ size?: 'sm' | 'md' | 'lg';
24
+ /**
25
+ * Optional pre-built controller. When provided, the component uses the
26
+ * shared state instead of creating its own. Useful if multiple toggles
27
+ * exist in the same app or if external code wants to read the mode.
28
+ */
29
+ controller?: ThemeController;
30
+ /** Accessible label. Defaults to `'Toggle theme'`. */
31
+ 'aria-label'?: string;
32
+ /**
33
+ * Custom sun icon snippet. When omitted, a built-in inline SVG is used.
34
+ * The icon is shown when the current theme is light.
35
+ */
36
+ sunIcon?: Snippet;
37
+ /**
38
+ * Custom moon icon snippet. When omitted, a built-in inline SVG is used.
39
+ * The icon is shown when the current theme is dark.
40
+ */
41
+ moonIcon?: Snippet;
42
+ /**
43
+ * Called with the new mode after it is applied. Invoked for explicit
44
+ * picks via click or reset via Alt-click / Escape.
45
+ */
46
+ onModeChange?: (mode: ThemeMode) => void;
47
+ }
48
+
49
+ let {
50
+ storageKey,
51
+ size = 'md',
52
+ controller: externalController,
53
+ 'aria-label': ariaLabel = 'Toggle theme',
54
+ sunIcon,
55
+ moonIcon,
56
+ onModeChange,
57
+ title = 'Alt-click or press Escape to return to system theme',
58
+ disabled,
59
+ ...rest
60
+ }: Props = $props();
61
+
62
+ // Read `externalController` and `storageKey` once at init time on purpose.
63
+ // Swapping the controller or key after mount is not supported; this is an
64
+ // init-time choice, so the linter warning about one-shot capture is expected.
65
+ // svelte-ignore state_referenced_locally
66
+ const ownsController = externalController === undefined;
67
+ // svelte-ignore state_referenced_locally
68
+ const controller = externalController ?? createThemeController({ storageKey });
69
+
70
+ onDestroy(() => {
71
+ if (ownsController) {
72
+ controller.destroy();
73
+ }
74
+ });
75
+
76
+ type ToggleClickEvent = Parameters<NonNullable<HTMLButtonAttributes['onclick']>>[0];
77
+ type ToggleKeyEvent = Parameters<NonNullable<HTMLButtonAttributes['onkeydown']>>[0];
78
+
79
+ function handleClick(event: ToggleClickEvent) {
80
+ event.preventDefault();
81
+
82
+ if (event.altKey) {
83
+ controller.reset();
84
+ onModeChange?.('system');
85
+ return;
86
+ }
87
+
88
+ controller.cycle();
89
+ onModeChange?.(controller.mode);
90
+ }
91
+
92
+ function handleKeydown(event: ToggleKeyEvent) {
93
+ if (event.key !== 'Escape') return;
94
+ event.preventDefault();
95
+ controller.reset();
96
+ onModeChange?.('system');
97
+ }
98
+
99
+ const iconState = $derived(controller.isDark ? 'dark' : 'light');
100
+ </script>
101
+
102
+ <Toggle
103
+ aria-label={ariaLabel}
104
+ aria-keyshortcuts="Escape"
105
+ pressed={controller.isDark}
106
+ data-theme-switch="true"
107
+ onclick={handleClick}
108
+ onkeydown={handleKeydown}
109
+ {disabled}
110
+ {size}
111
+ {title}
112
+ {...rest}
113
+ >
114
+ {#snippet icon()}
115
+ <span class="icons" data-mode={iconState}>
116
+ <span class="icon sun" aria-hidden="true">
117
+ {#if sunIcon}
118
+ {@render sunIcon()}
119
+ {:else}
120
+ <svg
121
+ viewBox="0 0 24 24"
122
+ fill="none"
123
+ stroke="currentColor"
124
+ stroke-width="2"
125
+ stroke-linecap="round"
126
+ stroke-linejoin="round"
127
+ aria-hidden="true"
128
+ >
129
+ <circle cx="12" cy="12" r="4" />
130
+ <path d="M12 2v2" />
131
+ <path d="M12 20v2" />
132
+ <path d="m4.93 4.93 1.41 1.41" />
133
+ <path d="m17.66 17.66 1.41 1.41" />
134
+ <path d="M2 12h2" />
135
+ <path d="M20 12h2" />
136
+ <path d="m6.34 17.66-1.41 1.41" />
137
+ <path d="m19.07 4.93-1.41 1.41" />
138
+ </svg>
139
+ {/if}
140
+ </span>
141
+ <span class="icon moon" aria-hidden="true">
142
+ {#if moonIcon}
143
+ {@render moonIcon()}
144
+ {:else}
145
+ <svg
146
+ viewBox="0 0 24 24"
147
+ fill="none"
148
+ stroke="currentColor"
149
+ stroke-width="2"
150
+ stroke-linecap="round"
151
+ stroke-linejoin="round"
152
+ aria-hidden="true"
153
+ >
154
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
155
+ </svg>
156
+ {/if}
157
+ </span>
158
+ </span>
159
+ {/snippet}
160
+ </Toggle>
161
+
162
+ <style>
163
+ .icons {
164
+ display: grid;
165
+ place-items: center;
166
+ color: var(--dry-theme-toggle-icon, currentColor);
167
+ }
168
+
169
+ .icon {
170
+ grid-column: 1;
171
+ grid-row: 1;
172
+ display: grid;
173
+ place-items: center;
174
+ }
175
+
176
+ .icon svg {
177
+ display: block;
178
+ block-size: var(--dry-theme-toggle-icon-size, 0.75rem);
179
+ aspect-ratio: 1;
180
+ }
181
+
182
+ .icons[data-mode='dark'] .sun {
183
+ display: none;
184
+ }
185
+
186
+ .icons[data-mode='light'] .moon {
187
+ display: none;
188
+ }
189
+ </style>
@@ -0,0 +1,40 @@
1
+ import { type Snippet } from 'svelte';
2
+ import type { ClassValue, HTMLButtonAttributes } from 'svelte/elements';
3
+ import { type ThemeController, type ThemeMode } from './theme-controller.svelte.js';
4
+ interface Props extends Omit<HTMLButtonAttributes, 'onclick' | 'onkeydown' | 'disabled' | 'class'> {
5
+ disabled?: boolean;
6
+ class?: ClassValue;
7
+ /**
8
+ * Storage key used to persist the explicit theme preference.
9
+ * Defaults to `'dryui-theme'`.
10
+ */
11
+ storageKey?: string;
12
+ /** Toggle size forwarded to the underlying Toggle. */
13
+ size?: 'sm' | 'md' | 'lg';
14
+ /**
15
+ * Optional pre-built controller. When provided, the component uses the
16
+ * shared state instead of creating its own. Useful if multiple toggles
17
+ * exist in the same app or if external code wants to read the mode.
18
+ */
19
+ controller?: ThemeController;
20
+ /** Accessible label. Defaults to `'Toggle theme'`. */
21
+ 'aria-label'?: string;
22
+ /**
23
+ * Custom sun icon snippet. When omitted, a built-in inline SVG is used.
24
+ * The icon is shown when the current theme is light.
25
+ */
26
+ sunIcon?: Snippet;
27
+ /**
28
+ * Custom moon icon snippet. When omitted, a built-in inline SVG is used.
29
+ * The icon is shown when the current theme is dark.
30
+ */
31
+ moonIcon?: Snippet;
32
+ /**
33
+ * Called with the new mode after it is applied. Invoked for explicit
34
+ * picks via click or reset via Alt-click / Escape.
35
+ */
36
+ onModeChange?: (mode: ThemeMode) => void;
37
+ }
38
+ declare const ThemeToggle: import("svelte").Component<Props, {}, "">;
39
+ type ThemeToggle = ReturnType<typeof ThemeToggle>;
40
+ export default ThemeToggle;
@@ -1,7 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
- import { createAnchoredPopover, type Placement } from '@dryui/primitives';
4
+ import { type Placement } from '@dryui/primitives';
5
+ import { createAnchoredOverlayContent } from '../internal/anchored-overlay-content.svelte.js';
5
6
  import { getTooltipCtx } from './context.svelte.js';
6
7
 
7
8
  interface Props extends HTMLAttributes<HTMLDivElement> {
@@ -21,25 +22,22 @@
21
22
 
22
23
  const ctx = getTooltipCtx();
23
24
 
24
- let contentEl = $state<HTMLDivElement>();
25
-
26
- const popover = createAnchoredPopover({
27
- triggerEl: () => ctx.triggerEl,
28
- contentEl: () => contentEl ?? null,
29
- open: () => ctx.open,
25
+ const overlay = createAnchoredOverlayContent({
26
+ ctx,
30
27
  placement: () => placement,
31
- offset: () => offset
28
+ offset: () => offset,
29
+ style: () => style
32
30
  });
33
31
  </script>
34
32
 
35
33
  <div
36
- bind:this={contentEl}
34
+ {@attach overlay.bindContent}
35
+ {@attach overlay.position}
37
36
  id={ctx.contentId}
38
37
  role="tooltip"
39
38
  popover="manual"
40
39
  data-tooltip-content
41
40
  data-state={ctx.open ? 'open' : 'closed'}
42
- use:popover.applyPosition={style}
43
41
  class={className}
44
42
  {...rest}
45
43
  >
@@ -1,92 +1,16 @@
1
1
  <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
- import type { HTMLAttributes } from 'svelte/elements';
4
- import { variantAttrs } from '@dryui/primitives';
5
-
6
- interface Props extends HTMLAttributes<HTMLHeadingElement> {
7
- level?: 1 | 2 | 3 | 4 | 5 | 6;
8
- variant?: 'default' | 'display';
9
- children: Snippet;
10
- }
11
-
12
- let { level = 2, variant = 'default', class: className, children, ...rest }: Props = $props();
2
+ import type { HeadingProps } from './index.js';
3
+ import Heading from '../heading/heading.svelte';
4
+
5
+ let {
6
+ level = 2,
7
+ variant = 'default',
8
+ class: className,
9
+ children,
10
+ ...rest
11
+ }: HeadingProps = $props();
13
12
  </script>
14
13
 
15
- {#if level === 1}
16
- <h1 class={className} {...variantAttrs({ level, variant })} {...rest}>
17
- {@render children()}
18
- </h1>
19
- {:else if level === 2}
20
- <h2 class={className} {...variantAttrs({ level, variant })} {...rest}>
21
- {@render children()}
22
- </h2>
23
- {:else if level === 3}
24
- <h3 class={className} {...variantAttrs({ level, variant })} {...rest}>
25
- {@render children()}
26
- </h3>
27
- {:else if level === 4}
28
- <h4 class={className} {...variantAttrs({ level, variant })} {...rest}>
29
- {@render children()}
30
- </h4>
31
- {:else if level === 5}
32
- <h5 class={className} {...variantAttrs({ level, variant })} {...rest}>
33
- {@render children()}
34
- </h5>
35
- {:else}
36
- <h6 class={className} {...variantAttrs({ level, variant })} {...rest}>
37
- {@render children()}
38
- </h6>
39
- {/if}
40
-
41
- <style>
42
- h1,
43
- h2,
44
- h3,
45
- h4,
46
- h5,
47
- h6 {
48
- margin: 0;
49
- color: var(--dry-typography-heading-color, var(--dry-color-text-strong));
50
- font-family: var(--dry-font-sans);
51
- font-weight: 700;
52
- line-height: var(--dry-type-heading-2-leading, 2.5rem);
53
- letter-spacing: -0.03em;
54
- text-wrap: balance;
55
- }
56
-
57
- [data-level='1'] {
58
- font-size: var(--dry-type-heading-1-size, var(--dry-text-4xl-size, 2.25rem));
59
- line-height: var(--dry-type-heading-1-leading, 3rem);
60
- }
61
-
62
- [data-level='2'] {
63
- font-size: var(--dry-type-heading-2-size, var(--dry-text-3xl-size, 1.875rem));
64
- line-height: var(--dry-type-heading-2-leading, 2.5rem);
65
- }
66
-
67
- [data-level='3'] {
68
- font-size: var(--dry-type-heading-3-size, var(--dry-text-2xl-size, 1.5rem));
69
- line-height: var(--dry-type-heading-3-leading, 2rem);
70
- }
71
-
72
- [data-level='4'] {
73
- font-size: var(--dry-type-heading-4-size, var(--dry-text-xl-size, 1.25rem));
74
- line-height: var(--dry-type-heading-4-leading, 1.75rem);
75
- }
76
-
77
- [data-level='5'] {
78
- font-size: var(--dry-type-small-size, var(--dry-text-lg-size, 1.125rem));
79
- line-height: var(--dry-type-small-leading, 1.5rem);
80
- }
81
-
82
- [data-level='6'] {
83
- font-size: var(--dry-type-tiny-size, var(--dry-text-xs-size));
84
- line-height: var(--dry-type-tiny-leading, 1.25rem);
85
- }
86
-
87
- [data-variant='display'] {
88
- font-size: var(--dry-type-display-size, var(--dry-text-4xl-size, 2.25rem));
89
- line-height: var(--dry-type-display-leading, 4rem);
90
- letter-spacing: -0.04em;
91
- }
92
- </style>
14
+ <Heading {level} {variant} {className} {...rest}>
15
+ {@render children()}
16
+ </Heading>
@@ -1,10 +1,5 @@
1
- import type { Snippet } from 'svelte';
2
- import type { HTMLAttributes } from 'svelte/elements';
3
- interface Props extends HTMLAttributes<HTMLHeadingElement> {
4
- level?: 1 | 2 | 3 | 4 | 5 | 6;
5
- variant?: 'default' | 'display';
6
- children: Snippet;
7
- }
8
- declare const Heading: import("svelte").Component<Props, {}, "">;
1
+ import type { HeadingProps } from './index.js';
2
+ import Heading from '../heading/heading.svelte';
3
+ declare const Heading: import("svelte").Component<HeadingProps, {}, "">;
9
4
  type Heading = ReturnType<typeof Heading>;
10
5
  export default Heading;
@@ -1,12 +1,13 @@
1
- import type { HeadingProps as PrimitiveHeadingProps, TextProps as PrimitiveTextProps } from '@dryui/primitives';
2
- export interface HeadingProps extends PrimitiveHeadingProps {
3
- variant?: 'default' | 'display';
4
- }
1
+ import type { TextProps as SharedTextProps } from '../text/index.js';
2
+ export type { HeadingProps } from '../heading/index.js';
5
3
  export type { CodeProps, BlockquoteProps } from '@dryui/primitives';
6
- export interface TextProps extends PrimitiveTextProps {
4
+ export interface TextProps extends Omit<SharedTextProps, 'color' | 'variant'> {
7
5
  color?: 'default' | 'muted' | 'secondary';
8
- variant?: 'default' | 'muted' | 'secondary';
9
- size?: 'sm' | 'md' | 'lg';
6
+ variant?: 'default' | 'muted' | 'secondary' | 'label';
7
+ size?: SharedTextProps['size'];
8
+ font?: SharedTextProps['font'];
9
+ weight?: SharedTextProps['weight'];
10
+ className?: SharedTextProps['className'];
10
11
  }
11
12
  import TypographyHeading from './heading.svelte';
12
13
  import TypographyText from './text.svelte';