@spectral_labs/ui 1.7.0 → 1.8.0-next.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 (150) hide show
  1. package/LICENSE +21 -0
  2. package/THIRD_PARTY_NOTICES.md +201 -0
  3. package/package.json +8 -2
  4. package/dist/components/__tests__/overlay-scrim-source.test.js +0 -134
  5. package/dist/components/accordion/__tests__/AccordionTest.svelte +0 -31
  6. package/dist/components/accordion/__tests__/accordion.test.svelte.js +0 -139
  7. package/dist/components/alert-dialog/__tests__/AlertDialogTest.svelte +0 -28
  8. package/dist/components/alert-dialog/__tests__/alert-dialog.a11y.test.js +0 -42
  9. package/dist/components/alert-dialog/__tests__/alert-dialog.integration.test.svelte.js +0 -51
  10. package/dist/components/alert-dialog/__tests__/alert-dialog.test.svelte.js +0 -113
  11. package/dist/components/app-bar/__tests__/app-bar.test.svelte.js +0 -30
  12. package/dist/components/aspect-ratio/__tests__/aspect-ratio.test.svelte.js +0 -22
  13. package/dist/components/avatar/__tests__/avatar.test.svelte.js +0 -26
  14. package/dist/components/badge/__tests__/badge.test.svelte.js +0 -30
  15. package/dist/components/bottom-sheet/__tests__/BottomSheetTest.svelte +0 -22
  16. package/dist/components/bottom-sheet/__tests__/bottom-sheet.test.svelte.js +0 -83
  17. package/dist/components/button/__tests__/button.test.svelte.js +0 -63
  18. package/dist/components/calendar/__tests__/CalendarTest.svelte +0 -56
  19. package/dist/components/calendar/__tests__/calendar.test.svelte.js +0 -190
  20. package/dist/components/card/__tests__/card.test.svelte.js +0 -30
  21. package/dist/components/checkbox/__tests__/checkbox.test.svelte.js +0 -44
  22. package/dist/components/chips/__tests__/chips.test.svelte.js +0 -26
  23. package/dist/components/collapsible/__tests__/CollapsibleTest.svelte +0 -18
  24. package/dist/components/collapsible/__tests__/collapsible.test.svelte.js +0 -125
  25. package/dist/components/combobox/__tests__/ComboboxTest.svelte +0 -40
  26. package/dist/components/combobox/__tests__/combobox.test.svelte.js +0 -255
  27. package/dist/components/command/__tests__/CommandInlineDirectTest.svelte +0 -29
  28. package/dist/components/command/__tests__/CommandInlineTest.svelte +0 -89
  29. package/dist/components/command/__tests__/CommandTest.svelte +0 -77
  30. package/dist/components/command/__tests__/command-inline.test.svelte.js +0 -392
  31. package/dist/components/command/__tests__/command-item-passthrough.test.svelte.js +0 -284
  32. package/dist/components/command/__tests__/command.a11y.test.js +0 -30
  33. package/dist/components/command/__tests__/command.integration.test.svelte.js +0 -68
  34. package/dist/components/command/__tests__/command.test.svelte.js +0 -230
  35. package/dist/components/context-menu/__tests__/ContextMenuNonInteractiveTest.svelte +0 -32
  36. package/dist/components/context-menu/__tests__/ContextMenuTest.svelte +0 -25
  37. package/dist/components/context-menu/__tests__/context-menu.test.svelte.js +0 -141
  38. package/dist/components/date-field/__tests__/DateFieldTest.svelte +0 -20
  39. package/dist/components/date-field/__tests__/date-field.test.svelte.js +0 -139
  40. package/dist/components/date-picker/__tests__/DatePickerTest.svelte +0 -20
  41. package/dist/components/date-picker/__tests__/date-picker.test.svelte.js +0 -190
  42. package/dist/components/date-range-field/__tests__/DateRangeFieldTest.svelte +0 -20
  43. package/dist/components/date-range-field/__tests__/date-range-field.test.svelte.js +0 -130
  44. package/dist/components/date-range-picker/__tests__/DateRangePickerTest.svelte +0 -18
  45. package/dist/components/date-range-picker/__tests__/date-range-picker.test.svelte.js +0 -156
  46. package/dist/components/dialog/__tests__/DialogTest.svelte +0 -34
  47. package/dist/components/dialog/__tests__/dialog.test.svelte.js +0 -184
  48. package/dist/components/drop-zone/__tests__/drop-zone.test.svelte.js +0 -26
  49. package/dist/components/dropdown-menu/__tests__/DropdownMenuRadioTest.svelte +0 -90
  50. package/dist/components/dropdown-menu/__tests__/DropdownMenuTest.svelte +0 -71
  51. package/dist/components/dropdown-menu/__tests__/dropdown-menu-radio-group.test.svelte.js +0 -306
  52. package/dist/components/dropdown-menu/__tests__/dropdown-menu.test.svelte.js +0 -567
  53. package/dist/components/empty-state/__tests__/empty-state.test.svelte.js +0 -26
  54. package/dist/components/fab/__tests__/fab.test.svelte.js +0 -30
  55. package/dist/components/field/__tests__/FieldTest.svelte +0 -26
  56. package/dist/components/field/__tests__/field.test.svelte.js +0 -74
  57. package/dist/components/grid-list/__tests__/GridListTest.svelte +0 -46
  58. package/dist/components/grid-list/__tests__/grid-list.test.svelte.js +0 -231
  59. package/dist/components/hover-card/__tests__/HoverCardTest.svelte +0 -30
  60. package/dist/components/hover-card/__tests__/hover-card.test.svelte.js +0 -236
  61. package/dist/components/indicator/__tests__/indicator.test.svelte.js +0 -30
  62. package/dist/components/input/__tests__/input.test.svelte.js +0 -67
  63. package/dist/components/label/__tests__/label.test.svelte.js +0 -22
  64. package/dist/components/language-select/__tests__/language-select.test.svelte.js +0 -199
  65. package/dist/components/language-select/__tests__/languages.test.js +0 -87
  66. package/dist/components/link-preview/__tests__/LinkPreviewTest.svelte +0 -37
  67. package/dist/components/link-preview/__tests__/link-preview.a11y.test.js +0 -28
  68. package/dist/components/link-preview/__tests__/link-preview.integration.test.svelte.js +0 -54
  69. package/dist/components/link-preview/__tests__/link-preview.test.svelte.js +0 -215
  70. package/dist/components/list/__tests__/list.test.svelte.js +0 -22
  71. package/dist/components/menubar/__tests__/MenubarTest.svelte +0 -52
  72. package/dist/components/menubar/__tests__/menubar.a11y.test.js +0 -28
  73. package/dist/components/menubar/__tests__/menubar.integration.test.svelte.js +0 -57
  74. package/dist/components/menubar/__tests__/menubar.test.svelte.js +0 -328
  75. package/dist/components/meter/__tests__/meter.test.svelte.js +0 -26
  76. package/dist/components/nav-bar/__tests__/nav-bar.test.svelte.js +0 -23
  77. package/dist/components/nav-drawer/__tests__/nav-drawer.test.svelte.js +0 -28
  78. package/dist/components/nav-rail/__tests__/nav-rail.test.svelte.js +0 -28
  79. package/dist/components/pagination/__tests__/pagination.test.svelte.js +0 -26
  80. package/dist/components/pin-input/__tests__/pin-input.test.svelte.js +0 -71
  81. package/dist/components/popover/__tests__/PopoverTest.svelte +0 -27
  82. package/dist/components/popover/__tests__/popover.test.svelte.js +0 -196
  83. package/dist/components/progress/__tests__/progress.test.svelte.js +0 -32
  84. package/dist/components/radio-group/__tests__/radio-group.test.svelte.js +0 -22
  85. package/dist/components/range-calendar/__tests__/RangeCalendarTest.svelte +0 -23
  86. package/dist/components/range-calendar/__tests__/range-calendar.test.svelte.js +0 -105
  87. package/dist/components/rating-group/__tests__/rating-group.test.svelte.js +0 -26
  88. package/dist/components/scroll-area/__tests__/scroll-area.test.svelte.js +0 -34
  89. package/dist/components/search-field/__tests__/SearchFieldTest.svelte +0 -34
  90. package/dist/components/search-field/__tests__/search-field.test.svelte.js +0 -118
  91. package/dist/components/select/__tests__/SelectLabelPersistenceTest.svelte +0 -31
  92. package/dist/components/select/__tests__/SelectTest.svelte +0 -33
  93. package/dist/components/select/__tests__/select.test.svelte.js +0 -221
  94. package/dist/components/separator/__tests__/separator.test.svelte.js +0 -39
  95. package/dist/components/sheet/__tests__/SheetTest.svelte +0 -34
  96. package/dist/components/sheet/__tests__/sheet.test.svelte.js +0 -193
  97. package/dist/components/side-sheet/__tests__/side-sheet.test.svelte.js +0 -138
  98. package/dist/components/sidebar/__tests__/SidebarFullTest.svelte +0 -45
  99. package/dist/components/sidebar/__tests__/SidebarTest.svelte +0 -9
  100. package/dist/components/sidebar/__tests__/sidebar.test.svelte.js +0 -186
  101. package/dist/components/simple-dialog/__tests__/SimpleDialogTest.svelte +0 -40
  102. package/dist/components/simple-dialog/__tests__/simple-dialog.test.svelte.js +0 -50
  103. package/dist/components/simple-tooltip/__tests__/SimpleTooltipTest.svelte +0 -19
  104. package/dist/components/simple-tooltip/__tests__/simple-tooltip.test.svelte.js +0 -61
  105. package/dist/components/slider/__tests__/slider.test.svelte.js +0 -42
  106. package/dist/components/sortable-list/__tests__/NestedSortableListTest.svelte +0 -49
  107. package/dist/components/sortable-list/__tests__/SortableListTest.svelte +0 -42
  108. package/dist/components/sortable-list/__tests__/sortable-list.nested.test.svelte.js +0 -112
  109. package/dist/components/sortable-list/__tests__/sortable-list.test.svelte.js +0 -175
  110. package/dist/components/splitter/__tests__/splitter.test.svelte.js +0 -26
  111. package/dist/components/switch/__tests__/switch.test.svelte.js +0 -44
  112. package/dist/components/table/__tests__/table.test.svelte.js +0 -22
  113. package/dist/components/tabs/__tests__/TabsTest.svelte +0 -32
  114. package/dist/components/tabs/__tests__/tabs.test.svelte.js +0 -227
  115. package/dist/components/textarea/__tests__/textarea.test.svelte.js +0 -55
  116. package/dist/components/time-field/__tests__/TimeFieldTest.svelte +0 -20
  117. package/dist/components/time-field/__tests__/time-field.test.svelte.js +0 -100
  118. package/dist/components/time-range-field/__tests__/TimeRangeFieldTest.svelte +0 -20
  119. package/dist/components/time-range-field/__tests__/time-range-field.test.svelte.js +0 -124
  120. package/dist/components/toast/__tests__/toast.test.svelte.js +0 -46
  121. package/dist/components/toggle/__tests__/toggle.test.svelte.js +0 -38
  122. package/dist/components/toggle-group/__tests__/toggle-group.test.svelte.js +0 -22
  123. package/dist/components/toolbar/__tests__/ToolbarCompositionTest.svelte +0 -18
  124. package/dist/components/toolbar/__tests__/ToolbarTabstopTest.svelte +0 -10
  125. package/dist/components/toolbar/__tests__/toolbar.test.svelte.js +0 -63
  126. package/dist/components/tooltip/__tests__/TooltipTest.svelte +0 -22
  127. package/dist/components/tooltip/__tests__/tooltip.test.svelte.js +0 -225
  128. package/dist/components/tree/__tests__/TreeLabelContentTest.svelte +0 -21
  129. package/dist/components/tree/__tests__/TreeTest.svelte +0 -24
  130. package/dist/components/tree/__tests__/tree.test.svelte.js +0 -229
  131. package/dist/components/virtualizer/__tests__/waterfall-layout.test.js +0 -82
  132. package/dist/internal/announcer/__tests__/announcer.test.js +0 -42
  133. package/dist/internal/dismissible-layer/__tests__/dismissible-layer.test.js +0 -196
  134. package/dist/internal/drag-drop/__tests__/auto-scroll.test.js +0 -104
  135. package/dist/internal/drag-drop/__tests__/drag-session.test.svelte.js +0 -803
  136. package/dist/internal/drag-drop/__tests__/drag-source.test.svelte.js +0 -130
  137. package/dist/internal/drag-drop/__tests__/drop-delegate.test.js +0 -223
  138. package/dist/internal/drag-drop/__tests__/types.test.js +0 -20
  139. package/dist/internal/escape-layer/__tests__/escape-layer.test.js +0 -113
  140. package/dist/internal/focus-scope/__tests__/focus-scope.test.js +0 -225
  141. package/dist/internal/grace-area/__tests__/grace-area.test.js +0 -67
  142. package/dist/internal/helpers/__tests__/helpers.test.js +0 -123
  143. package/dist/internal/portal/__tests__/PortalTest.svelte +0 -21
  144. package/dist/internal/portal/__tests__/portal.test.js +0 -29
  145. package/dist/internal/portal/__tests__/portal.test.svelte.js +0 -57
  146. package/dist/internal/scroll-lock/__tests__/scroll-lock.test.js +0 -160
  147. package/dist/internal/typeahead/__tests__/typeahead.test.js +0 -61
  148. package/src/themes/__tests__/carbon-dark-contrast.test.ts +0 -170
  149. package/src/themes/__tests__/generated-css-drift.test.ts +0 -53
  150. package/src/themes/__tests__/scrim-opaque.test.ts +0 -52
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Spectral
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,201 @@
1
+ # Third-party notices
2
+
3
+ `@spectral_labs/ui` is released under the MIT licence (`LICENSE`). It also ships the third-party material below, which keeps its own licence: one section per item, its licence reproduced as is.
4
+
5
+ ## Inter (OFL-1.1)
6
+
7
+ Inter 4.001, the variable font files `src/fonts/inter/InterVariable.woff2` and `src/fonts/inter/InterVariable-Italic.woff2` (https://github.com/rsms/inter). The copyright line is the one the font files carry.
8
+
9
+ ```text
10
+ Copyright 2016 The Inter Project Authors
11
+
12
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
13
+ This license is copied below, and is also available with a FAQ at:
14
+ http://scripts.sil.org/OFL
15
+
16
+ -----------------------------------------------------------
17
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
18
+ -----------------------------------------------------------
19
+
20
+ PREAMBLE
21
+ The goals of the Open Font License (OFL) are to stimulate worldwide
22
+ development of collaborative font projects, to support the font creation
23
+ efforts of academic and linguistic communities, and to provide a free and
24
+ open framework in which fonts may be shared and improved in partnership
25
+ with others.
26
+
27
+ The OFL allows the licensed fonts to be used, studied, modified and
28
+ redistributed freely as long as they are not sold by themselves. The
29
+ fonts, including any derivative works, can be bundled, embedded,
30
+ redistributed and/or sold with any software provided that any reserved
31
+ names are not used by derivative works. The fonts and derivatives,
32
+ however, cannot be released under any other type of license. The
33
+ requirement for fonts to remain under this license does not apply
34
+ to any document created using the fonts or their derivatives.
35
+
36
+ DEFINITIONS
37
+ "Font Software" refers to the set of files released by the Copyright
38
+ Holder(s) under this license and clearly marked as such. This may
39
+ include source files, build scripts and documentation.
40
+
41
+ "Reserved Font Name" refers to any names specified as such after the
42
+ copyright statement(s).
43
+
44
+ "Original Version" refers to the collection of Font Software components as
45
+ distributed by the Copyright Holder(s).
46
+
47
+ "Modified Version" refers to any derivative made by adding to, deleting,
48
+ or substituting -- in part or in whole -- any of the components of the
49
+ Original Version, by changing formats or by porting the Font Software to a
50
+ new environment.
51
+
52
+ "Author" refers to any designer, engineer, programmer, technical
53
+ writer or other person who contributed to the Font Software.
54
+
55
+ PERMISSION & CONDITIONS
56
+ Permission is hereby granted, free of charge, to any person obtaining
57
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
58
+ redistribute, and sell modified and unmodified copies of the Font
59
+ Software, subject to the following conditions:
60
+
61
+ 1) Neither the Font Software nor any of its individual components,
62
+ in Original or Modified Versions, may be sold by itself.
63
+
64
+ 2) Original or Modified Versions of the Font Software may be bundled,
65
+ redistributed and/or sold with any software, provided that each copy
66
+ contains the above copyright notice and this license. These can be
67
+ included either as stand-alone text files, human-readable headers or
68
+ in the appropriate machine-readable metadata fields within text or
69
+ binary files as long as those fields can be easily viewed by the user.
70
+
71
+ 3) No Modified Version of the Font Software may use the Reserved Font
72
+ Name(s) unless explicit written permission is granted by the corresponding
73
+ Copyright Holder. This restriction only applies to the primary font name as
74
+ presented to the users.
75
+
76
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
77
+ Software shall not be used to promote, endorse or advertise any
78
+ Modified Version, except to acknowledge the contribution(s) of the
79
+ Copyright Holder(s) and the Author(s) or with their explicit written
80
+ permission.
81
+
82
+ 5) The Font Software, modified or unmodified, in part or in whole,
83
+ must be distributed entirely under this license, and must not be
84
+ distributed under any other license. The requirement for fonts to
85
+ remain under this license does not apply to any document created
86
+ using the Font Software.
87
+
88
+ TERMINATION
89
+ This license becomes null and void if any of the above conditions are
90
+ not met.
91
+
92
+ DISCLAIMER
93
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
94
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
95
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
96
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
97
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
98
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
99
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
100
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
101
+ OTHER DEALINGS IN THE FONT SOFTWARE.
102
+ ```
103
+
104
+ ## JetBrains Mono (OFL-1.1)
105
+
106
+ JetBrains Mono 2.304, the font files `src/fonts/jetbrains-mono/JetBrainsMono-Regular.woff2`, `src/fonts/jetbrains-mono/JetBrainsMono-Bold.woff2` and `src/fonts/jetbrains-mono/JetBrainsMono-Italic.woff2` (https://github.com/JetBrains/JetBrainsMono). The copyright line is the one the font files carry.
107
+
108
+ ```text
109
+ Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
110
+
111
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
112
+ This license is copied below, and is also available with a FAQ at:
113
+ https://scripts.sil.org/OFL
114
+
115
+ -----------------------------------------------------------
116
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
117
+ -----------------------------------------------------------
118
+
119
+ PREAMBLE
120
+ The goals of the Open Font License (OFL) are to stimulate worldwide
121
+ development of collaborative font projects, to support the font creation
122
+ efforts of academic and linguistic communities, and to provide a free and
123
+ open framework in which fonts may be shared and improved in partnership
124
+ with others.
125
+
126
+ The OFL allows the licensed fonts to be used, studied, modified and
127
+ redistributed freely as long as they are not sold by themselves. The
128
+ fonts, including any derivative works, can be bundled, embedded,
129
+ redistributed and/or sold with any software provided that any reserved
130
+ names are not used by derivative works. The fonts and derivatives,
131
+ however, cannot be released under any other type of license. The
132
+ requirement for fonts to remain under this license does not apply
133
+ to any document created using the fonts or their derivatives.
134
+
135
+ DEFINITIONS
136
+ "Font Software" refers to the set of files released by the Copyright
137
+ Holder(s) under this license and clearly marked as such. This may
138
+ include source files, build scripts and documentation.
139
+
140
+ "Reserved Font Name" refers to any names specified as such after the
141
+ copyright statement(s).
142
+
143
+ "Original Version" refers to the collection of Font Software components as
144
+ distributed by the Copyright Holder(s).
145
+
146
+ "Modified Version" refers to any derivative made by adding to, deleting,
147
+ or substituting -- in part or in whole -- any of the components of the
148
+ Original Version, by changing formats or by porting the Font Software to a
149
+ new environment.
150
+
151
+ "Author" refers to any designer, engineer, programmer, technical
152
+ writer or other person who contributed to the Font Software.
153
+
154
+ PERMISSION & CONDITIONS
155
+ Permission is hereby granted, free of charge, to any person obtaining
156
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
157
+ redistribute, and sell modified and unmodified copies of the Font
158
+ Software, subject to the following conditions:
159
+
160
+ 1) Neither the Font Software nor any of its individual components,
161
+ in Original or Modified Versions, may be sold by itself.
162
+
163
+ 2) Original or Modified Versions of the Font Software may be bundled,
164
+ redistributed and/or sold with any software, provided that each copy
165
+ contains the above copyright notice and this license. These can be
166
+ included either as stand-alone text files, human-readable headers or
167
+ in the appropriate machine-readable metadata fields within text or
168
+ binary files as long as those fields can be easily viewed by the user.
169
+
170
+ 3) No Modified Version of the Font Software may use the Reserved Font
171
+ Name(s) unless explicit written permission is granted by the corresponding
172
+ Copyright Holder. This restriction only applies to the primary font name as
173
+ presented to the users.
174
+
175
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
176
+ Software shall not be used to promote, endorse or advertise any
177
+ Modified Version, except to acknowledge the contribution(s) of the
178
+ Copyright Holder(s) and the Author(s) or with their explicit written
179
+ permission.
180
+
181
+ 5) The Font Software, modified or unmodified, in part or in whole,
182
+ must be distributed entirely under this license, and must not be
183
+ distributed under any other license. The requirement for fonts to
184
+ remain under this license does not apply to any document created
185
+ using the Font Software.
186
+
187
+ TERMINATION
188
+ This license becomes null and void if any of the above conditions are
189
+ not met.
190
+
191
+ DISCLAIMER
192
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
193
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
194
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
195
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
196
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
197
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
198
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
199
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
200
+ OTHER DEALINGS IN THE FONT SOFTWARE.
201
+ ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@spectral_labs/ui",
3
3
  "type": "module",
4
- "version": "1.7.0",
4
+ "version": "1.8.0-next.0",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",
7
7
  "access": "public"
@@ -13,6 +13,9 @@
13
13
  "url": "https://github.com/negativemachine/spectral-ui.git",
14
14
  "directory": "packages/spectral-ui"
15
15
  },
16
+ "sideEffects": [
17
+ "**/*.css"
18
+ ],
16
19
  "exports": {
17
20
  ".": {
18
21
  "types": "./dist/index.d.ts",
@@ -30,6 +33,7 @@
30
33
  },
31
34
  "types": "./dist/index.d.ts",
32
35
  "files": [
36
+ "THIRD_PARTY_NOTICES.md",
33
37
  "dist",
34
38
  "src/base.css",
35
39
  "src/css",
@@ -37,7 +41,9 @@
37
41
  "src/fonts.css",
38
42
  "src/themes",
39
43
  "src/tokens.css",
40
- "src/utilities.css"
44
+ "src/utilities.css",
45
+ "!dist/**/__tests__",
46
+ "!src/**/__tests__"
41
47
  ],
42
48
  "svelte": "./dist/index.js",
43
49
  "scripts": {
@@ -1,134 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { dirname, resolve } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import { describe, expect, it } from 'vitest';
5
- /**
6
- * spectral-ui#206 — the six covering surfaces paint the OPAQUE scrim token and
7
- * own the veil's alpha through `opacity` (0.32, via the component's
8
- * `--sp-comp-*-overlay-opacity` token where one exists). Exactly one owner:
9
- * the colour is never translucent, the opacity is never missing or wrong.
10
- *
11
- * The two values are matched against an ALLOW-LIST, not a deny-list: any other
12
- * spelling fails, so `#0000004d`, `oklch(0 0 0 / .3)`, `rgb(0 0 0 / 30%)` or a
13
- * `color-mix()` cannot slip through a list of forbidden prefixes. Declarations
14
- * are parsed (property, value) instead of substring-matched, because
15
- * `--sp-comp-dialog-overlay-opacity: 0.32;` literally ends with
16
- * `opacity: 0.32;` and would otherwise satisfy a naive regex while the real
17
- * `opacity` declaration says something else.
18
- *
19
- * EVERY rule in the file that targets the class is inspected, not just the
20
- * first one: in a Svelte component a later rule (a duplicate, a `@media`
21
- * block) lives in the same scoped `<style>` and wins the cascade.
22
- *
23
- * Three of these surfaces (SideSheet, NavDrawer, BottomSheet) have no cell in
24
- * `tests/e2e/scrim-alpha.spec.ts`, so this file is their only control — it has
25
- * to be exact. The list is literal on purpose: a seventh surface that forgets
26
- * the idiom has to be added here.
27
- */
28
- const here = dirname(fileURLToPath(import.meta.url));
29
- const SURFACES = [
30
- { file: 'dialog/components/dialog-overlay.svelte', selector: '.sp-dialog-overlay' },
31
- {
32
- file: 'alert-dialog/components/alert-dialog-overlay.svelte',
33
- selector: '.sp-alert-dialog-overlay',
34
- },
35
- { file: 'sheet/components/sheet-overlay.svelte', selector: '.sp-sheet-overlay' },
36
- { file: 'side-sheet/side-sheet.svelte', selector: '.sp-side-sheet-overlay' },
37
- { file: 'nav-drawer/components/nav-drawer-root.svelte', selector: '.sp-nav-drawer-overlay' },
38
- {
39
- file: 'bottom-sheet/components/bottom-sheet-root.svelte',
40
- selector: '.sp-bottom-sheet-overlay',
41
- },
42
- ];
43
- /** `background-color` values that keep the colour opaque and token-driven. */
44
- const ALLOWED_BACKGROUND = [
45
- /^var\(--sp-sys-color-scrim\)$/,
46
- /^var\(--sp-comp-[a-z-]+-overlay-color,\s*var\(--sp-sys-color-scrim\)\)$/,
47
- ];
48
- /** `opacity` values that make the component the single owner of the alpha. */
49
- const ALLOWED_OPACITY = [/^0\.32$/, /^var\(--sp-comp-[a-z-]+-overlay-opacity,\s*0\.32\)$/];
50
- /** The component's scoped stylesheet, so template braces are never parsed. */
51
- function styleBlock(componentSource, file) {
52
- const match = componentSource.match(/<style>(.*)<\/style>/s);
53
- if (!match)
54
- throw new Error(`${file}: no <style> block`);
55
- return match[1];
56
- }
57
- /** Every rule in `source` whose selector list mentions `selector`, in order. */
58
- function rulesTargeting(source, selector) {
59
- const rules = [];
60
- for (let open = 0; open < source.length; open++) {
61
- if (source[open] !== '{')
62
- continue;
63
- let start = open - 1;
64
- while (start >= 0 && !'{};'.includes(source[start]))
65
- start--;
66
- const selectorList = source.slice(start + 1, open).trim();
67
- if (!selectorList.includes(selector))
68
- continue;
69
- let depth = 1;
70
- let close = open + 1;
71
- for (; close < source.length && depth > 0; close++) {
72
- if (source[close] === '{')
73
- depth++;
74
- else if (source[close] === '}')
75
- depth--;
76
- }
77
- const declarations = source
78
- .slice(open + 1, close - 1)
79
- .split(';')
80
- .map((chunk) => chunk.trim())
81
- .filter((chunk) => chunk.includes(':') && !chunk.includes('{'))
82
- .map((chunk) => ({
83
- property: chunk.slice(0, chunk.indexOf(':')).trim(),
84
- value: chunk.slice(chunk.indexOf(':') + 1).trim(),
85
- }));
86
- rules.push({ selectorList, declarations });
87
- }
88
- return rules;
89
- }
90
- const valueOf = (rule, property) => rule.declarations.findLast((d) => d.property === property)?.value;
91
- describe('overlay surfaces own the scrim alpha through opacity (#206)', () => {
92
- for (const { file, selector } of SURFACES) {
93
- const source = readFileSync(resolve(here, '..', file), 'utf8');
94
- const rules = rulesTargeting(styleBlock(source, file), selector);
95
- // The veil rule is the one whose selector is the bare class; anything else
96
- // (`[data-state='closed']`, a media-query variant) is a variant rule.
97
- const veilRules = rules.filter((r) => r.selectorList === selector);
98
- const variantRules = rules.filter((r) => r.selectorList !== selector);
99
- it(`${selector} is painted by exactly one veil rule`, () => {
100
- expect(veilRules).toHaveLength(1);
101
- });
102
- it(`${selector} paints the opaque scrim token`, () => {
103
- const background = valueOf(veilRules[0], 'background-color');
104
- expect(background, `${file}: background-color`).toBeDefined();
105
- expect(ALLOWED_BACKGROUND.some((allowed) => allowed.test(background)), `${file}: background-color "${background}" is not an opaque token reference`).toBe(true);
106
- });
107
- it(`${selector} carries the veil's alpha as opacity 0.32`, () => {
108
- const opacity = valueOf(veilRules[0], 'opacity');
109
- expect(opacity, `${file}: opacity`).toBeDefined();
110
- expect(ALLOWED_OPACITY.some((allowed) => allowed.test(opacity)), `${file}: opacity "${opacity}" is not the 0.32 the component owns`).toBe(true);
111
- });
112
- it(`${selector} declares no local overlay token that would change the veil`, () => {
113
- for (const rule of rules) {
114
- for (const { property, value } of rule.declarations) {
115
- if (/^--sp-comp-[a-z-]+-overlay-opacity$/.test(property)) {
116
- expect(value, `${file}: ${property}`).toBe('0.32');
117
- }
118
- if (/^--sp-comp-[a-z-]+-overlay-color$/.test(property)) {
119
- expect(value, `${file}: ${property}`).toBe('var(--sp-sys-color-scrim)');
120
- }
121
- }
122
- }
123
- });
124
- it(`${selector} variants only fade the veil out, never repaint it`, () => {
125
- for (const rule of variantRules) {
126
- expect(valueOf(rule, 'background-color'), `${file}: "${rule.selectorList}" repaints the veil`).toBeUndefined();
127
- const opacity = valueOf(rule, 'opacity');
128
- if (opacity !== undefined) {
129
- expect(opacity, `${file}: "${rule.selectorList}" opacity`).toBe('0');
130
- }
131
- }
132
- });
133
- }
134
- });
@@ -1,31 +0,0 @@
1
- <script lang="ts">
2
- import AccordionContent from '../components/accordion-content.svelte'
3
- import AccordionItem from '../components/accordion-item.svelte'
4
- import AccordionRoot from '../components/accordion-root.svelte'
5
- import AccordionTrigger from '../components/accordion-trigger.svelte'
6
-
7
- let {
8
- type = 'single',
9
- value = $bindable(''),
10
- disabled = false,
11
- }: {
12
- type?: 'single' | 'multiple'
13
- value?: string | string[]
14
- disabled?: boolean
15
- } = $props()
16
- </script>
17
-
18
- <AccordionRoot bind:value {type} {disabled}>
19
- <AccordionItem value="item-1">
20
- <AccordionTrigger>Trigger 1</AccordionTrigger>
21
- <AccordionContent>Content 1</AccordionContent>
22
- </AccordionItem>
23
- <AccordionItem value="item-2">
24
- <AccordionTrigger>Trigger 2</AccordionTrigger>
25
- <AccordionContent>Content 2</AccordionContent>
26
- </AccordionItem>
27
- <AccordionItem value="item-3" disabled={true}>
28
- <AccordionTrigger>Trigger 3</AccordionTrigger>
29
- <AccordionContent>Content 3</AccordionContent>
30
- </AccordionItem>
31
- </AccordionRoot>
@@ -1,139 +0,0 @@
1
- import { flushSync, mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import AccordionRoot from '../components/accordion-root.svelte';
4
- import AccordionTest from './AccordionTest.svelte';
5
- describe('accordion', () => {
6
- let target;
7
- let instance;
8
- function setup(props = {}) {
9
- target = document.createElement('div');
10
- document.body.appendChild(target);
11
- instance = mount(AccordionTest, { target, props });
12
- return target;
13
- }
14
- function setupRoot(props = {}) {
15
- target = document.createElement('div');
16
- document.body.appendChild(target);
17
- instance = mount(AccordionRoot, { target, props });
18
- return target;
19
- }
20
- afterEach(() => {
21
- if (instance)
22
- unmount(instance);
23
- target?.remove();
24
- });
25
- // --- Basic rendering ---
26
- it('renders with data-orientation', () => {
27
- setupRoot();
28
- expect(target.querySelector('[data-orientation]')).toBeTruthy();
29
- });
30
- it('renders all accordion items', () => {
31
- setup();
32
- const items = target.querySelectorAll('.sp-accordion-item');
33
- expect(items.length).toBe(3);
34
- });
35
- it('renders trigger buttons', () => {
36
- setup();
37
- const triggers = target.querySelectorAll('.sp-accordion-trigger');
38
- expect(triggers.length).toBe(3);
39
- });
40
- // --- ARIA attributes ---
41
- it('triggers have aria-expanded="false" when collapsed', () => {
42
- setup();
43
- const triggers = target.querySelectorAll('.sp-accordion-trigger');
44
- triggers.forEach((trigger) => {
45
- expect(trigger.getAttribute('aria-expanded')).toBe('false');
46
- });
47
- });
48
- it('trigger has aria-expanded="true" when item is open', () => {
49
- setup({ value: 'item-1' });
50
- const triggers = target.querySelectorAll('.sp-accordion-trigger');
51
- expect(triggers[0]?.getAttribute('aria-expanded')).toBe('true');
52
- expect(triggers[1]?.getAttribute('aria-expanded')).toBe('false');
53
- });
54
- it('item has data-state="open" when expanded', () => {
55
- setup({ value: 'item-1' });
56
- const items = target.querySelectorAll('.sp-accordion-item');
57
- expect(items[0]?.getAttribute('data-state')).toBe('open');
58
- expect(items[1]?.getAttribute('data-state')).toBe('closed');
59
- });
60
- it('content has role="region"', () => {
61
- setup({ value: 'item-1' });
62
- const content = target.querySelector('.sp-accordion-content');
63
- expect(content?.getAttribute('role')).toBe('region');
64
- });
65
- // --- Single mode behavior ---
66
- it('single mode: clicking one item closes the other', () => {
67
- setup({ type: 'single', value: 'item-1' });
68
- const triggers = target.querySelectorAll('.sp-accordion-trigger');
69
- // item-1 is open
70
- expect(target.querySelectorAll('.sp-accordion-content').length).toBe(1);
71
- // Click item-2
72
- triggers[1].click();
73
- flushSync();
74
- // item-2 should be open, item-1 closed
75
- const items = target.querySelectorAll('.sp-accordion-item');
76
- expect(items[0]?.getAttribute('data-state')).toBe('closed');
77
- expect(items[1]?.getAttribute('data-state')).toBe('open');
78
- expect(target.querySelectorAll('.sp-accordion-content').length).toBe(1);
79
- });
80
- it('single mode: clicking same item toggles it closed', () => {
81
- setup({ type: 'single', value: 'item-1' });
82
- const trigger = target.querySelector('.sp-accordion-trigger');
83
- trigger.click();
84
- flushSync();
85
- expect(target.querySelector('.sp-accordion-content')).toBeNull();
86
- });
87
- // --- Multiple mode behavior ---
88
- it('multiple mode: clicking items opens multiple', () => {
89
- setup({ type: 'multiple', value: ['item-1'] });
90
- const triggers = target.querySelectorAll('.sp-accordion-trigger');
91
- // item-1 is already open, click item-2
92
- triggers[1].click();
93
- flushSync();
94
- // Both should be open
95
- const items = target.querySelectorAll('.sp-accordion-item');
96
- expect(items[0]?.getAttribute('data-state')).toBe('open');
97
- expect(items[1]?.getAttribute('data-state')).toBe('open');
98
- expect(target.querySelectorAll('.sp-accordion-content').length).toBe(2);
99
- });
100
- // --- Disabled state ---
101
- it('disabled item has data-disabled attribute', () => {
102
- setup();
103
- const items = target.querySelectorAll('.sp-accordion-item');
104
- // item-3 is disabled
105
- expect(items[2]?.hasAttribute('data-disabled')).toBe(true);
106
- });
107
- it('disabled item trigger is disabled', () => {
108
- setup();
109
- const triggers = target.querySelectorAll('.sp-accordion-trigger');
110
- expect(triggers[2]?.disabled).toBe(true);
111
- });
112
- it('clicking disabled trigger does not toggle', () => {
113
- setup({ type: 'single' });
114
- const triggers = target.querySelectorAll('.sp-accordion-trigger');
115
- triggers[2].click();
116
- flushSync();
117
- // item-3 should still be closed
118
- const items = target.querySelectorAll('.sp-accordion-item');
119
- expect(items[2]?.getAttribute('data-state')).toBe('closed');
120
- });
121
- it('root disabled prevents all toggles', () => {
122
- setup({ disabled: true });
123
- const triggers = target.querySelectorAll('.sp-accordion-trigger');
124
- triggers[0].click();
125
- flushSync();
126
- // Nothing should be open
127
- expect(target.querySelector('.sp-accordion-content')).toBeNull();
128
- });
129
- // --- Content rendering ---
130
- it('content is not rendered for collapsed items', () => {
131
- setup();
132
- expect(target.querySelector('.sp-accordion-content')).toBeNull();
133
- });
134
- it('content is rendered for expanded item', () => {
135
- setup({ value: 'item-1' });
136
- const content = target.querySelector('.sp-accordion-content-inner');
137
- expect(content?.textContent).toContain('Content 1');
138
- });
139
- });
@@ -1,28 +0,0 @@
1
- <script lang="ts">
2
- import AlertDialogAction from '../components/alert-dialog-action.svelte'
3
- import AlertDialogCancel from '../components/alert-dialog-cancel.svelte'
4
- import AlertDialogContent from '../components/alert-dialog-content.svelte'
5
- import AlertDialogDescription from '../components/alert-dialog-description.svelte'
6
- import AlertDialogOverlay from '../components/alert-dialog-overlay.svelte'
7
- import AlertDialogRoot from '../components/alert-dialog-root.svelte'
8
- import AlertDialogTitle from '../components/alert-dialog-title.svelte'
9
- import AlertDialogTrigger from '../components/alert-dialog-trigger.svelte'
10
-
11
- let {
12
- open = $bindable(false),
13
- portalTo = undefined,
14
- }: { open?: boolean; portalTo?: HTMLElement | string } = $props()
15
- </script>
16
-
17
- <AlertDialogRoot bind:open>
18
- <AlertDialogTrigger>Delete</AlertDialogTrigger>
19
- <AlertDialogOverlay />
20
- <AlertDialogContent {portalTo}>
21
- <AlertDialogTitle>Are you sure?</AlertDialogTitle>
22
- <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
23
- <div class="sp-alert-dialog-actions">
24
- <AlertDialogCancel>Cancel</AlertDialogCancel>
25
- <AlertDialogAction>Confirm</AlertDialogAction>
26
- </div>
27
- </AlertDialogContent>
28
- </AlertDialogRoot>
@@ -1,42 +0,0 @@
1
- import { mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import { configureAxe } from 'vitest-axe';
4
- import * as matchers from 'vitest-axe/matchers';
5
- import AlertDialogTest from './AlertDialogTest.svelte';
6
- expect.extend(matchers);
7
- const axe = configureAxe({
8
- rules: {
9
- region: { enabled: false },
10
- 'page-has-heading-one': { enabled: false },
11
- 'landmark-one-main': { enabled: false },
12
- },
13
- });
14
- describe('alert-dialog a11y', () => {
15
- let cleanup;
16
- afterEach(() => cleanup?.());
17
- it('has no axe violations when closed', async () => {
18
- const container = document.createElement('div');
19
- document.body.appendChild(container);
20
- const instance = mount(AlertDialogTest, { target: container });
21
- const results = await axe(container);
22
- cleanup = () => {
23
- unmount(instance);
24
- container.remove();
25
- };
26
- expect(results).toHaveNoViolations();
27
- });
28
- it('has no axe violations when open', async () => {
29
- const container = document.createElement('div');
30
- document.body.appendChild(container);
31
- const instance = mount(AlertDialogTest, {
32
- target: container,
33
- props: { open: true },
34
- });
35
- const results = await axe(container);
36
- cleanup = () => {
37
- unmount(instance);
38
- container.remove();
39
- };
40
- expect(results).toHaveNoViolations();
41
- });
42
- });