zdp-design-system 0.43.8

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 (110) hide show
  1. package/CHANGELOG.md +449 -0
  2. package/LICENSE +21 -0
  3. package/README.md +568 -0
  4. package/THIRD_PARTY_NOTICES.md +34 -0
  5. package/dist/code.ts +2 -0
  6. package/dist/combobox.ts +9 -0
  7. package/dist/command.ts +1 -0
  8. package/dist/components/Accordion.svelte +97 -0
  9. package/dist/components/Avatar.svelte +90 -0
  10. package/dist/components/Badge.svelte +61 -0
  11. package/dist/components/Breadcrumb.svelte +97 -0
  12. package/dist/components/Button.svelte +163 -0
  13. package/dist/components/Callout.svelte +81 -0
  14. package/dist/components/Card.svelte +151 -0
  15. package/dist/components/CardHeader.svelte +58 -0
  16. package/dist/components/Checkbox.svelte +135 -0
  17. package/dist/components/CodeBlock.svelte +247 -0
  18. package/dist/components/Combobox.svelte +552 -0
  19. package/dist/components/CommandField.svelte +230 -0
  20. package/dist/components/ConfirmAction.svelte +307 -0
  21. package/dist/components/Container.svelte +63 -0
  22. package/dist/components/Dialog.svelte +303 -0
  23. package/dist/components/Disclosure.svelte +176 -0
  24. package/dist/components/Divider.svelte +41 -0
  25. package/dist/components/EmptyState.svelte +79 -0
  26. package/dist/components/ErrorText.svelte +18 -0
  27. package/dist/components/Field.svelte +38 -0
  28. package/dist/components/Grid.svelte +76 -0
  29. package/dist/components/HelpText.svelte +17 -0
  30. package/dist/components/Icon.svelte +45 -0
  31. package/dist/components/IconButton.svelte +162 -0
  32. package/dist/components/IdentityChip.svelte +130 -0
  33. package/dist/components/Inline.svelte +85 -0
  34. package/dist/components/InlineCode.svelte +27 -0
  35. package/dist/components/Input.svelte +109 -0
  36. package/dist/components/Kbd.svelte +63 -0
  37. package/dist/components/KeyValue.svelte +73 -0
  38. package/dist/components/Label.svelte +43 -0
  39. package/dist/components/Link.svelte +70 -0
  40. package/dist/components/LocaleSwitcher.svelte +209 -0
  41. package/dist/components/Menu.svelte +491 -0
  42. package/dist/components/Page.svelte +36 -0
  43. package/dist/components/PageHeader.svelte +93 -0
  44. package/dist/components/Pagination.svelte +297 -0
  45. package/dist/components/Popover.svelte +208 -0
  46. package/dist/components/Progress.svelte +111 -0
  47. package/dist/components/Radio.svelte +132 -0
  48. package/dist/components/Section.svelte +52 -0
  49. package/dist/components/SegmentedControl.svelte +190 -0
  50. package/dist/components/Select.svelte +88 -0
  51. package/dist/components/ShareDock.svelte +304 -0
  52. package/dist/components/Sheet.svelte +332 -0
  53. package/dist/components/ShortcutHint.svelte +52 -0
  54. package/dist/components/Skeleton.svelte +82 -0
  55. package/dist/components/SkipLink.svelte +40 -0
  56. package/dist/components/SortHeader.svelte +138 -0
  57. package/dist/components/Spinner.svelte +82 -0
  58. package/dist/components/Stack.svelte +62 -0
  59. package/dist/components/StatusToast.svelte +133 -0
  60. package/dist/components/Surface.svelte +53 -0
  61. package/dist/components/Switch.svelte +152 -0
  62. package/dist/components/Table.svelte +94 -0
  63. package/dist/components/TableToolbar.svelte +195 -0
  64. package/dist/components/Tabs.svelte +205 -0
  65. package/dist/components/TermSheet.svelte +392 -0
  66. package/dist/components/TermTrigger.svelte +70 -0
  67. package/dist/components/TextScaleControl.svelte +219 -0
  68. package/dist/components/Textarea.svelte +106 -0
  69. package/dist/components/ThemeToggle.svelte +148 -0
  70. package/dist/components/Toast.svelte +180 -0
  71. package/dist/components/Toolbar.svelte +83 -0
  72. package/dist/components/Tooltip.svelte +199 -0
  73. package/dist/components/VisuallyHidden.svelte +18 -0
  74. package/dist/disclosure.ts +11 -0
  75. package/dist/focusable.ts +36 -0
  76. package/dist/identity.ts +5 -0
  77. package/dist/index.d.ts +106 -0
  78. package/dist/index.js +76 -0
  79. package/dist/index.ts +106 -0
  80. package/dist/menu.ts +12 -0
  81. package/dist/modal-layer.ts +108 -0
  82. package/dist/pagination.ts +10 -0
  83. package/dist/preferences.js +14 -0
  84. package/dist/preferences.ts +36 -0
  85. package/dist/progress.ts +4 -0
  86. package/dist/schemas/design-tokens.schema.json +119 -0
  87. package/dist/segmented.ts +8 -0
  88. package/dist/share.d.ts +48 -0
  89. package/dist/share.js +115 -0
  90. package/dist/share.ts +99 -0
  91. package/dist/sheet.ts +3 -0
  92. package/dist/shortcuts.js +125 -0
  93. package/dist/shortcuts.ts +153 -0
  94. package/dist/styles/brand-fonts.css +10 -0
  95. package/dist/styles/components.css +4686 -0
  96. package/dist/styles/expressive-fonts.css +2 -0
  97. package/dist/styles/index.css +2 -0
  98. package/dist/styles/locale-fonts.css +4 -0
  99. package/dist/styles/tokens.css +413 -0
  100. package/dist/table-tools.ts +10 -0
  101. package/dist/term.ts +16 -0
  102. package/dist/theme.ts +2 -0
  103. package/dist/toast.ts +14 -0
  104. package/dist/tokens/zdp.tokens.json +241 -0
  105. package/dist/tokens.js +122 -0
  106. package/dist/tokens.ts +123 -0
  107. package/docs/CONSUMER_CONTRACT.md +482 -0
  108. package/docs/EXTERNAL_UI_ADOPTION.md +141 -0
  109. package/docs/INTERACTIVE_PRIMITIVE_AUDIT.md +127 -0
  110. package/package.json +78 -0
