@nationaldesignstudio/react 0.5.2 → 0.5.3

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 (160) hide show
  1. package/package.json +10 -2
  2. package/src/App.css +0 -0
  3. package/src/App.tsx +0 -7
  4. package/src/assets/fonts/PPNeueMontreal-Variable.woff2 +0 -0
  5. package/src/assets/react.svg +0 -1
  6. package/src/components/atoms/accordion/accordion.stories.tsx +0 -228
  7. package/src/components/atoms/accordion/accordion.test.tsx +0 -231
  8. package/src/components/atoms/accordion/index.ts +0 -6
  9. package/src/components/atoms/background/background.test.tsx +0 -213
  10. package/src/components/atoms/background/index.ts +0 -22
  11. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-chromium-darwin.png +0 -0
  12. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-chromium-linux.png +0 -0
  13. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-chromium-darwin.png +0 -0
  14. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-chromium-linux.png +0 -0
  15. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-quiet-chromium-darwin.png +0 -0
  16. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-quiet-chromium-linux.png +0 -0
  17. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-disabled-chromium-darwin.png +0 -0
  18. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-disabled-chromium-linux.png +0 -0
  19. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-chromium-darwin.png +0 -0
  20. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-chromium-linux.png +0 -0
  21. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-chromium-darwin.png +0 -0
  22. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-chromium-linux.png +0 -0
  23. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-quiet-chromium-darwin.png +0 -0
  24. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-quiet-chromium-linux.png +0 -0
  25. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-large-chromium-darwin.png +0 -0
  26. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-large-chromium-linux.png +0 -0
  27. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-medium-chromium-darwin.png +0 -0
  28. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-medium-chromium-linux.png +0 -0
  29. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-small-chromium-darwin.png +0 -0
  30. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-small-chromium-linux.png +0 -0
  31. package/src/components/atoms/button/button.stories.tsx +0 -289
  32. package/src/components/atoms/button/button.test.tsx +0 -419
  33. package/src/components/atoms/button/button.visual.test.tsx +0 -98
  34. package/src/components/atoms/button/icon-button.stories.tsx +0 -260
  35. package/src/components/atoms/button/icon-button.test.tsx +0 -186
  36. package/src/components/atoms/button/index.ts +0 -6
  37. package/src/components/atoms/input/index.ts +0 -17
  38. package/src/components/atoms/input/input-group.stories.tsx +0 -646
  39. package/src/components/atoms/input/input-group.test.tsx +0 -362
  40. package/src/components/atoms/input/input.stories.tsx +0 -228
  41. package/src/components/atoms/input/input.test.tsx +0 -167
  42. package/src/components/atoms/ndstudio-footer/index.ts +0 -1
  43. package/src/components/atoms/pager-control/index.ts +0 -5
  44. package/src/components/atoms/pager-control/pager-control.stories.tsx +0 -207
  45. package/src/components/atoms/pager-control/pager-control.test.tsx +0 -130
  46. package/src/components/atoms/popover/index.ts +0 -30
  47. package/src/components/atoms/popover/popover.stories.tsx +0 -531
  48. package/src/components/atoms/popover/popover.test.tsx +0 -486
  49. package/src/components/atoms/select/index.ts +0 -18
  50. package/src/components/atoms/select/select.stories.tsx +0 -455
  51. package/src/components/atoms/tooltip/index.ts +0 -24
  52. package/src/components/atoms/tooltip/tooltip.stories.tsx +0 -348
  53. package/src/components/atoms/tooltip/tooltip.test.tsx +0 -363
  54. package/src/components/dev-tools/dev-toolbar/dev-toolbar.stories.tsx +0 -73
  55. package/src/components/dev-tools/dev-toolbar/index.ts +0 -1
  56. package/src/components/dev-tools/grid-overlay/index.ts +0 -1
  57. package/src/components/dev-tools/index.ts +0 -2
  58. package/src/components/foundation/typography/typography.stories.tsx +0 -401
  59. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-default-vertical-chromium-darwin.png +0 -0
  60. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-default-vertical-chromium-linux.png +0 -0
  61. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-horizontal-chromium-darwin.png +0 -0
  62. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-horizontal-chromium-linux.png +0 -0
  63. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-minimal-chromium-darwin.png +0 -0
  64. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-minimal-chromium-linux.png +0 -0
  65. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-actions-chromium-darwin.png +0 -0
  66. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-actions-chromium-linux.png +0 -0
  67. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-eyebrow-chromium-darwin.png +0 -0
  68. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-eyebrow-chromium-linux.png +0 -0
  69. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-image-chromium-darwin.png +0 -0
  70. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-image-chromium-linux.png +0 -0
  71. package/src/components/organisms/card/card.stories.tsx +0 -293
  72. package/src/components/organisms/card/card.test.tsx +0 -247
  73. package/src/components/organisms/card/card.visual.test.tsx +0 -197
  74. package/src/components/organisms/card/index.ts +0 -26
  75. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-active-link-chromium-darwin.png +0 -0
  76. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-active-link-chromium-linux.png +0 -0
  77. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-brand-only-chromium-darwin.png +0 -0
  78. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-brand-only-chromium-linux.png +0 -0
  79. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-default-chromium-darwin.png +0 -0
  80. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-default-chromium-linux.png +0 -0
  81. package/src/components/organisms/navbar/index.ts +0 -18
  82. package/src/components/organisms/navbar/navbar.stories.tsx +0 -313
  83. package/src/components/organisms/navbar/navbar.test.tsx +0 -190
  84. package/src/components/organisms/navbar/navbar.visual.test.tsx +0 -85
  85. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-icon-chromium-darwin.png +0 -0
  86. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-icon-chromium-linux.png +0 -0
  87. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-text-chromium-darwin.png +0 -0
  88. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-text-chromium-linux.png +0 -0
  89. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-default-chromium-darwin.png +0 -0
  90. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-default-chromium-linux.png +0 -0
  91. package/src/components/organisms/us-gov-banner/index.ts +0 -5
  92. package/src/components/organisms/us-gov-banner/us-gov-banner.stories.tsx +0 -35
  93. package/src/components/organisms/us-gov-banner/us-gov-banner.test.tsx +0 -107
  94. package/src/components/organisms/us-gov-banner/us-gov-banner.visual.test.tsx +0 -46
  95. package/src/components/sections/banner/banner.stories.tsx +0 -150
  96. package/src/components/sections/banner/banner.test.tsx +0 -185
  97. package/src/components/sections/banner/index.ts +0 -2
  98. package/src/components/sections/card-grid/card-grid.stories.tsx +0 -351
  99. package/src/components/sections/card-grid/index.ts +0 -1
  100. package/src/components/sections/faq-section/faq-section.stories.tsx +0 -453
  101. package/src/components/sections/faq-section/index.ts +0 -2
  102. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-desktop-chromium-darwin.png +0 -0
  103. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-desktop-chromium-linux.png +0 -0
  104. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-mobile-chromium-darwin.png +0 -0
  105. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-mobile-chromium-linux.png +0 -0
  106. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-tablet-chromium-darwin.png +0 -0
  107. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-tablet-chromium-linux.png +0 -0
  108. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-desktop-chromium-darwin.png +0 -0
  109. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-desktop-chromium-linux.png +0 -0
  110. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-mobile-chromium-darwin.png +0 -0
  111. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-mobile-chromium-linux.png +0 -0
  112. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-tablet-chromium-darwin.png +0 -0
  113. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-tablet-chromium-linux.png +0 -0
  114. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-desktop-chromium-darwin.png +0 -0
  115. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-desktop-chromium-linux.png +0 -0
  116. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-mobile-chromium-darwin.png +0 -0
  117. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-mobile-chromium-linux.png +0 -0
  118. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-tablet-chromium-darwin.png +0 -0
  119. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-tablet-chromium-linux.png +0 -0
  120. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-custom-class-chromium-darwin.png +0 -0
  121. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-custom-class-chromium-linux.png +0 -0
  122. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-default-chromium-linux.png +0 -0
  123. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-long-title-chromium-darwin.png +0 -0
  124. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-long-title-chromium-linux.png +0 -0
  125. package/src/components/sections/hero/hero.stories.tsx +0 -397
  126. package/src/components/sections/hero/hero.test.tsx +0 -138
  127. package/src/components/sections/hero/hero.visual.test.tsx +0 -140
  128. package/src/components/sections/hero/index.ts +0 -23
  129. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-h3-heading-chromium-darwin.png +0 -0
  130. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-h3-heading-chromium-linux.png +0 -0
  131. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-paragraphs-chromium-darwin.png +0 -0
  132. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-paragraphs-chromium-linux.png +0 -0
  133. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-sections-chromium-darwin.png +0 -0
  134. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-sections-chromium-linux.png +0 -0
  135. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-single-section-chromium-darwin.png +0 -0
  136. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-single-section-chromium-linux.png +0 -0
  137. package/src/components/sections/prose/index.ts +0 -6
  138. package/src/components/sections/prose/prose.stories.tsx +0 -144
  139. package/src/components/sections/prose/prose.test.tsx +0 -178
  140. package/src/components/sections/prose/prose.visual.test.tsx +0 -105
  141. package/src/components/sections/quote-block/index.ts +0 -5
  142. package/src/components/sections/river/index.ts +0 -1
  143. package/src/components/sections/river/river.stories.tsx +0 -237
  144. package/src/components/sections/river/river.test.tsx +0 -268
  145. package/src/components/sections/tout/index.ts +0 -1
  146. package/src/components/sections/tout/tout.stories.tsx +0 -171
  147. package/src/components/sections/tout/tout.test.tsx +0 -242
  148. package/src/components/sections/two-column-section/index.ts +0 -5
  149. package/src/components/sections/two-column-section/two-column-section.stories.tsx +0 -285
  150. package/src/components/shared/index.ts +0 -5
  151. package/src/index.ts +0 -293
  152. package/src/main.tsx +0 -13
  153. package/src/stories/grid-system.stories.tsx +0 -309
  154. package/src/stories/introduction.mdx +0 -128
  155. package/src/stories/theme-provider.stories.tsx +0 -349
  156. package/src/stories/token-showcase.stories.tsx +0 -73
  157. package/src/stories/token-showcase.tsx +0 -777
  158. package/src/styles.css +0 -14
  159. package/src/tests/token-resolution.test.tsx +0 -298
  160. package/src/theme/theme-provider.test.tsx +0 -270
