seblify 0.2.1 → 0.4.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 (141) hide show
  1. package/README.md +145 -49
  2. package/dist/components/AppShell.svelte +1 -1
  3. package/dist/components/Banner.svelte +3 -3
  4. package/dist/components/Button.svelte +4 -4
  5. package/dist/components/action/button/button/Button.svelte +1041 -0
  6. package/dist/components/action/button/button/Button.svelte.d.ts +28 -0
  7. package/dist/components/action/button/button-group/ButtonGroup.svelte +146 -0
  8. package/dist/components/action/button/button-group/ButtonGroup.svelte.d.ts +14 -0
  9. package/dist/components/action/button/floating-action-button/FloatingActionButton.svelte +1102 -0
  10. package/dist/components/action/button/floating-action-button/FloatingActionButton.svelte.d.ts +26 -0
  11. package/dist/components/action/button/icon-button/IconButton.svelte +954 -0
  12. package/dist/components/action/button/icon-button/IconButton.svelte.d.ts +22 -0
  13. package/dist/components/action/button/timed-button/TimedButton.svelte +1143 -0
  14. package/dist/components/action/button/timed-button/TimedButton.svelte.d.ts +32 -0
  15. package/dist/components/action/button/toggle-button/ToggleButton.svelte +1109 -0
  16. package/dist/components/action/button/toggle-button/ToggleButton.svelte.d.ts +28 -0
  17. package/dist/components/action/button/toggle-button-group/ToggleButtonGroup.svelte +242 -0
  18. package/dist/components/action/button/toggle-button-group/ToggleButtonGroup.svelte.d.ts +19 -0
  19. package/dist/components/action/button/toggle-button-group/ToggleButtonGroup.test.svelte +36 -0
  20. package/dist/components/action/button/toggle-button-group/ToggleButtonGroup.test.svelte.d.ts +11 -0
  21. package/dist/components/action/button/toggle-button-group/context.d.ts +8 -0
  22. package/dist/components/action/button/toggle-button-group/context.js +8 -0
  23. package/dist/components/action/input/field/pin-input/PinInput.svelte +4 -4
  24. package/dist/components/action/input/select/checkbox/Checkbox.svelte +4704 -25
  25. package/dist/components/action/input/select/checkbox/Checkbox.svelte.d.ts +28 -0
  26. package/dist/components/action/input/select/checkbox/checkbox-relations.svelte.d.ts +46 -0
  27. package/dist/components/action/input/select/checkbox/checkbox-relations.svelte.js +202 -0
  28. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/bounce.d.ts +1 -0
  29. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/bounce.html +27 -0
  30. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/bounce.js +13 -0
  31. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/bump.d.ts +1 -0
  32. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/bump.html +12 -0
  33. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/bump.js +13 -0
  34. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/draw.d.ts +1 -0
  35. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/draw.html +12 -0
  36. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/draw.js +12 -0
  37. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/fade.d.ts +1 -0
  38. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/fade.html +12 -0
  39. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/fade.js +12 -0
  40. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/pop.d.ts +1 -0
  41. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/pop.html +12 -0
  42. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/pop.js +13 -0
  43. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/rise.d.ts +1 -0
  44. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/rise.html +27 -0
  45. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/rise.js +13 -0
  46. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/scale.d.ts +1 -0
  47. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/scale.html +27 -0
  48. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/scale.js +13 -0
  49. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/visual-state.d.ts +1 -0
  50. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/visual-state.html +12 -0
  51. package/dist/components/action/input/select/checkbox/tests/visual-fixtures/visual-state.js +278 -0
  52. package/dist/components/action/input/select/{theme-switch/ThemeSwitch.svelte → color-mode-switch/ColorModeSwitch.svelte} +8 -8
  53. package/dist/components/action/input/select/color-mode-switch/ColorModeSwitch.svelte.d.ts +10 -0
  54. package/dist/components/action/input/select/segment-control/SegmentControl.svelte +2 -2
  55. package/dist/components/action/input/select/slider/Slider.svelte +1 -1
  56. package/dist/components/action/input/select/switch/Switch.svelte +1004 -99
  57. package/dist/components/action/input/select/switch/Switch.svelte.d.ts +8 -3
  58. package/dist/components/display/annotation/badge/Badge.svelte +732 -63
  59. package/dist/components/display/annotation/badge/Badge.svelte.d.ts +1 -1
  60. package/dist/components/display/annotation/tag/Tag.svelte +670 -58
  61. package/dist/components/display/annotation/tag/Tag.svelte.d.ts +3 -1
  62. package/dist/components/display/data-display/metric/date-time/DateTimeValue.svelte +59 -0
  63. package/dist/components/display/data-display/metric/date-time/DateTimeValue.svelte.d.ts +13 -0
  64. package/dist/components/display/data-display/metric/date-time/DateValue.svelte +52 -0
  65. package/dist/components/display/data-display/metric/date-time/DateValue.svelte.d.ts +11 -0
  66. package/dist/components/display/data-display/metric/date-time/TimeValue.svelte +55 -0
  67. package/dist/components/display/data-display/metric/date-time/TimeValue.svelte.d.ts +12 -0
  68. package/dist/components/display/data-display/metric/duration/Duration.svelte +64 -0
  69. package/dist/components/display/data-display/metric/duration/Duration.svelte.d.ts +16 -0
  70. package/dist/components/display/data-display/metric/relative-time/RelativeTime.svelte +121 -0
  71. package/dist/components/display/data-display/metric/relative-time/RelativeTime.svelte.d.ts +21 -0
  72. package/dist/components/display/data-display/metric/timestamp-card/TimestampCard.svelte +121 -0
  73. package/dist/components/display/data-display/metric/timestamp-card/TimestampCard.svelte.d.ts +25 -0
  74. package/dist/components/display/data-display/visual/timeline/TimelineItem.svelte +660 -51
  75. package/dist/components/display/data-display/visual/timeline/context.d.ts +1 -1
  76. package/dist/components/display/feedback/loading/loading-dots/LoadingDots.svelte +657 -48
  77. package/dist/components/display/feedback/loading/loading-dots/LoadingDots.svelte.d.ts +1 -1
  78. package/dist/components/display/feedback/loading/spinner/Spinner.svelte +657 -48
  79. package/dist/components/display/feedback/loading/spinner/Spinner.svelte.d.ts +1 -1
  80. package/dist/components/display/motion/collapse/Collapse.svelte +115 -0
  81. package/dist/components/display/motion/collapse/Collapse.svelte.d.ts +17 -0
  82. package/dist/components/display/typography/accordion/Accordion.svelte +347 -0
  83. package/dist/components/display/typography/accordion/Accordion.svelte.d.ts +13 -0
  84. package/dist/components/display/typography/accordion/AccordionGroup.svelte +132 -0
  85. package/dist/components/display/typography/accordion/AccordionGroup.svelte.d.ts +11 -0
  86. package/dist/components/display/typography/accordion/context.d.ts +8 -0
  87. package/dist/components/display/typography/accordion/context.js +8 -0
  88. package/dist/components/display/typography/code-snippet/CodeSnippet.svelte +3 -3
  89. package/dist/components/display/typography/eyebrow/Eyebrow.svelte +2 -2
  90. package/dist/components/display/typography/highlight/Highlight.svelte +719 -59
  91. package/dist/components/display/typography/highlight/Highlight.svelte.d.ts +1 -1
  92. package/dist/components/framework/layout/container/app-shell/AppShell.svelte +16 -2
  93. package/dist/components/framework/navigation/context/breadcrumb/Breadcrumb.svelte +1 -1
  94. package/dist/components/framework/navigation/sidebar/sidebar/Sidebar.svelte +35 -10
  95. package/dist/components/framework/navigation/sidebar/sidenav/Sidenav.svelte +5 -5
  96. package/dist/components/framework/overlay/tooltip/Tooltip.svelte +1011 -0
  97. package/dist/components/framework/overlay/tooltip/Tooltip.svelte.d.ts +31 -0
  98. package/dist/components/framework/surface/paper/Paper.svelte +730 -87
  99. package/dist/components/framework/surface/paper/Paper.svelte.d.ts +1 -1
  100. package/dist/components/utility/format/date-time/formatDateTime.d.ts +23 -0
  101. package/dist/components/utility/format/date-time/formatDateTime.js +33 -0
  102. package/dist/components/utility/format/duration/formatDuration.d.ts +15 -0
  103. package/dist/components/utility/format/duration/formatDuration.js +218 -0
  104. package/dist/components/utility/format/relative-time/formatRelativeTime.d.ts +42 -0
  105. package/dist/components/utility/format/relative-time/formatRelativeTime.js +530 -0
  106. package/dist/design-system/inheritance/tokens.js +6 -0
  107. package/dist/design-system/reserved-props/allowed-options.d.ts +9 -4
  108. package/dist/design-system/theme/tokens.d.ts +72 -2
  109. package/dist/design-system/theme/tokens.js +173 -134
  110. package/dist/icons/generated/check-thick.svelte +16 -0
  111. package/dist/icons/generated/check-thick.svelte.d.ts +7 -0
  112. package/dist/icons/generated/check.svelte +16 -0
  113. package/dist/icons/generated/check.svelte.d.ts +7 -0
  114. package/dist/icons/generated/close-thick.svelte +16 -0
  115. package/dist/icons/generated/close-thick.svelte.d.ts +7 -0
  116. package/dist/icons/generated/close.svelte +16 -0
  117. package/dist/icons/generated/close.svelte.d.ts +7 -0
  118. package/dist/icons/generated/index.d.ts +4 -0
  119. package/dist/icons/generated/index.js +4 -0
  120. package/dist/icons/generated/manifest.js +28 -0
  121. package/dist/index.d.ts +22 -2
  122. package/dist/index.js +22 -2
  123. package/dist/styles/tone-context.css +656 -46
  124. package/dist/theme.css +1 -161
  125. package/dist/themes/canopy.css +373 -0
  126. package/dist/themes/cobalt.css +373 -0
  127. package/dist/themes/iris.css +373 -0
  128. package/dist/themes/lumen.css +373 -0
  129. package/dist/themes/mono.css +373 -0
  130. package/dist/themes/moss.css +373 -0
  131. package/dist/themes/noir.css +373 -0
  132. package/dist/themes/plain.css +373 -0
  133. package/dist/themes/pulse.css +373 -0
  134. package/dist/themes/signal.css +373 -0
  135. package/dist/themes/slate.css +373 -0
  136. package/dist/themes/solar.css +373 -0
  137. package/dist/themes/sorbet.css +373 -0
  138. package/dist/themes/studio.css +369 -0
  139. package/dist/themes/vesper.css +373 -0
  140. package/package.json +32 -4
  141. package/dist/components/action/input/select/theme-switch/ThemeSwitch.svelte.d.ts +0 -10
