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,106 @@
1
+ <script lang="ts">
2
+ type DescribedBy = string | readonly string[] | null;
3
+
4
+ export let id: string | null = null;
5
+ export let name: string | null = null;
6
+ export let value = '';
7
+ export let placeholder: string | null = null;
8
+ export let describedBy: DescribedBy = null;
9
+ export let errorMessageId: string | null = null;
10
+ export let invalid = false;
11
+ export let disabled = false;
12
+ export let readonly = false;
13
+ export let required = false;
14
+ export let rows = 4;
15
+
16
+ $: ariaDescribedBy = normalizeIdRefs(describedBy);
17
+ $: resolvedErrorMessageId = invalid && errorMessageId ? errorMessageId : null;
18
+
19
+ function handleInput(event: Event): void {
20
+ value = (event.currentTarget as HTMLTextAreaElement).value;
21
+ }
22
+
23
+ function normalizeIdRefs(value: DescribedBy): string | null {
24
+ if (value === null) {
25
+ return null;
26
+ }
27
+
28
+ if (typeof value === 'string') {
29
+ const normalized = value.trim();
30
+ return normalized ? normalized : null;
31
+ }
32
+
33
+ const normalized = value.map((entry) => entry.trim()).filter(Boolean);
34
+ return normalized.length > 0 ? normalized.join(' ') : null;
35
+ }
36
+ </script>
37
+
38
+ <textarea
39
+ class="zdp-textarea"
40
+ id={id ?? undefined}
41
+ name={name ?? undefined}
42
+ {value}
43
+ placeholder={placeholder ?? undefined}
44
+ aria-describedby={ariaDescribedBy ?? undefined}
45
+ aria-errormessage={resolvedErrorMessageId ?? undefined}
46
+ aria-invalid={invalid ? 'true' : undefined}
47
+ {disabled}
48
+ readonly={readonly}
49
+ {required}
50
+ {rows}
51
+ oninput={handleInput}
52
+ ></textarea>
53
+
54
+ <style>
55
+ .zdp-textarea {
56
+ background: var(--zdp-color-surface-panel);
57
+ border: var(--zdp-control-border-width) solid var(--zdp-color-line-strong);
58
+ border-radius: var(--zdp-control-radius);
59
+ box-sizing: border-box;
60
+ color: var(--zdp-color-ink-strong);
61
+ font-family: var(--zdp-font-family-sans);
62
+ font-size: var(--zdp-type-control-size);
63
+ line-height: var(--zdp-font-line-height-normal);
64
+ min-height: 7rem;
65
+ padding: var(--zdp-space-3);
66
+ resize: vertical;
67
+ transition:
68
+ background-color var(--zdp-motion-fast) ease,
69
+ border-color var(--zdp-motion-fast) ease,
70
+ color var(--zdp-motion-fast) ease;
71
+ width: 100%;
72
+ }
73
+
74
+ .zdp-textarea::placeholder {
75
+ color: var(--zdp-color-ink-muted);
76
+ }
77
+
78
+ .zdp-textarea:hover:not(:disabled) {
79
+ background: var(--zdp-color-surface-raised);
80
+ border-color: var(--zdp-color-line-strong);
81
+ }
82
+
83
+ .zdp-textarea:focus-visible {
84
+ border-color: var(--zdp-color-focus-line);
85
+ outline: var(--zdp-control-focus-outline-width) solid var(--zdp-color-focus-surface);
86
+ outline-offset: var(--zdp-control-focus-outline-offset);
87
+ }
88
+
89
+ .zdp-textarea[aria-invalid="true"] {
90
+ border-color: var(--zdp-color-accent-danger);
91
+ }
92
+
93
+ .zdp-textarea[readonly] {
94
+ background: var(--zdp-color-surface-raised);
95
+ color: var(--zdp-color-ink-normal);
96
+ }
97
+
98
+ .zdp-textarea[readonly]:hover {
99
+ background: var(--zdp-color-surface-raised);
100
+ }
101
+
102
+ .zdp-textarea:disabled {
103
+ cursor: not-allowed;
104
+ opacity: 0.56;
105
+ }
106
+ </style>
@@ -0,0 +1,148 @@
1
+ <script lang="ts">
2
+ import type { ZdpThemeMode, ZdpThemeToggleSize } from '../theme';
3
+
4
+ export let theme: ZdpThemeMode = 'light';
5
+ export let size: ZdpThemeToggleSize = 'md';
6
+ export let id: string | null = null;
7
+ export let name: string | null = null;
8
+ export let value: string | null = null;
9
+ export let form: string | null = null;
10
+ export let disabled = false;
11
+ export let type: 'button' | 'submit' | 'reset' = 'button';
12
+ export let lightLabel = 'Switch to light mode';
13
+ export let darkLabel = 'Switch to dark mode';
14
+ export let ariaControls: string | null = null;
15
+ export let ariaDescribedBy: string | null = null;
16
+ export let onclick: ((event: MouseEvent) => void) | null = null;
17
+
18
+ $: isDark = theme === 'dark';
19
+ $: ariaLabel = isDark ? lightLabel : darkLabel;
20
+ </script>
21
+
22
+ <button
23
+ class={`zdp-theme-toggle zdp-theme-toggle--${size}`}
24
+ {id}
25
+ {name}
26
+ {value}
27
+ {form}
28
+ {type}
29
+ {disabled}
30
+ aria-label={ariaLabel}
31
+ aria-pressed={isDark}
32
+ aria-controls={ariaControls ?? undefined}
33
+ aria-describedby={ariaDescribedBy ?? undefined}
34
+ data-zdp-theme-toggle
35
+ data-zdp-theme-state={theme}
36
+ onclick={onclick ?? undefined}
37
+ >
38
+ <span class="zdp-theme-toggle__icon zdp-theme-toggle__icon--sun" aria-hidden="true">
39
+ <svg viewBox="0 0 24 24" focusable="false">
40
+ <circle cx="12" cy="12" r="3.6"></circle>
41
+ <path d="M12 3v2.2M12 18.8V21M3 12h2.2M18.8 12H21M5.6 5.6l1.6 1.6M16.8 16.8l1.6 1.6M18.4 5.6l-1.6 1.6M7.2 16.8l-1.6 1.6"></path>
42
+ </svg>
43
+ </span>
44
+ <span class="zdp-theme-toggle__icon zdp-theme-toggle__icon--moon" aria-hidden="true">
45
+ <svg viewBox="0 0 24 24" focusable="false">
46
+ <path d="M17.8 15.4A7 7 0 0 1 8.6 6.2 7.4 7.4 0 1 0 17.8 15.4Z"></path>
47
+ </svg>
48
+ </span>
49
+ </button>
50
+
51
+ <style>
52
+ .zdp-theme-toggle {
53
+ align-items: center;
54
+ background: var(--zdp-color-surface-panel);
55
+ border: var(--zdp-control-border-width) solid var(--zdp-color-line-subtle);
56
+ border-radius: var(--zdp-control-radius);
57
+ box-sizing: border-box;
58
+ color: var(--zdp-color-ink-normal);
59
+ cursor: pointer;
60
+ display: inline-grid;
61
+ flex: 0 0 auto;
62
+ font-family: var(--zdp-font-family-sans);
63
+ justify-items: center;
64
+ line-height: 1;
65
+ padding: 0;
66
+ place-items: center;
67
+ position: relative;
68
+ transition:
69
+ background-color var(--zdp-motion-fast) ease,
70
+ border-color var(--zdp-motion-fast) ease,
71
+ color var(--zdp-motion-fast) ease;
72
+ vertical-align: middle;
73
+ -webkit-user-select: none;
74
+ user-select: none;
75
+ }
76
+
77
+ .zdp-theme-toggle--sm {
78
+ height: var(--zdp-control-icon-sm);
79
+ width: var(--zdp-control-icon-sm);
80
+ }
81
+
82
+ .zdp-theme-toggle--md {
83
+ height: var(--zdp-control-icon-md);
84
+ width: var(--zdp-control-icon-md);
85
+ }
86
+
87
+ .zdp-theme-toggle:hover:not(:disabled) {
88
+ background: var(--zdp-color-surface-raised);
89
+ border-color: var(--zdp-color-line-strong);
90
+ color: var(--zdp-color-ink-strong);
91
+ }
92
+
93
+ .zdp-theme-toggle:focus-visible {
94
+ border-color: var(--zdp-color-focus-line);
95
+ outline: var(--zdp-control-focus-outline-width) solid var(--zdp-color-focus-surface);
96
+ outline-offset: var(--zdp-control-focus-outline-offset);
97
+ }
98
+
99
+ .zdp-theme-toggle:disabled {
100
+ cursor: not-allowed;
101
+ opacity: 0.56;
102
+ }
103
+
104
+ .zdp-theme-toggle__icon {
105
+ color: currentColor;
106
+ display: grid;
107
+ grid-area: 1 / 1;
108
+ height: var(--zdp-control-glyph-md);
109
+ place-items: center;
110
+ transition: opacity var(--zdp-motion-fast) ease;
111
+ width: var(--zdp-control-glyph-md);
112
+ -webkit-user-select: none;
113
+ user-select: none;
114
+ }
115
+
116
+ .zdp-theme-toggle--sm .zdp-theme-toggle__icon {
117
+ height: var(--zdp-control-glyph-sm);
118
+ width: var(--zdp-control-glyph-sm);
119
+ }
120
+
121
+ .zdp-theme-toggle__icon svg {
122
+ display: block;
123
+ fill: none;
124
+ height: 100%;
125
+ stroke: currentColor;
126
+ stroke-linecap: round;
127
+ stroke-linejoin: round;
128
+ stroke-width: 1.8;
129
+ width: 100%;
130
+ }
131
+
132
+ .zdp-theme-toggle__icon--moon svg {
133
+ fill: currentColor;
134
+ stroke: currentColor;
135
+ transform: translate(0.08rem, -0.04rem);
136
+ }
137
+
138
+ .zdp-theme-toggle[data-zdp-theme-state='light'] .zdp-theme-toggle__icon--moon,
139
+ .zdp-theme-toggle[data-zdp-theme-state='dark'] .zdp-theme-toggle__icon--sun {
140
+ opacity: 0;
141
+ }
142
+
143
+ .zdp-theme-toggle[data-zdp-theme-state='dark'] {
144
+ background: var(--zdp-color-surface-raised);
145
+ border-color: var(--zdp-color-line-strong);
146
+ color: var(--zdp-color-ink-strong);
147
+ }
148
+ </style>
@@ -0,0 +1,180 @@
1
+ <script lang="ts">
2
+ import type { ZdpToastTone } from '../toast';
3
+
4
+ export let tone: ZdpToastTone = 'neutral';
5
+ export let labelledBy: string | null = null;
6
+ export let describedBy: string | null = null;
7
+ export let semanticRole: 'status' | 'alert' | 'note' | null = null;
8
+ export let live: 'off' | 'polite' | 'assertive' | null = null;
9
+ export let atomic = true;
10
+ export let dismissLabel = 'Dismiss notification';
11
+ export let onClose: ((event: MouseEvent) => void) | null = null;
12
+
13
+ $: resolvedRole = semanticRole ?? (tone === 'danger' ? 'alert' : 'status');
14
+ $: resolvedLive = live === 'off' ? undefined : live ?? (tone === 'danger' ? 'assertive' : 'polite');
15
+ $: resolvedAtomic = live === 'off' ? undefined : atomic;
16
+ </script>
17
+
18
+ <div
19
+ class={`zdp-toast zdp-toast--${tone}`}
20
+ aria-labelledby={labelledBy ?? undefined}
21
+ aria-describedby={describedBy ?? undefined}
22
+ aria-live={resolvedLive}
23
+ aria-atomic={resolvedAtomic}
24
+ role={resolvedRole ?? undefined}
25
+ >
26
+ <span class="zdp-toast__mark" aria-hidden="true"></span>
27
+ <div class="zdp-toast__body">
28
+ <slot />
29
+ </div>
30
+ {#if onClose}
31
+ <button class="zdp-toast__close" type="button" aria-label={dismissLabel} onclick={onClose}>
32
+ <span aria-hidden="true">×</span>
33
+ </button>
34
+ {/if}
35
+ </div>
36
+
37
+ <style>
38
+ .zdp-toast {
39
+ align-items: start;
40
+ background: var(--zdp-color-surface-panel);
41
+ border: var(--zdp-control-border-width) solid var(--zdp-color-line-strong);
42
+ border-radius: var(--zdp-control-radius);
43
+ box-sizing: border-box;
44
+ color: var(--zdp-color-ink-normal);
45
+ display: grid;
46
+ font-family: var(--zdp-font-family-sans);
47
+ gap: var(--zdp-space-3);
48
+ grid-template-columns: var(--zdp-space-2) minmax(0, 1fr) auto;
49
+ inline-size: min(100%, 28rem);
50
+ line-height: var(--zdp-type-body-small-line-height);
51
+ min-width: 0;
52
+ padding: var(--zdp-space-4);
53
+ }
54
+
55
+ .zdp-toast__mark {
56
+ align-self: stretch;
57
+ background: var(--zdp-color-line-strong);
58
+ border-radius: var(--zdp-radius-sm);
59
+ display: block;
60
+ min-block-size: calc(var(--zdp-type-body-small-size) * var(--zdp-type-body-small-line-height));
61
+ -webkit-user-select: none;
62
+ user-select: none;
63
+ width: var(--zdp-space-2);
64
+ }
65
+
66
+ .zdp-toast__body {
67
+ display: grid;
68
+ gap: var(--zdp-space-1);
69
+ min-width: 0;
70
+ }
71
+
72
+ .zdp-toast__body :global(*) {
73
+ margin-bottom: 0;
74
+ margin-top: 0;
75
+ }
76
+
77
+ .zdp-toast__body :global(strong),
78
+ .zdp-toast__body :global(.zdp-toast__title) {
79
+ color: var(--zdp-color-ink-strong);
80
+ font-size: var(--zdp-type-body-small-size);
81
+ font-weight: var(--zdp-font-weight-medium);
82
+ line-height: var(--zdp-type-body-small-line-height);
83
+ }
84
+
85
+ .zdp-toast__body :global(p),
86
+ .zdp-toast__body :global(.zdp-toast__message) {
87
+ color: var(--zdp-color-ink-muted);
88
+ font-size: var(--zdp-type-caption-size);
89
+ line-height: var(--zdp-type-caption-line-height);
90
+ overflow-wrap: var(--zdp-i18n-overflow-wrap);
91
+ }
92
+
93
+ .zdp-toast__body :global(.zdp-toast__action) {
94
+ align-items: center;
95
+ align-self: start;
96
+ background: transparent;
97
+ border: var(--zdp-control-border-width) solid var(--zdp-color-line-subtle);
98
+ border-radius: var(--zdp-control-radius);
99
+ color: var(--zdp-color-ink-strong);
100
+ cursor: pointer;
101
+ display: inline-flex;
102
+ font-family: var(--zdp-font-family-sans);
103
+ font-size: var(--zdp-type-caption-size);
104
+ font-weight: var(--zdp-font-weight-medium);
105
+ justify-content: center;
106
+ line-height: var(--zdp-type-caption-line-height);
107
+ margin-block-start: var(--zdp-space-3);
108
+ min-height: var(--zdp-control-height-sm);
109
+ padding: 0 var(--zdp-space-3);
110
+ text-decoration-line: none;
111
+ transition:
112
+ background-color var(--zdp-motion-fast) ease,
113
+ border-color var(--zdp-motion-fast) ease,
114
+ color var(--zdp-motion-fast) ease;
115
+ -webkit-user-select: none;
116
+ user-select: none;
117
+ }
118
+
119
+ .zdp-toast__body :global(.zdp-toast__action:hover) {
120
+ background: var(--zdp-color-surface-raised);
121
+ border-color: var(--zdp-color-line-strong);
122
+ }
123
+
124
+ .zdp-toast__body :global(.zdp-toast__action:focus-visible) {
125
+ border-color: var(--zdp-color-focus-line);
126
+ outline: var(--zdp-control-focus-outline-width) solid var(--zdp-color-focus-surface);
127
+ outline-offset: var(--zdp-control-focus-outline-offset);
128
+ }
129
+
130
+ .zdp-toast__close {
131
+ align-items: center;
132
+ background: transparent;
133
+ border: var(--zdp-control-border-width) solid transparent;
134
+ border-radius: var(--zdp-control-radius);
135
+ color: var(--zdp-color-ink-muted);
136
+ cursor: pointer;
137
+ display: inline-flex;
138
+ font-family: var(--zdp-font-family-sans);
139
+ font-size: var(--zdp-type-title-size);
140
+ height: var(--zdp-control-height-sm);
141
+ justify-content: center;
142
+ line-height: 1;
143
+ padding: 0;
144
+ -webkit-user-select: none;
145
+ user-select: none;
146
+ width: var(--zdp-control-height-sm);
147
+ }
148
+
149
+ .zdp-toast__close:hover {
150
+ background: var(--zdp-color-surface-raised);
151
+ border-color: var(--zdp-color-line-strong);
152
+ color: var(--zdp-color-ink-strong);
153
+ }
154
+
155
+ .zdp-toast__close:focus-visible {
156
+ border-color: var(--zdp-color-focus-line);
157
+ outline: var(--zdp-control-focus-outline-width) solid var(--zdp-color-focus-surface);
158
+ outline-offset: var(--zdp-control-focus-outline-offset);
159
+ }
160
+
161
+ .zdp-toast--info .zdp-toast__mark {
162
+ background: var(--zdp-color-accent-primary);
163
+ }
164
+
165
+ .zdp-toast--success .zdp-toast__mark {
166
+ background: var(--zdp-color-accent-success);
167
+ }
168
+
169
+ .zdp-toast--warning .zdp-toast__mark {
170
+ background: var(--zdp-color-accent-warning);
171
+ }
172
+
173
+ .zdp-toast--danger {
174
+ border-color: var(--zdp-color-accent-danger);
175
+ }
176
+
177
+ .zdp-toast--danger .zdp-toast__mark {
178
+ background: var(--zdp-color-accent-danger);
179
+ }
180
+ </style>
@@ -0,0 +1,83 @@
1
+ <script lang="ts">
2
+ export let as: 'div' | 'section' | 'nav' | 'header' | 'footer' = 'div';
3
+ export let gap: 'sm' | 'md' | 'lg' = 'md';
4
+ export let align: 'start' | 'center' | 'end' = 'center';
5
+ export let labelledBy: string | null = null;
6
+
7
+ $: labelledGroupRole = as === 'div' && labelledBy ? 'group' : undefined;
8
+ </script>
9
+
10
+ <svelte:element
11
+ this={as}
12
+ class={`zdp-toolbar zdp-toolbar--gap-${gap} zdp-toolbar--align-${align}`}
13
+ role={labelledGroupRole}
14
+ aria-labelledby={labelledBy ?? undefined}
15
+ >
16
+ <div class="zdp-toolbar__main">
17
+ <slot />
18
+ </div>
19
+ <div class="zdp-toolbar__actions">
20
+ <slot name="actions" />
21
+ </div>
22
+ </svelte:element>
23
+
24
+ <style>
25
+ .zdp-toolbar {
26
+ align-items: center;
27
+ display: flex;
28
+ flex-wrap: wrap;
29
+ gap: var(--zdp-space-3);
30
+ justify-content: space-between;
31
+ min-width: 0;
32
+ }
33
+
34
+ .zdp-toolbar--gap-sm {
35
+ gap: var(--zdp-space-2);
36
+ }
37
+
38
+ .zdp-toolbar--gap-md {
39
+ gap: var(--zdp-space-3);
40
+ }
41
+
42
+ .zdp-toolbar--gap-lg {
43
+ gap: var(--zdp-space-4);
44
+ }
45
+
46
+ .zdp-toolbar--align-start {
47
+ align-items: flex-start;
48
+ }
49
+
50
+ .zdp-toolbar--align-center {
51
+ align-items: center;
52
+ }
53
+
54
+ .zdp-toolbar--align-end {
55
+ align-items: flex-end;
56
+ }
57
+
58
+ .zdp-toolbar__main,
59
+ .zdp-toolbar__actions {
60
+ align-items: center;
61
+ display: flex;
62
+ flex-wrap: wrap;
63
+ gap: var(--zdp-space-2);
64
+ min-width: 0;
65
+ }
66
+
67
+ .zdp-toolbar__main {
68
+ flex: 1 1 16rem;
69
+ }
70
+
71
+ .zdp-toolbar__actions {
72
+ flex: 0 1 auto;
73
+ justify-content: flex-end;
74
+ }
75
+
76
+ @media (max-width: 42rem) {
77
+ .zdp-toolbar__main,
78
+ .zdp-toolbar__actions {
79
+ inline-size: 100%;
80
+ justify-content: flex-start;
81
+ }
82
+ }
83
+ </style>
@@ -0,0 +1,199 @@
1
+ <script context="module" lang="ts">
2
+ let tooltipIdCounter = 0;
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ import { onMount } from 'svelte';
7
+
8
+ export let text: string;
9
+ export let placement: 'top' | 'right' | 'bottom' | 'left' = 'top';
10
+ export let id: string | null = null;
11
+ export let disabled = false;
12
+
13
+ let rootElement: HTMLElement | null = null;
14
+ const fallbackId = `zdp-tooltip-${++tooltipIdCounter}`;
15
+
16
+ let dismissed = false;
17
+ let pointerInside = false;
18
+
19
+ $: tooltipId = id ?? fallbackId;
20
+ $: describedBy = disabled ? null : tooltipId;
21
+
22
+ onMount(() => {
23
+ const root = rootElement;
24
+
25
+ if (!root) {
26
+ return;
27
+ }
28
+
29
+ root.addEventListener('mouseenter', handleMouseenter);
30
+ root.addEventListener('mouseleave', handleMouseleave);
31
+ root.addEventListener('focusin', handleFocusin);
32
+ root.addEventListener('focusout', handleFocusout);
33
+ root.addEventListener('keydown', handleKeydown);
34
+
35
+ return () => {
36
+ root.removeEventListener('mouseenter', handleMouseenter);
37
+ root.removeEventListener('mouseleave', handleMouseleave);
38
+ root.removeEventListener('focusin', handleFocusin);
39
+ root.removeEventListener('focusout', handleFocusout);
40
+ root.removeEventListener('keydown', handleKeydown);
41
+ };
42
+ });
43
+
44
+ function handleMouseenter(): void {
45
+ pointerInside = true;
46
+ dismissed = false;
47
+ }
48
+
49
+ function handleMouseleave(): void {
50
+ pointerInside = false;
51
+ dismissed = false;
52
+ }
53
+
54
+ function handleFocusin(): void {
55
+ if (!pointerInside) {
56
+ dismissed = false;
57
+ }
58
+ }
59
+
60
+ function handleFocusout(): void {
61
+ if (!pointerInside) {
62
+ dismissed = false;
63
+ }
64
+ }
65
+
66
+ function handleKeydown(event: KeyboardEvent): void {
67
+ if (event.key !== 'Escape' || disabled) {
68
+ return;
69
+ }
70
+
71
+ dismissed = true;
72
+
73
+ if (typeof document !== 'undefined' && document.activeElement instanceof HTMLElement) {
74
+ document.activeElement.blur();
75
+ }
76
+ }
77
+ </script>
78
+
79
+ <span
80
+ class={`zdp-tooltip zdp-tooltip--${placement}`}
81
+ data-disabled={disabled ? 'true' : undefined}
82
+ data-dismissed={dismissed ? 'true' : undefined}
83
+ bind:this={rootElement}
84
+ >
85
+ <span class="zdp-tooltip__trigger">
86
+ <slot describedBy={describedBy} />
87
+ </span>
88
+ {#if !disabled}
89
+ <span
90
+ id={tooltipId}
91
+ class="zdp-tooltip__content"
92
+ role="tooltip"
93
+ >
94
+ {text}
95
+ </span>
96
+ {/if}
97
+ </span>
98
+
99
+ <style>
100
+ .zdp-tooltip {
101
+ display: inline-flex;
102
+ min-width: 0;
103
+ position: relative;
104
+ vertical-align: middle;
105
+ }
106
+
107
+ .zdp-tooltip__trigger {
108
+ display: inline-flex;
109
+ min-width: 0;
110
+ }
111
+
112
+ .zdp-tooltip__content {
113
+ background: var(--zdp-color-ink-strong);
114
+ border: var(--zdp-control-border-width) solid var(--zdp-color-line-strong);
115
+ border-radius: var(--zdp-control-radius);
116
+ bottom: var(--zdp-tooltip-bottom, auto);
117
+ color: var(--zdp-color-surface-panel);
118
+ font-family: var(--zdp-font-family-sans);
119
+ font-size: var(--zdp-type-caption-size);
120
+ left: var(--zdp-tooltip-left, auto);
121
+ line-height: var(--zdp-type-caption-line-height);
122
+ opacity: 0;
123
+ padding: var(--zdp-space-1) var(--zdp-space-2);
124
+ pointer-events: none;
125
+ position: absolute;
126
+ right: var(--zdp-tooltip-right, auto);
127
+ top: var(--zdp-tooltip-top, auto);
128
+ transform: var(--zdp-tooltip-transform, none);
129
+ -webkit-user-select: none;
130
+ user-select: none;
131
+ white-space: nowrap;
132
+ z-index: 30;
133
+ }
134
+
135
+ .zdp-tooltip--top {
136
+ --zdp-tooltip-bottom: calc(100% + var(--zdp-space-2));
137
+ --zdp-tooltip-left: 0;
138
+ --zdp-tooltip-right: auto;
139
+ --zdp-tooltip-top: auto;
140
+ --zdp-tooltip-transform: none;
141
+ }
142
+
143
+ .zdp-tooltip--top .zdp-tooltip__content {
144
+ bottom: var(--zdp-tooltip-bottom);
145
+ left: var(--zdp-tooltip-left);
146
+ }
147
+
148
+ .zdp-tooltip--right {
149
+ --zdp-tooltip-bottom: auto;
150
+ --zdp-tooltip-left: calc(100% + var(--zdp-space-2));
151
+ --zdp-tooltip-right: auto;
152
+ --zdp-tooltip-top: 0;
153
+ --zdp-tooltip-transform: none;
154
+ }
155
+
156
+ .zdp-tooltip--right .zdp-tooltip__content {
157
+ left: var(--zdp-tooltip-left);
158
+ top: var(--zdp-tooltip-top);
159
+ }
160
+
161
+ .zdp-tooltip--bottom {
162
+ --zdp-tooltip-bottom: auto;
163
+ --zdp-tooltip-left: 0;
164
+ --zdp-tooltip-right: auto;
165
+ --zdp-tooltip-top: calc(100% + var(--zdp-space-2));
166
+ --zdp-tooltip-transform: none;
167
+ }
168
+
169
+ .zdp-tooltip--bottom .zdp-tooltip__content {
170
+ left: var(--zdp-tooltip-left);
171
+ top: var(--zdp-tooltip-top);
172
+ }
173
+
174
+ .zdp-tooltip--left {
175
+ --zdp-tooltip-bottom: auto;
176
+ --zdp-tooltip-left: auto;
177
+ --zdp-tooltip-right: calc(100% + var(--zdp-space-2));
178
+ --zdp-tooltip-top: 0;
179
+ --zdp-tooltip-transform: none;
180
+ }
181
+
182
+ .zdp-tooltip--left .zdp-tooltip__content {
183
+ right: var(--zdp-tooltip-right);
184
+ top: var(--zdp-tooltip-top);
185
+ }
186
+
187
+ .zdp-tooltip:hover .zdp-tooltip__content,
188
+ .zdp-tooltip:focus-within .zdp-tooltip__content {
189
+ opacity: 1;
190
+ }
191
+
192
+ .zdp-tooltip[data-dismissed="true"] .zdp-tooltip__content {
193
+ opacity: 0;
194
+ }
195
+
196
+ .zdp-tooltip[data-disabled="true"] {
197
+ cursor: default;
198
+ }
199
+ </style>