@@ -1,348 +0,0 @@
1
- import type { Meta, StoryObj } from "@storybook/react-vite";
2
- import { Button } from "../button";
3
- import {
4
- Tooltip,
5
- TooltipArrow,
6
- TooltipParts,
7
- TooltipPopup,
8
- TooltipPortal,
9
- TooltipPositioner,
10
- TooltipProvider,
11
- TooltipTrigger,
12
- } from ".";
13
-
14
- const meta: Meta<typeof Tooltip> = {
15
- title: "Atoms/Tooltip",
16
- component: Tooltip,
17
- argTypes: {
18
- side: {
19
- control: { type: "select" },
20
- options: ["top", "bottom", "left", "right"],
21
- },
22
- align: {
23
- control: { type: "select" },
24
- options: ["start", "center", "end"],
25
- },
26
- sideOffset: {
27
- control: { type: "number" },
28
- },
29
- delay: {
30
- control: { type: "number" },
31
- },
32
- closeDelay: {
33
- control: { type: "number" },
34
- },
35
- showArrow: {
36
- control: { type: "boolean" },
37
- },
38
- },
39
- args: {
40
- side: "top",
41
- align: "center",
42
- sideOffset: 8,
43
- showArrow: true,
44
- },
45
- decorators: [
46
- (Story) => (
47
- <div className="flex min-h-[200px] items-center justify-center p-48">
48
- <Story />
49
- </div>
50
- ),
51
- ],
52
- } satisfies Meta<typeof Tooltip>;
53
-
54
- export default meta;
55
- type Story = StoryObj<typeof Tooltip>;
56
-
57
- // =============================================================================
58
- // Playground
59
- // =============================================================================
60
-
61
- export const Playground: Story = {
62
- render: (args) => (
63
- <Tooltip {...args} content="This is a tooltip">
64
- <Button>Hover me</Button>
65
- </Tooltip>
66
- ),
67
- };
68
-
69
- // =============================================================================
70
- // Basic Examples
71
- // =============================================================================
72
-
73
- /**
74
- * Basic tooltip with default settings.
75
- */
76
- export const Default: Story = {
77
- render: () => (
78
- <Tooltip content="Save your changes">
79
- <Button>Save</Button>
80
- </Tooltip>
81
- ),
82
- };
83
-
84
- /**
85
- * Tooltip without arrow.
86
- */
87
- export const NoArrow: Story = {
88
- render: () => (
89
- <Tooltip content="No arrow here" showArrow={false}>
90
- <Button>Hover me</Button>
91
- </Tooltip>
92
- ),
93
- };
94
-
95
- /**
96
- * Tooltip with longer content.
97
- */
98
- export const LongContent: Story = {
99
- render: () => (
100
- <Tooltip content="This is a longer tooltip that provides more detailed information about the element.">
101
- <Button>Hover for details</Button>
102
- </Tooltip>
103
- ),
104
- };
105
-
106
- // =============================================================================
107
- // Positioning
108
- // =============================================================================
109
-
110
- /**
111
- * Tooltip positioned on all four sides.
112
- */
113
- export const AllPositions: Story = {
114
- render: () => (
115
- <div className="flex flex-col items-center gap-48">
116
- <Tooltip content="Top tooltip" side="top">
117
- <Button variant="outline">Top</Button>
118
- </Tooltip>
119
- <div className="flex items-center gap-48">
120
- <Tooltip content="Left tooltip" side="left">
121
- <Button variant="outline">Left</Button>
122
- </Tooltip>
123
- <Tooltip content="Right tooltip" side="right">
124
- <Button variant="outline">Right</Button>
125
- </Tooltip>
126
- </div>
127
- <Tooltip content="Bottom tooltip" side="bottom">
128
- <Button variant="outline">Bottom</Button>
129
- </Tooltip>
130
- </div>
131
- ),
132
- };
133
-
134
- export const Top: Story = {
135
- render: () => (
136
- <Tooltip content="Top position" side="top">
137
- <Button>Top</Button>
138
- </Tooltip>
139
- ),
140
- };
141
-
142
- export const Bottom: Story = {
143
- render: () => (
144
- <Tooltip content="Bottom position" side="bottom">
145
- <Button>Bottom</Button>
146
- </Tooltip>
147
- ),
148
- };
149
-
150
- export const Left: Story = {
151
- render: () => (
152
- <Tooltip content="Left position" side="left">
153
- <Button>Left</Button>
154
- </Tooltip>
155
- ),
156
- };
157
-
158
- export const Right: Story = {
159
- render: () => (
160
- <Tooltip content="Right position" side="right">
161
- <Button>Right</Button>
162
- </Tooltip>
163
- ),
164
- };
165
-
166
- // =============================================================================
167
- // Alignment
168
- // =============================================================================
169
-
170
- /**
171
- * Tooltip alignment options.
172
- */
173
- export const Alignment: Story = {
174
- render: () => (
175
- <div className="flex flex-col gap-24">
176
- <div className="flex items-center gap-24">
177
- <Tooltip content="Aligned to start" side="bottom" align="start">
178
- <Button variant="secondary" className="w-144">
179
- Start
180
- </Button>
181
- </Tooltip>
182
- <Tooltip content="Aligned to center" side="bottom" align="center">
183
- <Button variant="secondary" className="w-144">
184
- Center
185
- </Button>
186
- </Tooltip>
187
- <Tooltip content="Aligned to end" side="bottom" align="end">
188
- <Button variant="secondary" className="w-144">
189
- End
190
- </Button>
191
- </Tooltip>
192
- </div>
193
- </div>
194
- ),
195
- };
196
-
197
- // =============================================================================
198
- // Delays
199
- // =============================================================================
200
-
201
- /**
202
- * Tooltip with custom open delay.
203
- */
204
- export const CustomDelay: Story = {
205
- render: () => (
206
- <Tooltip content="Appears after 1 second" delay={1000}>
207
- <Button>1s delay</Button>
208
- </Tooltip>
209
- ),
210
- };
211
-
212
- /**
213
- * Tooltip with close delay.
214
- */
215
- export const CloseDelay: Story = {
216
- render: () => (
217
- <Tooltip content="Stays visible for 500ms" closeDelay={500}>
218
- <Button>Close delay</Button>
219
- </Tooltip>
220
- ),
221
- };
222
-
223
- // =============================================================================
224
- // With Provider (Shared Delays)
225
- // =============================================================================
226
-
227
- /**
228
- * Multiple tooltips with shared delay using TooltipProvider.
229
- * After opening one tooltip, others open instantly.
230
- */
231
- export const WithProvider: Story = {
232
- render: () => (
233
- <TooltipProvider delay={300} closeDelay={0}>
234
- <div className="flex items-center gap-16">
235
- <Tooltip content="First tooltip">
236
- <Button variant="outline">First</Button>
237
- </Tooltip>
238
- <Tooltip content="Second tooltip">
239
- <Button variant="outline">Second</Button>
240
- </Tooltip>
241
- <Tooltip content="Third tooltip">
242
- <Button variant="outline">Third</Button>
243
- </Tooltip>
244
- </div>
245
- </TooltipProvider>
246
- ),
247
- };
248
-
249
- // =============================================================================
250
- // Compound Component API
251
- // =============================================================================
252
-
253
- /**
254
- * Using the compound component API for full control.
255
- */
256
- export const CompoundAPI: Story = {
257
- render: () => (
258
- <TooltipParts>
259
- <TooltipTrigger>
260
- <Button variant="primary">Custom Tooltip</Button>
261
- </TooltipTrigger>
262
- <TooltipPortal>
263
- <TooltipPositioner side="bottom" sideOffset={12}>
264
- <TooltipPopup>
265
- <TooltipArrow />
266
- Built with compound components
267
- </TooltipPopup>
268
- </TooltipPositioner>
269
- </TooltipPortal>
270
- </TooltipParts>
271
- ),
272
- };
273
-
274
- // =============================================================================
275
- // On Different Elements
276
- // =============================================================================
277
-
278
- /**
279
- * Tooltip on various trigger elements.
280
- */
281
- export const OnDifferentElements: Story = {
282
- render: () => (
283
- <div className="flex items-center gap-24">
284
- <Tooltip content="Button tooltip">
285
- <Button>Button</Button>
286
- </Tooltip>
287
-
288
- <Tooltip content="Icon tooltip">
289
- <button
290
- type="button"
291
- className="flex size-36 items-center justify-center rounded-surface-ui-small bg-bg-section text-text-primary hover:bg-bg-section-secondary"
292
- >
293
- <svg
294
- className="size-20"
295
- fill="none"
296
- viewBox="0 0 24 24"
297
- stroke="currentColor"
298
- aria-hidden="true"
299
- >
300
- <path
301
- strokeLinecap="round"
302
- strokeLinejoin="round"
303
- strokeWidth={2}
304
- d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
305
- />
306
- </svg>
307
- <span className="sr-only">Info</span>
308
- </button>
309
- </Tooltip>
310
-
311
- <Tooltip content="Text tooltip">
312
- <span className="cursor-help border-b border-dashed border-fg-muted text-text-secondary">
313
- Hover this text
314
- </span>
315
- </Tooltip>
316
- </div>
317
- ),
318
- };
319
-
320
- // =============================================================================
321
- // Controlled
322
- // =============================================================================
323
-
324
- /**
325
- * Controlled tooltip with external state management.
326
- */
327
- export const Controlled: Story = {
328
- render: function ControlledStory() {
329
- const [open, setOpen] = React.useState(false);
330
-
331
- return (
332
- <div className="flex flex-col items-center gap-16">
333
- <Tooltip
334
- content="Controlled tooltip"
335
- open={open}
336
- onOpenChange={setOpen}
337
- >
338
- <Button>Hover or click button below</Button>
339
- </Tooltip>
340
- <Button variant="outline" onClick={() => setOpen(!open)}>
341
- {open ? "Close tooltip" : "Open tooltip"}
342
- </Button>
343
- </div>
344
- );
345
- },
346
- };
347
-
348
- import * as React from "react";
@@ -1,363 +0,0 @@
1
- import { describe, expect, test, vi } from "vitest";
2
- import { page, userEvent } from "vitest/browser";
3
- import { render } from "vitest-browser-react";
4
- import { Button } from "../button";
5
- import {
6
- Tooltip,
7
- TooltipArrow,
8
- TooltipParts,
9
- TooltipPopup,
10
- TooltipPortal,
11
- TooltipPositioner,
12
- TooltipProvider,
13
- TooltipTrigger,
14
- } from "./tooltip";
15
-
16
- describe("Tooltip", () => {
17
- describe("Accessibility", () => {
18
- test("trigger element is accessible", async () => {
19
- render(
20
- <Tooltip content="Helpful tip">
21
- <Button>Hover me</Button>
22
- </Tooltip>,
23
- );
24
- await expect
25
- .element(page.getByRole("button", { name: "Hover me" }))
26
- .toBeInTheDocument();
27
- });
28
-
29
- test("tooltip has correct role when visible", async () => {
30
- render(
31
- <Tooltip content="Helpful tip" defaultOpen>
32
- <Button>Hover me</Button>
33
- </Tooltip>,
34
- );
35
- await expect
36
- .element(page.getByRole("tooltip", { name: "Helpful tip" }))
37
- .toBeInTheDocument();
38
- });
39
-
40
- test("trigger element is focusable", async () => {
41
- render(
42
- <Tooltip content="Helpful tip">
43
- <Button>Focus me</Button>
44
- </Tooltip>,
45
- );
46
- await userEvent.keyboard("{Tab}");
47
- await expect
48
- .element(page.getByRole("button", { name: "Focus me" }))
49
- .toHaveFocus();
50
- });
51
- });
52
-
53
- describe("Interactions", () => {
54
- test("shows tooltip on hover", async () => {
55
- render(
56
- <Tooltip content="Hover tooltip">
57
- <Button>Hover me</Button>
58
- </Tooltip>,
59
- );
60
-
61
- // Tooltip should not be visible initially
62
- await expect
63
- .element(page.getByRole("tooltip", { name: "Hover tooltip" }))
64
- .not.toBeInTheDocument();
65
-
66
- // Hover over the trigger
67
- await page.getByRole("button", { name: "Hover me" }).hover();
68
-
69
- // Tooltip should now be visible
70
- await expect
71
- .element(page.getByRole("tooltip", { name: "Hover tooltip" }))
72
- .toBeInTheDocument();
73
- });
74
-
75
- test("shows tooltip on focus", async () => {
76
- render(
77
- <Tooltip content="Focus tooltip">
78
- <Button>Focus me</Button>
79
- </Tooltip>,
80
- );
81
-
82
- // Tooltip should not be visible initially
83
- await expect
84
- .element(page.getByRole("tooltip", { name: "Focus tooltip" }))
85
- .not.toBeInTheDocument();
86
-
87
- // Focus the trigger
88
- page.getByRole("button", { name: "Focus me" }).element().focus();
89
-
90
- // Tooltip should now be visible
91
- await expect
92
- .element(page.getByRole("tooltip", { name: "Focus tooltip" }))
93
- .toBeInTheDocument();
94
- });
95
-
96
- test("hides tooltip on blur", async () => {
97
- render(
98
- <>
99
- <Tooltip content="Focus tooltip">
100
- <Button>Focus me</Button>
101
- </Tooltip>
102
- <Button>Other button</Button>
103
- </>,
104
- );
105
-
106
- // Focus the trigger to show tooltip
107
- page.getByRole("button", { name: "Focus me" }).element().focus();
108
- await expect
109
- .element(page.getByRole("tooltip", { name: "Focus tooltip" }))
110
- .toBeInTheDocument();
111
-
112
- // Blur by focusing another element
113
- page.getByRole("button", { name: "Other button" }).element().focus();
114
-
115
- // Tooltip should be hidden
116
- await expect
117
- .element(page.getByRole("tooltip", { name: "Focus tooltip" }))
118
- .not.toBeInTheDocument();
119
- });
120
- });
121
-
122
- describe("Controlled State", () => {
123
- test("respects controlled open state", async () => {
124
- render(
125
- <Tooltip content="Controlled tooltip" open={true}>
126
- <Button>Trigger</Button>
127
- </Tooltip>,
128
- );
129
-
130
- // Tooltip should be visible when open=true
131
- await expect
132
- .element(page.getByRole("tooltip", { name: "Controlled tooltip" }))
133
- .toBeInTheDocument();
134
- });
135
-
136
- test("respects controlled closed state", async () => {
137
- render(
138
- <Tooltip content="Controlled tooltip" open={false}>
139
- <Button>Trigger</Button>
140
- </Tooltip>,
141
- );
142
-
143
- // Tooltip should not be visible when open=false
144
- await expect
145
- .element(page.getByRole("tooltip", { name: "Controlled tooltip" }))
146
- .not.toBeInTheDocument();
147
-
148
- // Should not show on hover when controlled
149
- await page.getByRole("button", { name: "Trigger" }).hover();
150
- await expect
151
- .element(page.getByRole("tooltip", { name: "Controlled tooltip" }))
152
- .not.toBeInTheDocument();
153
- });
154
-
155
- test("calls onOpenChange callback", async () => {
156
- const handleOpenChange = vi.fn();
157
- render(
158
- <Tooltip content="Callback tooltip" onOpenChange={handleOpenChange}>
159
- <Button>Trigger</Button>
160
- </Tooltip>,
161
- );
162
-
163
- // Hover to trigger open
164
- await page.getByRole("button", { name: "Trigger" }).hover();
165
-
166
- // Wait for tooltip to appear (ensures callback has been called)
167
- await expect
168
- .element(page.getByRole("tooltip", { name: "Callback tooltip" }))
169
- .toBeInTheDocument();
170
-
171
- // Callback should have been called with true as first argument
172
- // (Base UI passes additional context as second argument)
173
- expect(handleOpenChange).toHaveBeenCalled();
174
- expect(handleOpenChange.mock.calls[0][0]).toBe(true);
175
- });
176
-
177
- test("defaultOpen shows tooltip initially", async () => {
178
- render(
179
- <Tooltip content="Default open tooltip" defaultOpen>
180
- <Button>Trigger</Button>
181
- </Tooltip>,
182
- );
183
-
184
- // Tooltip should be visible initially
185
- await expect
186
- .element(page.getByRole("tooltip", { name: "Default open tooltip" }))
187
- .toBeInTheDocument();
188
- });
189
- });
190
-
191
- describe("Content", () => {
192
- test("displays text content", async () => {
193
- render(
194
- <Tooltip content="Simple text" defaultOpen>
195
- <Button>Trigger</Button>
196
- </Tooltip>,
197
- );
198
-
199
- await expect.element(page.getByText("Simple text")).toBeInTheDocument();
200
- });
201
-
202
- test("displays React node content", async () => {
203
- render(
204
- <Tooltip
205
- content={
206
- <span data-testid="custom-content">
207
- <strong>Bold</strong> text
208
- </span>
209
- }
210
- defaultOpen
211
- >
212
- <Button>Trigger</Button>
213
- </Tooltip>,
214
- );
215
-
216
- await expect
217
- .element(page.getByTestId("custom-content"))
218
- .toBeInTheDocument();
219
- await expect.element(page.getByText("Bold")).toBeInTheDocument();
220
- });
221
- });
222
-
223
- describe("Arrow", () => {
224
- test("shows arrow by default", async () => {
225
- render(
226
- <Tooltip content="With arrow" defaultOpen>
227
- <Button>Trigger</Button>
228
- </Tooltip>,
229
- );
230
-
231
- // The arrow is an SVG element rendered by Base UI
232
- const tooltip = page.getByRole("tooltip");
233
- await expect.element(tooltip).toBeInTheDocument();
234
- });
235
-
236
- test("hides arrow when showArrow is false", async () => {
237
- render(
238
- <Tooltip content="Without arrow" defaultOpen showArrow={false}>
239
- <Button>Trigger</Button>
240
- </Tooltip>,
241
- );
242
-
243
- const tooltip = page.getByRole("tooltip");
244
- await expect.element(tooltip).toBeInTheDocument();
245
- });
246
- });
247
-
248
- describe("Compound Components", () => {
249
- test("renders with compound component API", async () => {
250
- render(
251
- <TooltipParts defaultOpen>
252
- <TooltipTrigger>
253
- <Button>Compound trigger</Button>
254
- </TooltipTrigger>
255
- <TooltipPortal>
256
- <TooltipPositioner>
257
- <TooltipPopup>
258
- <TooltipArrow />
259
- Compound tooltip content
260
- </TooltipPopup>
261
- </TooltipPositioner>
262
- </TooltipPortal>
263
- </TooltipParts>,
264
- );
265
-
266
- await expect
267
- .element(page.getByRole("button", { name: "Compound trigger" }))
268
- .toBeInTheDocument();
269
- await expect
270
- .element(page.getByText("Compound tooltip content"))
271
- .toBeInTheDocument();
272
- });
273
- });
274
-
275
- describe("Provider", () => {
276
- test("TooltipProvider wraps children", async () => {
277
- render(
278
- <TooltipProvider>
279
- <Tooltip content="Provider tooltip" defaultOpen>
280
- <Button>Trigger</Button>
281
- </Tooltip>
282
- </TooltipProvider>,
283
- );
284
-
285
- await expect
286
- .element(page.getByRole("tooltip", { name: "Provider tooltip" }))
287
- .toBeInTheDocument();
288
- });
289
- });
290
-
291
- describe("Styles", () => {
292
- test("tooltip popup has dark background", async () => {
293
- render(
294
- <Tooltip content="Styled tooltip" defaultOpen>
295
- <Button>Trigger</Button>
296
- </Tooltip>,
297
- );
298
-
299
- const tooltip = page.getByRole("tooltip");
300
- await expect.element(tooltip).toBeInTheDocument();
301
-
302
- const element = tooltip.element();
303
- const styles = window.getComputedStyle(element);
304
-
305
- // Tooltip should have a light background (not transparent)
306
- expect(styles.backgroundColor).not.toBe("rgba(0, 0, 0, 0)");
307
- expect(styles.backgroundColor).not.toBe("transparent");
308
- });
309
-
310
- test("tooltip has border radius", async () => {
311
- render(
312
- <Tooltip content="Styled tooltip" defaultOpen>
313
- <Button>Trigger</Button>
314
- </Tooltip>,
315
- );
316
-
317
- const tooltip = page.getByRole("tooltip");
318
- await expect.element(tooltip).toBeInTheDocument();
319
-
320
- const element = tooltip.element();
321
- const styles = window.getComputedStyle(element);
322
-
323
- // Should have border radius
324
- const borderRadius = parseFloat(styles.borderRadius);
325
- expect(borderRadius).toBeGreaterThan(0);
326
- });
327
-
328
- test("tooltip has shadow", async () => {
329
- render(
330
- <Tooltip content="Styled tooltip" defaultOpen>
331
- <Button>Trigger</Button>
332
- </Tooltip>,
333
- );
334
-
335
- const tooltip = page.getByRole("tooltip");
336
- await expect.element(tooltip).toBeInTheDocument();
337
-
338
- const element = tooltip.element();
339
- const styles = window.getComputedStyle(element);
340
-
341
- // Should have a box shadow
342
- expect(styles.boxShadow).not.toBe("none");
343
- });
344
-
345
- test("tooltip has high z-index", async () => {
346
- render(
347
- <Tooltip content="Styled tooltip" defaultOpen>
348
- <Button>Trigger</Button>
349
- </Tooltip>,
350
- );
351
-
352
- const tooltip = page.getByRole("tooltip");
353
- await expect.element(tooltip).toBeInTheDocument();
354
-
355
- const element = tooltip.element();
356
- const styles = window.getComputedStyle(element);
357
-
358
- // Should have z-index of 50 or higher
359
- const zIndex = parseInt(styles.zIndex, 10);
360
- expect(zIndex).toBeGreaterThanOrEqual(50);
361
- });
362
- });
363
- });