@@ -1,4 +1,4 @@
1
- type SpinnerTone = 'neutral' | 'primary' | 'success' | 'danger' | 'warning' | 'info' | 'inverse';
1
+ type SpinnerTone = 'neutral' | 'primary' | 'success' | 'danger' | 'warning' | 'info';
2
2
  declare const Spinner: import("svelte").Component<{
3
3
  label?: string | undefined;
4
4
  size?: "xs" | "sm" | "md" | "lg" | undefined;
@@ -0,0 +1,115 @@
1
+ <script lang="ts">
2
+ import type { CustomCssSize, SeblifyProps } from 'seblify';
3
+ import type { Snippet } from 'svelte';
4
+
5
+ type CollapseElement = keyof HTMLElementTagNameMap;
6
+
7
+ type Props = SeblifyProps<{
8
+ [key: string]: unknown;
9
+ as?: CollapseElement;
10
+ children?: Snippet;
11
+ class?: string;
12
+ closeEasing?: string;
13
+ collapsedHeight?: number | CustomCssSize;
14
+ duration?: number;
15
+ easing?: string;
16
+ expanded?: boolean;
17
+ openEasing?: string;
18
+ }>;
19
+
20
+ let {
21
+ as = 'div',
22
+ children,
23
+ class: className,
24
+ closeEasing = 'cubic-bezier(0, 0, 0.2, 1)',
25
+ collapsedHeight = 0,
26
+ duration = 220,
27
+ easing,
28
+ expanded = false,
29
+ openEasing = 'cubic-bezier(0, 0, 0.2, 1)',
30
+ ...restProps
31
+ }: Props = $props();
32
+
33
+ let contentElement: HTMLDivElement | undefined;
34
+ let measuredHeight = $state(0);
35
+
36
+ function cssLength(value: number | CustomCssSize): string {
37
+ return typeof value === 'number' ? `${Math.max(0, value)}px` : value;
38
+ }
39
+
40
+ function cssDuration(value: number): string {
41
+ if (!Number.isFinite(value)) {
42
+ return '0ms';
43
+ }
44
+
45
+ return `${Math.max(0, value)}ms`;
46
+ }
47
+
48
+ function measureContentHeight() {
49
+ measuredHeight = contentElement?.scrollHeight ?? 0;
50
+ }
51
+
52
+ const collapsedHeightValue = $derived(cssLength(collapsedHeight));
53
+ const durationValue = $derived(cssDuration(duration));
54
+ const expandedHeightValue = $derived(`${measuredHeight}px`);
55
+ const resolvedHeight = $derived(
56
+ expanded ? expandedHeightValue : collapsedHeightValue,
57
+ );
58
+ const resolvedEasing = $derived(
59
+ easing ?? (expanded ? openEasing : closeEasing),
60
+ );
61
+
62
+ $effect(() => {
63
+ if (!contentElement) {
64
+ return;
65
+ }
66
+
67
+ measureContentHeight();
68
+
69
+ if (typeof ResizeObserver === 'undefined') {
70
+ return;
71
+ }
72
+
73
+ const observer = new ResizeObserver(measureContentHeight);
74
+ observer.observe(contentElement);
75
+
76
+ return () => {
77
+ observer.disconnect();
78
+ };
79
+ });
80
+ </script>
81
+
82
+ <svelte:element
83
+ this={as}
84
+ {...restProps}
85
+ class={`collapse${className ? ` ${className}` : ''}`}
86
+ data-state={expanded ? 'expanded' : 'collapsed'}
87
+ style:--collapse-collapsed-height={collapsedHeightValue}
88
+ style:--collapse-duration={durationValue}
89
+ style:--collapse-easing={resolvedEasing}
90
+ style:--collapse-expanded-height={expandedHeightValue}
91
+ style:--collapse-height={resolvedHeight}
92
+ >
93
+ <div class="collapse__content" bind:this={contentElement}>
94
+ {@render children?.()}
95
+ </div>
96
+ </svelte:element>
97
+
98
+ <style>
99
+ .collapse {
100
+ display: block;
101
+ height: var(--collapse-height);
102
+ overflow: hidden;
103
+ transition: height var(--collapse-duration) var(--collapse-easing);
104
+ }
105
+
106
+ .collapse__content {
107
+ min-height: 0;
108
+ }
109
+
110
+ @media (prefers-reduced-motion: reduce) {
111
+ .collapse {
112
+ transition-duration: 0ms;
113
+ }
114
+ }
115
+ </style>
@@ -0,0 +1,17 @@
1
+ import type { CustomCssSize } from 'seblify';
2
+ import type { Snippet } from 'svelte';
3
+ type CollapseElement = keyof HTMLElementTagNameMap;
4
+ declare const Collapse: import("svelte").Component<{
5
+ [x: string]: unknown;
6
+ as?: CollapseElement | undefined;
7
+ children?: Snippet | undefined;
8
+ class?: string | undefined;
9
+ closeEasing?: string | undefined;
10
+ collapsedHeight?: (number | CustomCssSize) | undefined;
11
+ duration?: number | undefined;
12
+ easing?: string | undefined;
13
+ expanded?: boolean | undefined;
14
+ openEasing?: string | undefined;
15
+ }, {}, "">;
16
+ type Collapse = ReturnType<typeof Collapse>;
17
+ export default Collapse;
@@ -0,0 +1,347 @@
1
+ <script lang="ts" module>
2
+ let nextAccordionId = 0;
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ import type { SeblifyProps } from 'seblify';
7
+ import type { Snippet } from 'svelte';
8
+ import { onMount, tick } from 'svelte';
9
+ import ChevronRightIcon from '../../../../icons/generated/chevron-right.svelte';
10
+ import Collapse from '../../motion/collapse/Collapse.svelte';
11
+ import { getAccordionGroupContext } from './context';
12
+
13
+ const COLLAPSE_DURATION_MS = 220;
14
+
15
+ type Props = SeblifyProps<{
16
+ [key: string]: unknown;
17
+ children?: Snippet;
18
+ class?: string;
19
+ description?: string;
20
+ disabled?: boolean;
21
+ open?: boolean;
22
+ title: string;
23
+ value?: string;
24
+ }>;
25
+
26
+ let {
27
+ children,
28
+ class: className,
29
+ description,
30
+ disabled = false,
31
+ open = $bindable(false),
32
+ title,
33
+ value,
34
+ ...restProps
35
+ }: Props = $props();
36
+
37
+ const group = getAccordionGroupContext();
38
+ const generatedValue = `accordion-${++nextAccordionId}`;
39
+ const itemValue = $derived(value ?? generatedValue);
40
+ let closeTimer: ReturnType<typeof setTimeout> | undefined;
41
+ let hasInitialized = false;
42
+ let isRegisteredWithGroup = $state(false);
43
+ let motionVersion = 0;
44
+ let nativeOpen = $state(open);
45
+ let visualOpen = $state(open);
46
+
47
+ function clearCloseTimer() {
48
+ if (closeTimer) {
49
+ clearTimeout(closeTimer);
50
+ closeTimer = undefined;
51
+ }
52
+ }
53
+
54
+ function nextFrame(): Promise<void> {
55
+ return new Promise((resolve) => {
56
+ if (typeof requestAnimationFrame === 'function') {
57
+ requestAnimationFrame(() => resolve());
58
+ return;
59
+ }
60
+
61
+ setTimeout(resolve, 0);
62
+ });
63
+ }
64
+
65
+ function finishClose(version = motionVersion) {
66
+ if (version !== motionVersion || open) {
67
+ return;
68
+ }
69
+
70
+ clearCloseTimer();
71
+ nativeOpen = false;
72
+ }
73
+
74
+ $effect(() => {
75
+ const nextOpen = open;
76
+ const version = ++motionVersion;
77
+
78
+ clearCloseTimer();
79
+
80
+ if (!hasInitialized) {
81
+ hasInitialized = true;
82
+ nativeOpen = nextOpen;
83
+ visualOpen = nextOpen;
84
+ return;
85
+ }
86
+
87
+ if (nextOpen) {
88
+ nativeOpen = true;
89
+
90
+ void tick()
91
+ .then(nextFrame)
92
+ .then(() => {
93
+ if (version !== motionVersion || !open) {
94
+ return;
95
+ }
96
+
97
+ visualOpen = true;
98
+ });
99
+
100
+ return;
101
+ }
102
+
103
+ nativeOpen = true;
104
+ visualOpen = false;
105
+
106
+ closeTimer = setTimeout(() => {
107
+ finishClose(version);
108
+ }, COLLAPSE_DURATION_MS + 80);
109
+ });
110
+
111
+ onMount(() => {
112
+ if (!group) {
113
+ return;
114
+ }
115
+
116
+ group.register(itemValue, open);
117
+ open = group.isOpen(itemValue);
118
+ isRegisteredWithGroup = true;
119
+
120
+ return () => {
121
+ isRegisteredWithGroup = false;
122
+ group.unregister(itemValue);
123
+ };
124
+ });
125
+
126
+ $effect(() => {
127
+ if (!group || !isRegisteredWithGroup) {
128
+ return;
129
+ }
130
+
131
+ const groupOpen = group.isOpen(itemValue);
132
+
133
+ if (open !== groupOpen) {
134
+ open = groupOpen;
135
+ }
136
+ });
137
+
138
+ function handleSummaryClick(event: MouseEvent) {
139
+ event.preventDefault();
140
+
141
+ if (disabled) {
142
+ event.stopPropagation();
143
+ return;
144
+ }
145
+
146
+ setOpenState(!open);
147
+ }
148
+
149
+ function handleSummaryKeydown(event: KeyboardEvent) {
150
+ if (event.key !== 'Enter' && event.key !== ' ') {
151
+ return;
152
+ }
153
+
154
+ event.preventDefault();
155
+
156
+ if (disabled) {
157
+ event.stopPropagation();
158
+ return;
159
+ }
160
+
161
+ setOpenState(!open);
162
+ }
163
+
164
+ function handleToggle(event: Event) {
165
+ const details = event.currentTarget as HTMLDetailsElement;
166
+
167
+ if (disabled) {
168
+ details.open = nativeOpen;
169
+ return;
170
+ }
171
+
172
+ if (details.open !== nativeOpen) {
173
+ setOpenState(details.open);
174
+ }
175
+ }
176
+
177
+ function setOpenState(nextOpen: boolean) {
178
+ if (group) {
179
+ group.setOpen(itemValue, nextOpen);
180
+ open = group.isOpen(itemValue);
181
+ return;
182
+ }
183
+
184
+ open = nextOpen;
185
+ }
186
+
187
+ function handleCollapseTransitionEnd(event: TransitionEvent) {
188
+ if (event.propertyName !== 'height') {
189
+ return;
190
+ }
191
+
192
+ finishClose();
193
+ }
194
+ </script>
195
+
196
+ <details
197
+ {...restProps}
198
+ class={`accordion${className ? ` ${className}` : ''}`}
199
+ data-disabled={disabled}
200
+ data-state={open ? 'open' : 'closed'}
201
+ open={nativeOpen}
202
+ ontoggle={handleToggle}
203
+ >
204
+ <summary
205
+ class="accordion__summary"
206
+ aria-disabled={disabled}
207
+ aria-expanded={open}
208
+ onclick={handleSummaryClick}
209
+ onkeydown={handleSummaryKeydown}
210
+ tabindex={disabled ? -1 : undefined}
211
+ >
212
+ <span class="accordion__summary-text">
213
+ <span class="accordion__title">{title}</span>
214
+ {#if description}
215
+ <span class="accordion__description">{description}</span>
216
+ {/if}
217
+ </span>
218
+ <span class="accordion__icon" aria-hidden="true">
219
+ <ChevronRightIcon size="1.125rem" />
220
+ </span>
221
+ </summary>
222
+
223
+ <Collapse
224
+ class="accordion__collapse"
225
+ expanded={visualOpen}
226
+ aria-hidden={!open}
227
+ ontransitionend={handleCollapseTransitionEnd}
228
+ >
229
+ <div class="accordion__body">
230
+ {@render children?.()}
231
+ </div>
232
+ </Collapse>
233
+ </details>
234
+
235
+ <style>
236
+ .accordion {
237
+ --accordion-radius: 8px;
238
+ --accordion-border: var(--seblify-color-border, #c8d2df);
239
+ --accordion-border-hover: var(--seblify-color-border-strong, #aab7c5);
240
+ --accordion-surface: var(--seblify-color-surface, #ffffff);
241
+ --accordion-surface-hover: var(--seblify-color-surface-hover, #f1f4f9);
242
+ --accordion-text: var(--seblify-color-text, #172033);
243
+ --accordion-description: var(--seblify-color-text-muted, #516176);
244
+ --accordion-focus-ring: color-mix(
245
+ in srgb,
246
+ var(--seblify-color-focus-ring, #9bd4d8) 72%,
247
+ transparent
248
+ );
249
+
250
+ display: block;
251
+ border: 1px solid var(--accordion-border);
252
+ border-radius: var(--accordion-radius);
253
+ background: var(--accordion-surface);
254
+ color: var(--accordion-text);
255
+ }
256
+
257
+ .accordion__summary {
258
+ display: grid;
259
+ grid-template-columns: minmax(0, 1fr) auto;
260
+ gap: 0.75rem;
261
+ align-items: center;
262
+ min-height: 3rem;
263
+ padding: 0.75rem 1rem;
264
+ border-radius: calc(var(--accordion-radius) - 1px);
265
+ cursor: pointer;
266
+ list-style: none;
267
+ }
268
+
269
+ .accordion[data-state='open'] .accordion__summary {
270
+ border-bottom-left-radius: 0;
271
+ border-bottom-right-radius: 0;
272
+ }
273
+
274
+ .accordion__summary::-webkit-details-marker {
275
+ display: none;
276
+ }
277
+
278
+ .accordion__summary:hover {
279
+ background: var(--accordion-surface-hover);
280
+ }
281
+
282
+ .accordion__summary:focus-visible {
283
+ outline: 3px solid var(--accordion-focus-ring);
284
+ outline-offset: 2px;
285
+ }
286
+
287
+ .accordion__summary-text {
288
+ display: grid;
289
+ gap: 0.25rem;
290
+ min-width: 0;
291
+ }
292
+
293
+ .accordion__title {
294
+ overflow-wrap: anywhere;
295
+ font-size: 0.95rem;
296
+ font-weight: 650;
297
+ line-height: 1.35;
298
+ }
299
+
300
+ .accordion__description {
301
+ overflow-wrap: anywhere;
302
+ color: var(--accordion-description);
303
+ font-size: 0.875rem;
304
+ line-height: 1.4;
305
+ }
306
+
307
+ .accordion__icon {
308
+ display: inline-flex;
309
+ color: var(--accordion-description);
310
+ transition: transform 160ms ease;
311
+ }
312
+
313
+ .accordion[data-state='open'] .accordion__icon {
314
+ transform: rotate(90deg);
315
+ }
316
+
317
+ .accordion :global(.accordion__collapse) {
318
+ display: block;
319
+ }
320
+
321
+ .accordion__body {
322
+ padding: 0 1rem 1rem;
323
+ color: var(--accordion-text);
324
+ font-size: 0.95rem;
325
+ line-height: 1.55;
326
+ }
327
+
328
+ .accordion__body :global(:first-child) {
329
+ margin-top: 0;
330
+ }
331
+
332
+ .accordion__body :global(:last-child) {
333
+ margin-bottom: 0;
334
+ }
335
+
336
+ .accordion[data-disabled='true'] {
337
+ opacity: var(--seblify-opacity-disabled, 0.56);
338
+ }
339
+
340
+ .accordion[data-disabled='true'] .accordion__summary {
341
+ cursor: not-allowed;
342
+ }
343
+
344
+ .accordion[data-disabled='true'] .accordion__summary:hover {
345
+ background: transparent;
346
+ }
347
+ </style>
@@ -0,0 +1,13 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const Accordion: import("svelte").Component<{
3
+ [x: string]: unknown;
4
+ children?: Snippet | undefined;
5
+ class?: string | undefined;
6
+ description?: string | undefined;
7
+ disabled?: boolean | undefined;
8
+ open?: boolean | undefined;
9
+ title: string;
10
+ value?: string | undefined;
11
+ }, {}, "open">;
12
+ type Accordion = ReturnType<typeof Accordion>;
13
+ export default Accordion;
@@ -0,0 +1,132 @@
1
+ <script lang="ts">
2
+ import type { SeblifyProps } from 'seblify';
3
+ import type { Snippet } from 'svelte';
4
+ import { setAccordionGroupContext } from './context';
5
+
6
+ type AccordionGroupElement = keyof HTMLElementTagNameMap;
7
+
8
+ type Props = SeblifyProps<{
9
+ [key: string]: unknown;
10
+ as?: AccordionGroupElement;
11
+ children?: Snippet;
12
+ class?: string;
13
+ multiple?: boolean;
14
+ }>;
15
+
16
+ let {
17
+ as = 'div',
18
+ children,
19
+ class: className,
20
+ multiple = false,
21
+ ...restProps
22
+ }: Props = $props();
23
+
24
+ let itemState = $state<Record<string, boolean>>({});
25
+
26
+ function closeOtherItems(value: string) {
27
+ for (const itemValue of Object.keys(itemState)) {
28
+ if (itemValue !== value) {
29
+ itemState[itemValue] = false;
30
+ }
31
+ }
32
+ }
33
+
34
+ function register(value: string, initialOpen: boolean) {
35
+ if (value in itemState) {
36
+ return;
37
+ }
38
+
39
+ if (initialOpen && !multiple) {
40
+ closeOtherItems(value);
41
+ }
42
+
43
+ itemState[value] = initialOpen;
44
+ }
45
+
46
+ function unregister(value: string) {
47
+ delete itemState[value];
48
+ }
49
+
50
+ function isOpen(value: string): boolean {
51
+ return itemState[value] === true;
52
+ }
53
+
54
+ function setOpen(value: string, open: boolean) {
55
+ if (open && !multiple) {
56
+ closeOtherItems(value);
57
+ }
58
+
59
+ itemState[value] = open;
60
+ }
61
+
62
+ $effect(() => {
63
+ if (multiple) {
64
+ return;
65
+ }
66
+
67
+ const openValues = Object.entries(itemState)
68
+ .filter(([, open]) => open)
69
+ .map(([value]) => value);
70
+
71
+ for (const value of openValues.slice(1)) {
72
+ itemState[value] = false;
73
+ }
74
+ });
75
+
76
+ setAccordionGroupContext({
77
+ isOpen,
78
+ register,
79
+ setOpen,
80
+ unregister,
81
+ });
82
+ </script>
83
+
84
+ <svelte:element
85
+ this={as}
86
+ {...restProps}
87
+ class={`accordion-group${className ? ` ${className}` : ''}`}
88
+ data-multiple={multiple}
89
+ >
90
+ {@render children?.()}
91
+ </svelte:element>
92
+
93
+ <style>
94
+ .accordion-group {
95
+ --accordion-group-radius: 8px;
96
+
97
+ display: block;
98
+ }
99
+
100
+ .accordion-group :global(.accordion) {
101
+ border-radius: 0;
102
+ }
103
+
104
+ .accordion-group :global(.accordion + .accordion) {
105
+ margin-top: -1px;
106
+ }
107
+
108
+ .accordion-group :global(.accordion .accordion__summary) {
109
+ border-radius: 0;
110
+ }
111
+
112
+ .accordion-group :global(.accordion:first-child) {
113
+ border-top-left-radius: var(--accordion-group-radius);
114
+ border-top-right-radius: var(--accordion-group-radius);
115
+ }
116
+
117
+ .accordion-group :global(.accordion:first-child .accordion__summary) {
118
+ border-top-left-radius: calc(var(--accordion-group-radius) - 1px);
119
+ border-top-right-radius: calc(var(--accordion-group-radius) - 1px);
120
+ }
121
+
122
+ .accordion-group :global(.accordion:last-child) {
123
+ border-bottom-left-radius: var(--accordion-group-radius);
124
+ border-bottom-right-radius: var(--accordion-group-radius);
125
+ }
126
+
127
+ .accordion-group
128
+ :global(.accordion:last-child[data-state='closed'] .accordion__summary) {
129
+ border-bottom-left-radius: calc(var(--accordion-group-radius) - 1px);
130
+ border-bottom-right-radius: calc(var(--accordion-group-radius) - 1px);
131
+ }
132
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { Snippet } from 'svelte';
2
+ type AccordionGroupElement = keyof HTMLElementTagNameMap;
3
+ declare const AccordionGroup: import("svelte").Component<{
4
+ [x: string]: unknown;
5
+ as?: AccordionGroupElement | undefined;
6
+ children?: Snippet | undefined;
7
+ class?: string | undefined;
8
+ multiple?: boolean | undefined;
9
+ }, {}, "">;
10
+ type AccordionGroup = ReturnType<typeof AccordionGroup>;
11
+ export default AccordionGroup;
@@ -0,0 +1,8 @@
1
+ export interface AccordionGroupContext {
2
+ isOpen: (value: string) => boolean;
3
+ register: (value: string, initialOpen: boolean) => void;
4
+ setOpen: (value: string, open: boolean) => void;
5
+ unregister: (value: string) => void;
6
+ }
7
+ export declare function setAccordionGroupContext(value: AccordionGroupContext): void;
8
+ export declare function getAccordionGroupContext(): AccordionGroupContext | undefined;
@@ -0,0 +1,8 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ const accordionGroupContextKey = Symbol('seblify-accordion-group');
3
+ export function setAccordionGroupContext(value) {
4
+ setContext(accordionGroupContextKey, value);
5
+ }
6
+ export function getAccordionGroupContext() {
7
+ return getContext(accordionGroupContextKey);
8
+ }
@@ -47,11 +47,11 @@
47
47
  --code-snippet-muted: var(--seblify-color-text-muted, #516176);
48
48
  --code-snippet-comment: var(--seblify-color-text-muted, #516176);
49
49
  --code-snippet-string: var(--seblify-color-success-text, #143d25);
50
- --code-snippet-keyword: var(--seblify-color-fill-primary, #146a6f);
50
+ --code-snippet-keyword: var(--seblify-color-primary-text, #0d4d52);
51
51
  --code-snippet-number: var(--seblify-color-warning-text, #4d3900);
52
52
  --code-snippet-tag: var(--seblify-color-info-text, #102f55);
53
- --code-snippet-attribute: var(--seblify-color-fill-danger, #c93434);
54
- --code-snippet-directive: var(--seblify-color-fill-primary, #146a6f);
53
+ --code-snippet-attribute: var(--seblify-color-danger-fill, #c93434);
54
+ --code-snippet-directive: var(--seblify-color-primary-text, #0d4d52);
55
55
  --code-snippet-punctuation: var(--seblify-color-text-muted, #516176);
56
56
 
57
57
  margin: 0;
@@ -26,7 +26,7 @@
26
26
  display: inline-flex;
27
27
  max-width: 100%;
28
28
  align-items: center;
29
- color: var(--seblify-color-fill-accent, #146a6f);
29
+ color: var(--seblify-color-primary-text, #0d4d52);
30
30
  font-size: 0.75rem;
31
31
  font-weight: 800;
32
32
  letter-spacing: 0.08em;
@@ -43,6 +43,6 @@
43
43
  }
44
44
 
45
45
  .accent {
46
- color: var(--seblify-color-fill-accent, #146a6f);
46
+ color: var(--seblify-color-primary-text, #0d4d52);
47
47
  }
48
48
  </style>