@@ -0,0 +1,304 @@
1
+ <script lang="ts">
2
+ import { zdpShareIcons, type ZdpShareDockItem } from '../share';
3
+ import Tooltip from './Tooltip.svelte';
4
+
5
+ export let items: readonly ZdpShareDockItem[] = [];
6
+ export let ariaLabel = 'Share';
7
+ export let labelledBy: string | null = null;
8
+ export let placement: 'side' | 'rail' | 'bottom' | 'inline' = 'side';
9
+
10
+ function handleClick(event: MouseEvent, item: ZdpShareDockItem): void {
11
+ item.onclick?.(event, item);
12
+ }
13
+
14
+ function resolvedRel(item: ZdpShareDockItem): string | undefined {
15
+ if (item.rel) {
16
+ return item.rel;
17
+ }
18
+
19
+ return item.target === '_blank' ? 'noopener noreferrer' : undefined;
20
+ }
21
+
22
+ $: tooltipPlacement = (placement === 'side' || placement === 'rail' ? 'left' : 'top') as 'left' | 'top';
23
+ </script>
24
+
25
+ <aside
26
+ class={`zdp-share-dock zdp-share-dock--${placement}`}
27
+ aria-label={labelledBy ? undefined : ariaLabel}
28
+ aria-labelledby={labelledBy ?? undefined}
29
+ >
30
+ <div class="zdp-share-dock__list">
31
+ {#each items as item (item.id)}
32
+ {@const icon = zdpShareIcons[item.icon]}
33
+ {#if item.href}
34
+ <Tooltip text={item.label} placement={tooltipPlacement} let:describedBy>
35
+ <a
36
+ class="zdp-share-action"
37
+ href={item.href}
38
+ target={item.target ?? undefined}
39
+ rel={resolvedRel(item)}
40
+ aria-label={item.ariaLabel ?? item.label}
41
+ aria-describedby={describedBy ?? undefined}
42
+ data-share-id={item.id}
43
+ onclick={(event) => handleClick(event, item)}
44
+ >
45
+ <span class="zdp-share-action__mark" aria-hidden="true">
46
+ <svg class={`zdp-share-icon zdp-share-icon--${item.icon}`} viewBox={icon.viewBox} focusable="false">
47
+ {#each icon.lines ?? [] as line}
48
+ <line
49
+ x1={line.x1}
50
+ y1={line.y1}
51
+ x2={line.x2}
52
+ y2={line.y2}
53
+ stroke="currentColor"
54
+ stroke-linecap="round"
55
+ stroke-width={line.strokeWidth ?? '2'}
56
+ />
57
+ {/each}
58
+ {#each icon.paths ?? [] as path}
59
+ <path
60
+ d={path.d}
61
+ fill={path.fill === false ? 'none' : 'currentColor'}
62
+ stroke={path.stroke ? 'currentColor' : undefined}
63
+ stroke-linecap={path.strokeLinecap}
64
+ stroke-linejoin={path.strokeLinejoin}
65
+ stroke-width={path.strokeWidth}
66
+ />
67
+ {/each}
68
+ {#each icon.circles ?? [] as circle}
69
+ <circle
70
+ cx={circle.cx}
71
+ cy={circle.cy}
72
+ r={circle.r}
73
+ fill={circle.fill === false || circle.stroke ? 'none' : 'currentColor'}
74
+ stroke={circle.stroke ? 'currentColor' : undefined}
75
+ stroke-width={circle.strokeWidth}
76
+ />
77
+ {/each}
78
+ </svg>
79
+ </span>
80
+ </a>
81
+ </Tooltip>
82
+ {:else}
83
+ <Tooltip text={item.label} placement={tooltipPlacement} disabled={item.disabled} let:describedBy>
84
+ <button
85
+ class="zdp-share-action"
86
+ type="button"
87
+ disabled={item.disabled}
88
+ aria-label={item.ariaLabel ?? item.label}
89
+ aria-describedby={describedBy ?? undefined}
90
+ data-share-id={item.id}
91
+ onclick={(event) => handleClick(event, item)}
92
+ >
93
+ <span class="zdp-share-action__mark" aria-hidden="true">
94
+ <svg class={`zdp-share-icon zdp-share-icon--${item.icon}`} viewBox={icon.viewBox} focusable="false">
95
+ {#each icon.lines ?? [] as line}
96
+ <line
97
+ x1={line.x1}
98
+ y1={line.y1}
99
+ x2={line.x2}
100
+ y2={line.y2}
101
+ stroke="currentColor"
102
+ stroke-linecap="round"
103
+ stroke-width={line.strokeWidth ?? '2'}
104
+ />
105
+ {/each}
106
+ {#each icon.paths ?? [] as path}
107
+ <path
108
+ d={path.d}
109
+ fill={path.fill === false ? 'none' : 'currentColor'}
110
+ stroke={path.stroke ? 'currentColor' : undefined}
111
+ stroke-linecap={path.strokeLinecap}
112
+ stroke-linejoin={path.strokeLinejoin}
113
+ stroke-width={path.strokeWidth}
114
+ />
115
+ {/each}
116
+ {#each icon.circles ?? [] as circle}
117
+ <circle
118
+ cx={circle.cx}
119
+ cy={circle.cy}
120
+ r={circle.r}
121
+ fill={circle.fill === false || circle.stroke ? 'none' : 'currentColor'}
122
+ stroke={circle.stroke ? 'currentColor' : undefined}
123
+ stroke-width={circle.strokeWidth}
124
+ />
125
+ {/each}
126
+ </svg>
127
+ </span>
128
+ </button>
129
+ </Tooltip>
130
+ {/if}
131
+ {/each}
132
+ </div>
133
+ </aside>
134
+
135
+ <style>
136
+ .zdp-share-dock {
137
+ color: var(--zdp-color-ink-normal);
138
+ font-family: var(--zdp-font-family-sans);
139
+ z-index: 20;
140
+ }
141
+
142
+ .zdp-share-dock--side {
143
+ position: fixed;
144
+ right: max(var(--zdp-space-3), calc((100vw - var(--zdp-breakpoint-desktop)) / 2 + var(--zdp-space-4)));
145
+ top: 40vh;
146
+ }
147
+
148
+ .zdp-share-dock--rail {
149
+ align-self: start;
150
+ position: sticky;
151
+ top: var(--zdp-space-5);
152
+ }
153
+
154
+ .zdp-share-dock--bottom {
155
+ bottom: var(--zdp-space-3);
156
+ left: var(--zdp-space-3);
157
+ position: fixed;
158
+ right: var(--zdp-space-3);
159
+ }
160
+
161
+ .zdp-share-dock--inline {
162
+ position: static;
163
+ transform: none;
164
+ }
165
+
166
+ .zdp-share-dock__list {
167
+ background: var(--zdp-color-surface-panel);
168
+ border: var(--zdp-control-border-width) solid var(--zdp-color-line-subtle);
169
+ border-radius: var(--zdp-radius-lg);
170
+ display: grid;
171
+ gap: var(--zdp-space-1);
172
+ padding: var(--zdp-space-1);
173
+ }
174
+
175
+ .zdp-share-dock--bottom .zdp-share-dock__list,
176
+ .zdp-share-dock--inline .zdp-share-dock__list {
177
+ display: flex;
178
+ flex-wrap: wrap;
179
+ justify-content: center;
180
+ }
181
+
182
+ .zdp-share-action {
183
+ align-items: center;
184
+ background: transparent;
185
+ border: var(--zdp-control-border-width) solid transparent;
186
+ border-radius: var(--zdp-control-radius);
187
+ box-sizing: border-box;
188
+ color: var(--zdp-color-ink-muted);
189
+ cursor: pointer;
190
+ display: inline-flex;
191
+ height: var(--zdp-control-icon-sm);
192
+ justify-content: center;
193
+ position: relative;
194
+ text-decoration-line: none;
195
+ transition:
196
+ background-color var(--zdp-motion-fast) ease,
197
+ border-color var(--zdp-motion-fast) ease,
198
+ color var(--zdp-motion-fast) ease;
199
+ -webkit-user-select: none;
200
+ user-select: none;
201
+ width: var(--zdp-control-icon-sm);
202
+ }
203
+
204
+ .zdp-share-action:hover:not(:disabled),
205
+ .zdp-share-action:focus-visible {
206
+ background: var(--zdp-color-surface-raised);
207
+ border-color: var(--zdp-color-line-subtle);
208
+ color: var(--zdp-color-ink-strong);
209
+ }
210
+
211
+ .zdp-share-action:focus-visible {
212
+ border-color: var(--zdp-color-focus-line);
213
+ outline: var(--zdp-control-focus-outline-width) solid var(--zdp-color-focus-surface);
214
+ outline-offset: var(--zdp-control-focus-outline-offset);
215
+ }
216
+
217
+ .zdp-share-action:disabled {
218
+ cursor: not-allowed;
219
+ opacity: 0.56;
220
+ }
221
+
222
+ .zdp-share-action__mark,
223
+ .zdp-share-icon {
224
+ height: var(--zdp-control-glyph-sm);
225
+ width: var(--zdp-control-glyph-sm);
226
+ }
227
+
228
+ .zdp-share-action__mark {
229
+ align-items: center;
230
+ display: inline-flex;
231
+ flex: 0 0 auto;
232
+ justify-content: center;
233
+ line-height: 1;
234
+ -webkit-user-select: none;
235
+ user-select: none;
236
+ }
237
+
238
+ .zdp-share-icon {
239
+ display: block;
240
+ overflow: visible;
241
+ }
242
+
243
+ @media (max-width: 57.5rem) {
244
+ .zdp-share-dock--side {
245
+ bottom: var(--zdp-space-3);
246
+ left: var(--zdp-space-3);
247
+ right: var(--zdp-space-3);
248
+ top: auto;
249
+ }
250
+
251
+ .zdp-share-dock--side .zdp-share-dock__list {
252
+ display: flex;
253
+ flex-wrap: wrap;
254
+ justify-content: center;
255
+ max-inline-size: calc(100vw - var(--zdp-space-6));
256
+ }
257
+
258
+ .zdp-share-dock--rail {
259
+ inline-size: 100%;
260
+ }
261
+
262
+ .zdp-share-dock--rail .zdp-share-dock__list {
263
+ display: flex;
264
+ flex-wrap: wrap;
265
+ justify-content: center;
266
+ }
267
+
268
+ :global(.zdp-share-dock--side .zdp-tooltip.zdp-tooltip--left),
269
+ :global(.zdp-share-dock--rail .zdp-tooltip.zdp-tooltip--left) {
270
+ --zdp-tooltip-bottom: calc(100% + var(--zdp-space-2));
271
+ --zdp-tooltip-left: 50%;
272
+ --zdp-tooltip-right: auto;
273
+ --zdp-tooltip-top: auto;
274
+ --zdp-tooltip-transform: translateX(-50%);
275
+ }
276
+
277
+ :global(.zdp-share-dock--side .zdp-tooltip:first-child),
278
+ :global(.zdp-share-dock--rail .zdp-tooltip:first-child) {
279
+ --zdp-tooltip-left: 0;
280
+ --zdp-tooltip-transform: none;
281
+ }
282
+
283
+ :global(.zdp-share-dock--side .zdp-tooltip:last-child),
284
+ :global(.zdp-share-dock--rail .zdp-tooltip:last-child) {
285
+ --zdp-tooltip-left: auto;
286
+ --zdp-tooltip-right: 0;
287
+ --zdp-tooltip-transform: none;
288
+ }
289
+
290
+ }
291
+
292
+ @media (max-width: 42rem) {
293
+ .zdp-share-dock--side,
294
+ .zdp-share-dock--bottom {
295
+ bottom: var(--zdp-space-2);
296
+ }
297
+
298
+ .zdp-share-dock__list {
299
+ gap: var(--zdp-space-1);
300
+ padding: var(--zdp-space-1);
301
+ }
302
+
303
+ }
304
+ </style>
@@ -0,0 +1,332 @@
1
+ <script lang="ts">
2
+ import { onDestroy, tick } from 'svelte';
3
+ import { isZdpFocusableElement, zdpFocusableSelector } from '../focusable';
4
+ import { createZdpModalLayer } from '../modal-layer';
5
+ import type { ZdpSheetPlacement, ZdpSheetSize } from '../sheet';
6
+
7
+ export let open = false;
8
+ export let id: string | null = null;
9
+ export let labelledBy: string;
10
+ export let describedBy: string | null = null;
11
+ export let placement: ZdpSheetPlacement = 'right';
12
+ export let size: ZdpSheetSize = 'md';
13
+ export let closeLabel = 'Close';
14
+ export let closeOnEscape = true;
15
+ export let closeOnBackdrop = true;
16
+ export let onClose: (() => void) | null = null;
17
+
18
+ let layerElement: HTMLDivElement | null = null;
19
+ let panelElement: HTMLDivElement | null = null;
20
+ let previousFocusElement: HTMLElement | null = null;
21
+ let wasOpen = false;
22
+ const modalLayer = createZdpModalLayer();
23
+
24
+ $: {
25
+ modalLayer.setActive(open, layerElement);
26
+
27
+ if (open && !wasOpen) {
28
+ wasOpen = true;
29
+ void handleSheetOpened();
30
+ } else if (!open && wasOpen) {
31
+ wasOpen = false;
32
+ restorePreviousFocus();
33
+ }
34
+ }
35
+
36
+ onDestroy(() => {
37
+ modalLayer.destroy();
38
+ });
39
+
40
+ async function handleSheetOpened(): Promise<void> {
41
+ if (typeof document !== 'undefined') {
42
+ const activeElement = document.activeElement;
43
+ previousFocusElement = activeElement instanceof HTMLElement ? activeElement : null;
44
+ }
45
+
46
+ await tick();
47
+
48
+ const firstFocusableElement = getFocusableElements()[0];
49
+ (firstFocusableElement ?? panelElement)?.focus();
50
+ }
51
+
52
+ function requestClose(): void {
53
+ open = false;
54
+ onClose?.();
55
+ }
56
+
57
+ function restorePreviousFocus(): void {
58
+ if (previousFocusElement !== null && document.contains(previousFocusElement)) {
59
+ previousFocusElement.focus();
60
+ }
61
+
62
+ previousFocusElement = null;
63
+ }
64
+
65
+ function handleBackdropClick(): void {
66
+ if (closeOnBackdrop) {
67
+ requestClose();
68
+ }
69
+ }
70
+
71
+ function handleKeydown(event: KeyboardEvent): void {
72
+ if (event.key === 'Escape' && closeOnEscape) {
73
+ event.preventDefault();
74
+ requestClose();
75
+ return;
76
+ }
77
+
78
+ if (event.key !== 'Tab') {
79
+ return;
80
+ }
81
+
82
+ const focusableElements = getFocusableElements();
83
+
84
+ if (focusableElements.length === 0) {
85
+ event.preventDefault();
86
+ panelElement?.focus();
87
+ return;
88
+ }
89
+
90
+ const firstElement = focusableElements[0];
91
+ const lastElement = focusableElements[focusableElements.length - 1];
92
+ const activeElement = document.activeElement;
93
+
94
+ if (event.shiftKey && activeElement === firstElement) {
95
+ event.preventDefault();
96
+ lastElement.focus();
97
+ } else if (!event.shiftKey && activeElement === lastElement) {
98
+ event.preventDefault();
99
+ firstElement.focus();
100
+ }
101
+ }
102
+
103
+ function getFocusableElements(): HTMLElement[] {
104
+ if (panelElement === null) {
105
+ return [];
106
+ }
107
+
108
+ return Array.from(panelElement.querySelectorAll<HTMLElement>(zdpFocusableSelector)).filter(isZdpFocusableElement);
109
+ }
110
+ </script>
111
+
112
+ {#if open}
113
+ <div class="zdp-sheet-layer" bind:this={layerElement}>
114
+ <button
115
+ class="zdp-sheet__backdrop"
116
+ type="button"
117
+ aria-label={closeLabel}
118
+ tabindex="-1"
119
+ onclick={handleBackdropClick}
120
+ ></button>
121
+ <div
122
+ class={`zdp-sheet zdp-sheet--${placement} zdp-sheet--${size}`}
123
+ id={id ?? undefined}
124
+ bind:this={panelElement}
125
+ role="dialog"
126
+ aria-modal="true"
127
+ aria-labelledby={labelledBy}
128
+ aria-describedby={describedBy ?? undefined}
129
+ data-zdp-sheet-placement={placement}
130
+ data-zdp-sheet-size={size}
131
+ data-zdp-sheet-surface="sheet"
132
+ tabindex="-1"
133
+ onkeydown={handleKeydown}
134
+ >
135
+ <header class="zdp-sheet__header">
136
+ <div class="zdp-sheet__title">
137
+ <slot name="title" />
138
+ </div>
139
+ <button class="zdp-sheet__close" type="button" aria-label={closeLabel} onclick={requestClose}>
140
+ <span aria-hidden="true">×</span>
141
+ </button>
142
+ </header>
143
+ <div class="zdp-sheet__body">
144
+ <slot />
145
+ </div>
146
+ <div class="zdp-sheet__footer">
147
+ <slot name="footer" />
148
+ </div>
149
+ </div>
150
+ </div>
151
+ {/if}
152
+
153
+ <style>
154
+ .zdp-sheet-layer {
155
+ display: contents;
156
+ }
157
+
158
+ .zdp-sheet__backdrop {
159
+ background: rgb(47 36 24 / 0.32);
160
+ border: 0;
161
+ cursor: pointer;
162
+ inset: 0;
163
+ margin: 0;
164
+ padding: 0;
165
+ position: fixed;
166
+ z-index: 940;
167
+ }
168
+
169
+ :global([data-zdp-theme="dark"]) .zdp-sheet__backdrop {
170
+ background: rgb(10 8 5 / 0.66);
171
+ }
172
+
173
+ .zdp-sheet {
174
+ background: var(--zdp-color-surface-panel);
175
+ border: var(--zdp-control-border-width) solid var(--zdp-color-line-strong);
176
+ box-sizing: border-box;
177
+ color: var(--zdp-color-ink-normal);
178
+ display: grid;
179
+ font-family: var(--zdp-font-family-sans);
180
+ gap: var(--zdp-space-4);
181
+ max-block-size: calc(100vh - var(--zdp-space-6));
182
+ min-width: 0;
183
+ overflow: auto;
184
+ padding: var(--zdp-space-5);
185
+ position: fixed;
186
+ z-index: 941;
187
+ }
188
+
189
+ .zdp-sheet--right,
190
+ .zdp-sheet--left {
191
+ block-size: calc(100vh - var(--zdp-space-6));
192
+ border-radius: var(--zdp-control-radius);
193
+ inset-block: var(--zdp-space-3);
194
+ }
195
+
196
+ .zdp-sheet--right {
197
+ inset-inline-end: var(--zdp-space-3);
198
+ }
199
+
200
+ .zdp-sheet--left {
201
+ inset-inline-start: var(--zdp-space-3);
202
+ }
203
+
204
+ .zdp-sheet--bottom {
205
+ border-end-end-radius: 0;
206
+ border-end-start-radius: 0;
207
+ border-radius: var(--zdp-control-radius) var(--zdp-control-radius) 0 0;
208
+ inset-block-end: 0;
209
+ inset-inline: 0;
210
+ max-block-size: min(34rem, calc(100vh - var(--zdp-space-6)));
211
+ }
212
+
213
+ .zdp-sheet--sm {
214
+ inline-size: min(24rem, calc(100vw - var(--zdp-space-6)));
215
+ }
216
+
217
+ .zdp-sheet--md {
218
+ inline-size: min(30rem, calc(100vw - var(--zdp-space-6)));
219
+ }
220
+
221
+ .zdp-sheet--lg {
222
+ inline-size: min(38rem, calc(100vw - var(--zdp-space-6)));
223
+ }
224
+
225
+ .zdp-sheet--bottom.zdp-sheet--sm,
226
+ .zdp-sheet--bottom.zdp-sheet--md,
227
+ .zdp-sheet--bottom.zdp-sheet--lg {
228
+ inline-size: auto;
229
+ }
230
+
231
+ .zdp-sheet--bottom.zdp-sheet--lg {
232
+ max-block-size: min(42rem, calc(100vh - var(--zdp-space-6)));
233
+ }
234
+
235
+ .zdp-sheet:focus-visible {
236
+ border-color: var(--zdp-color-focus-line);
237
+ outline: var(--zdp-control-focus-outline-width) solid var(--zdp-color-focus-surface);
238
+ outline-offset: var(--zdp-control-focus-outline-offset);
239
+ }
240
+
241
+ .zdp-sheet__header {
242
+ align-items: start;
243
+ display: grid;
244
+ gap: var(--zdp-space-3);
245
+ grid-template-columns: minmax(0, 1fr) auto;
246
+ }
247
+
248
+ .zdp-sheet__title {
249
+ color: var(--zdp-color-ink-strong);
250
+ display: grid;
251
+ gap: var(--zdp-space-1);
252
+ min-width: 0;
253
+ }
254
+
255
+ .zdp-sheet__title :global(*) {
256
+ margin: 0;
257
+ }
258
+
259
+ .zdp-sheet__body {
260
+ color: var(--zdp-color-ink-normal);
261
+ display: grid;
262
+ gap: var(--zdp-space-3);
263
+ line-height: var(--zdp-type-body-line-height);
264
+ min-width: 0;
265
+ }
266
+
267
+ .zdp-sheet__body :global(*) {
268
+ margin-bottom: 0;
269
+ margin-top: 0;
270
+ }
271
+
272
+ .zdp-sheet__footer {
273
+ align-items: center;
274
+ border-block-start: var(--zdp-control-border-width) solid var(--zdp-color-line-subtle);
275
+ display: flex;
276
+ flex-wrap: wrap;
277
+ gap: var(--zdp-space-3);
278
+ justify-content: end;
279
+ min-width: 0;
280
+ padding-block-start: var(--zdp-space-3);
281
+ }
282
+
283
+ .zdp-sheet__close {
284
+ align-items: center;
285
+ background: var(--zdp-color-surface-panel);
286
+ border: var(--zdp-control-border-width) solid var(--zdp-color-line-strong);
287
+ border-radius: var(--zdp-control-radius);
288
+ color: var(--zdp-color-ink-normal);
289
+ cursor: pointer;
290
+ display: inline-flex;
291
+ font-family: var(--zdp-font-family-sans);
292
+ font-size: var(--zdp-type-control-size);
293
+ height: var(--zdp-control-icon-sm);
294
+ justify-content: center;
295
+ line-height: 1;
296
+ transition:
297
+ background-color var(--zdp-motion-fast) ease,
298
+ border-color var(--zdp-motion-fast) ease,
299
+ color var(--zdp-motion-fast) ease;
300
+ -webkit-user-select: none;
301
+ user-select: none;
302
+ width: var(--zdp-control-icon-sm);
303
+ }
304
+
305
+ .zdp-sheet__close:hover:not(:disabled) {
306
+ background: var(--zdp-color-surface-raised);
307
+ border-color: var(--zdp-color-line-strong);
308
+ color: var(--zdp-color-ink-strong);
309
+ }
310
+
311
+ .zdp-sheet__close:focus-visible {
312
+ border-color: var(--zdp-color-focus-line);
313
+ outline: var(--zdp-control-focus-outline-width) solid var(--zdp-color-focus-surface);
314
+ outline-offset: var(--zdp-control-focus-outline-offset);
315
+ }
316
+
317
+ @media (max-width: 720px) {
318
+ .zdp-sheet,
319
+ .zdp-sheet--right,
320
+ .zdp-sheet--left {
321
+ block-size: auto;
322
+ border-end-end-radius: 0;
323
+ border-end-start-radius: 0;
324
+ border-radius: var(--zdp-control-radius) var(--zdp-control-radius) 0 0;
325
+ inline-size: auto;
326
+ inset-block: auto 0;
327
+ inset-inline: 0;
328
+ max-block-size: min(34rem, calc(100vh - var(--zdp-space-6)));
329
+ padding: var(--zdp-space-4);
330
+ }
331
+ }
332
+ </style>
@@ -0,0 +1,52 @@
1
+ <script lang="ts">
2
+ import Kbd from './Kbd.svelte';
3
+
4
+ export let keys: readonly string[] = [];
5
+ export let size: 'sm' | 'md' = 'md';
6
+ export let ariaLabel: string | null = null;
7
+
8
+ $: resolvedAriaLabel = ariaLabel ?? keys.join(' ');
9
+ $: labelledGroupRole = resolvedAriaLabel ? 'group' : undefined;
10
+ </script>
11
+
12
+ <span
13
+ class={`zdp-shortcut-hint zdp-shortcut-hint--${size}`}
14
+ role={labelledGroupRole}
15
+ aria-label={resolvedAriaLabel || undefined}
16
+ >
17
+ {#each keys as key, index}
18
+ {#if index > 0}
19
+ <span class="zdp-shortcut-hint__separator" aria-hidden="true">+</span>
20
+ {/if}
21
+ <Kbd label={key} {size} />
22
+ {/each}
23
+ </span>
24
+
25
+ <style>
26
+ .zdp-shortcut-hint {
27
+ align-items: center;
28
+ color: var(--zdp-color-ink-muted);
29
+ display: inline-flex;
30
+ flex: 0 0 auto;
31
+ gap: var(--zdp-space-1);
32
+ line-height: 1;
33
+ min-width: 0;
34
+ -webkit-user-select: none;
35
+ user-select: none;
36
+ white-space: nowrap;
37
+ }
38
+
39
+ .zdp-shortcut-hint--sm {
40
+ font-size: var(--zdp-type-caption-size);
41
+ }
42
+
43
+ .zdp-shortcut-hint--md {
44
+ font-size: var(--zdp-type-label-size);
45
+ }
46
+
47
+ .zdp-shortcut-hint__separator {
48
+ color: var(--zdp-color-ink-muted);
49
+ font-size: 0.85em;
50
+ line-height: 1;
51
+ }
52
+ </style>