@fragments-sdk/ui 0.8.4 → 0.8.5

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 (30) hide show
  1. package/fragments.json +1 -1
  2. package/package.json +29 -7
  3. package/src/blocks/NavigationHeader.block.ts +89 -0
  4. package/src/components/Chart/Chart.fragment.tsx +3 -0
  5. package/src/components/Chart/index.tsx +62 -14
  6. package/src/components/CodeBlock/CodeBlock.fragment.tsx +3 -0
  7. package/src/components/CodeBlock/CodeBlock.test.tsx +6 -6
  8. package/src/components/CodeBlock/index.tsx +38 -3
  9. package/src/components/ColorPicker/ColorPicker.fragment.tsx +3 -0
  10. package/src/components/ColorPicker/index.tsx +24 -2
  11. package/src/components/DatePicker/DatePicker.fragment.tsx +4 -0
  12. package/src/components/DatePicker/index.tsx +101 -43
  13. package/src/components/Header/Header.fragment.tsx +37 -0
  14. package/src/components/Link/Link.fragment.tsx +17 -0
  15. package/src/components/Link/Link.test.tsx +23 -0
  16. package/src/components/Link/index.tsx +20 -0
  17. package/src/components/Markdown/Markdown.fragment.tsx +4 -0
  18. package/src/components/NavigationMenu/NavigationMenu.fragment.tsx +270 -0
  19. package/src/components/NavigationMenu/NavigationMenu.module.scss +516 -0
  20. package/src/components/NavigationMenu/NavigationMenu.test.tsx +457 -0
  21. package/src/components/NavigationMenu/NavigationMenuContext.ts +89 -0
  22. package/src/components/NavigationMenu/index.tsx +854 -0
  23. package/src/components/NavigationMenu/useNavigationMenu.ts +91 -0
  24. package/src/components/Sidebar/Sidebar.fragment.tsx +1 -1
  25. package/src/components/Sidebar/Sidebar.module.scss +2 -1
  26. package/src/components/Table/Table.fragment.tsx +3 -0
  27. package/src/components/Table/index.tsx +70 -24
  28. package/src/index.ts +25 -0
  29. package/src/tokens/_palettes.scss +8 -7
  30. package/src/tokens/_seeds.scss +2 -2
@@ -0,0 +1,516 @@
1
+ @use '../../tokens/variables' as *;
2
+ @use '../../tokens/mixins' as *;
3
+
4
+ // ============================================
5
+ // Root
6
+ // ============================================
7
+
8
+ .root {
9
+ position: relative;
10
+ display: flex;
11
+ align-items: center;
12
+ }
13
+
14
+ .rootVertical {
15
+ flex-direction: column;
16
+ align-items: flex-start;
17
+ }
18
+
19
+ // ============================================
20
+ // List
21
+ // ============================================
22
+
23
+ .list {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: var(--fui-space-1, $fui-space-1);
27
+ list-style: none;
28
+ margin: 0;
29
+ padding: 0;
30
+
31
+ // Hide on mobile — hamburger replaces it
32
+ @include below-md {
33
+ display: none;
34
+ }
35
+ }
36
+
37
+ .listVertical {
38
+ flex-direction: column;
39
+ align-items: stretch;
40
+ }
41
+
42
+ // ============================================
43
+ // Trigger
44
+ // ============================================
45
+
46
+ .trigger {
47
+ @include button-reset;
48
+ @include interactive-base;
49
+ @include text-base;
50
+
51
+ display: flex;
52
+ align-items: center;
53
+ gap: var(--fui-space-1, $fui-space-1);
54
+ padding: var(--fui-padding-item-xs, $fui-padding-item-xs) var(--fui-padding-item-md, $fui-padding-item-md);
55
+ border-radius: var(--fui-radius-md, $fui-radius-md);
56
+ color: var(--fui-text-secondary, $fui-text-secondary);
57
+ white-space: nowrap;
58
+ min-height: var(--fui-button-height-md, $fui-button-height-md);
59
+ cursor: pointer;
60
+
61
+ &:hover {
62
+ background-color: var(--fui-bg-hover, $fui-bg-hover);
63
+ color: var(--fui-text-primary, $fui-text-primary);
64
+ }
65
+
66
+ &:active {
67
+ background-color: var(--fui-bg-active, $fui-bg-active);
68
+ }
69
+
70
+ &[data-state='open'] {
71
+ color: var(--fui-text-primary, $fui-text-primary);
72
+ }
73
+ }
74
+
75
+ .triggerChevron {
76
+ transition: transform var(--fui-transition-fast, $fui-transition-fast);
77
+ flex-shrink: 0;
78
+
79
+ [data-state='open'] > & {
80
+ transform: rotate(180deg);
81
+ }
82
+ }
83
+
84
+ // ============================================
85
+ // Content
86
+ // ============================================
87
+
88
+ .content {
89
+ position: absolute;
90
+ left: 0;
91
+ top: 0;
92
+ width: auto;
93
+
94
+ // Motion direction for directional slide
95
+ &[data-motion='from-start'] {
96
+ animation: slideFromStart var(--fui-transition-normal, $fui-transition-normal) ease forwards;
97
+ }
98
+ &[data-motion='from-end'] {
99
+ animation: slideFromEnd var(--fui-transition-normal, $fui-transition-normal) ease forwards;
100
+ }
101
+ &[data-motion='to-start'] {
102
+ animation: slideToStart var(--fui-transition-normal, $fui-transition-normal) ease forwards;
103
+ }
104
+ &[data-motion='to-end'] {
105
+ animation: slideToEnd var(--fui-transition-normal, $fui-transition-normal) ease forwards;
106
+ }
107
+ }
108
+
109
+ @keyframes slideFromStart {
110
+ from {
111
+ opacity: 0;
112
+ transform: translateX(calc(-1 * #{$fui-anim-offset-md}));
113
+ }
114
+ to {
115
+ opacity: 1;
116
+ transform: translateX(0);
117
+ }
118
+ }
119
+
120
+ @keyframes slideFromEnd {
121
+ from {
122
+ opacity: 0;
123
+ transform: translateX($fui-anim-offset-md);
124
+ }
125
+ to {
126
+ opacity: 1;
127
+ transform: translateX(0);
128
+ }
129
+ }
130
+
131
+ @keyframes slideToStart {
132
+ from {
133
+ opacity: 1;
134
+ transform: translateX(0);
135
+ }
136
+ to {
137
+ opacity: 0;
138
+ transform: translateX(calc(-1 * #{$fui-anim-offset-md}));
139
+ }
140
+ }
141
+
142
+ @keyframes slideToEnd {
143
+ from {
144
+ opacity: 1;
145
+ transform: translateX(0);
146
+ }
147
+ to {
148
+ opacity: 0;
149
+ transform: translateX($fui-anim-offset-md);
150
+ }
151
+ }
152
+
153
+ // ============================================
154
+ // Link
155
+ // ============================================
156
+
157
+ .link {
158
+ @include text-base;
159
+
160
+ display: flex;
161
+ align-items: center;
162
+ padding: var(--fui-padding-item-xs, $fui-padding-item-xs) var(--fui-padding-item-md, $fui-padding-item-md);
163
+ border-radius: var(--fui-radius-md, $fui-radius-md);
164
+ color: var(--fui-text-secondary, $fui-text-secondary);
165
+ text-decoration: none;
166
+ white-space: nowrap;
167
+ min-height: var(--fui-button-height-md, $fui-button-height-md);
168
+ transition: background-color var(--fui-transition-fast, $fui-transition-fast),
169
+ color var(--fui-transition-fast, $fui-transition-fast);
170
+
171
+ &:hover {
172
+ background-color: var(--fui-bg-hover, $fui-bg-hover);
173
+ color: var(--fui-text-primary, $fui-text-primary);
174
+ }
175
+
176
+ &:focus-visible {
177
+ @include focus-ring;
178
+ }
179
+ }
180
+
181
+ .linkActive {
182
+ color: var(--fui-text-primary, $fui-text-primary);
183
+ font-weight: var(--fui-font-weight-medium, $fui-font-weight-medium);
184
+ background-color: var(--fui-bg-secondary, $fui-bg-secondary);
185
+
186
+ &:hover {
187
+ background-color: var(--fui-bg-secondary, $fui-bg-secondary);
188
+ color: var(--fui-text-primary, $fui-text-primary);
189
+ }
190
+ }
191
+
192
+ // Structured link (title + description + icon) inside content panels
193
+ .linkStructured {
194
+ display: flex;
195
+ gap: var(--fui-space-3, $fui-space-3);
196
+ padding: var(--fui-padding-item-sm, $fui-padding-item-sm) var(--fui-padding-item-md, $fui-padding-item-md);
197
+ border-radius: var(--fui-radius-md, $fui-radius-md);
198
+ white-space: normal;
199
+ min-height: auto;
200
+
201
+ &:hover {
202
+ background-color: var(--fui-bg-hover, $fui-bg-hover);
203
+ }
204
+ }
205
+
206
+ .linkIcon {
207
+ display: flex;
208
+ align-items: center;
209
+ justify-content: center;
210
+ flex-shrink: 0;
211
+ width: var(--fui-icon-xl, $fui-icon-xl);
212
+ height: var(--fui-icon-xl, $fui-icon-xl);
213
+ color: var(--fui-text-secondary, $fui-text-secondary);
214
+ margin-top: var(--fui-space-0-5, $fui-space-0-5);
215
+ }
216
+
217
+ .linkBody {
218
+ display: flex;
219
+ flex-direction: column;
220
+ gap: var(--fui-space-0-5, $fui-space-0-5);
221
+ min-width: 0;
222
+ }
223
+
224
+ .linkTitle {
225
+ font-weight: var(--fui-font-weight-medium, $fui-font-weight-medium);
226
+ color: var(--fui-text-primary, $fui-text-primary);
227
+ font-size: var(--fui-font-size-sm, $fui-font-size-sm);
228
+ line-height: var(--fui-line-height-tight, $fui-line-height-tight);
229
+ }
230
+
231
+ .linkDescription {
232
+ font-size: var(--fui-font-size-xs, $fui-font-size-xs);
233
+ color: var(--fui-text-secondary, $fui-text-secondary);
234
+ line-height: var(--fui-line-height-normal, $fui-line-height-normal);
235
+ }
236
+
237
+ .linkFeatured {
238
+ background-color: var(--fui-bg-secondary, $fui-bg-secondary);
239
+ border: 1px solid var(--fui-border, $fui-border);
240
+
241
+ &:hover {
242
+ background-color: var(--fui-bg-hover, $fui-bg-hover);
243
+ border-color: var(--fui-border-strong, $fui-border-strong);
244
+ }
245
+ }
246
+
247
+ // ============================================
248
+ // Indicator
249
+ // ============================================
250
+
251
+ .indicator {
252
+ position: absolute;
253
+ bottom: 0;
254
+ height: 2px;
255
+ background-color: var(--fui-color-accent, $fui-color-accent);
256
+ border-radius: 1px;
257
+ transition:
258
+ left var(--fui-transition-normal, $fui-transition-normal),
259
+ width var(--fui-transition-normal, $fui-transition-normal);
260
+ pointer-events: none;
261
+ }
262
+
263
+ // ============================================
264
+ // Viewport
265
+ // ============================================
266
+
267
+ .viewport {
268
+ @include surface-elevated;
269
+
270
+ position: absolute;
271
+ top: 100%;
272
+ left: var(--fui-navmenu-viewport-left, 0);
273
+ overflow: hidden;
274
+ box-shadow: var(--fui-shadow-lg, $fui-shadow-lg);
275
+ z-index: calc(var(--fui-header-z-index, $fui-header-z-index) + 1);
276
+
277
+ width: var(--fui-navmenu-viewport-width);
278
+ height: var(--fui-navmenu-viewport-height);
279
+ transition:
280
+ left var(--fui-transition-fast, $fui-transition-fast),
281
+ opacity var(--fui-transition-fast, $fui-transition-fast);
282
+
283
+ // Hidden when no item is open
284
+ &[data-state='closed'] {
285
+ opacity: 0;
286
+ pointer-events: none;
287
+ // Collapse to avoid layout space
288
+ width: 0;
289
+ height: 0;
290
+ overflow: hidden;
291
+ }
292
+
293
+ &[data-state='open'] {
294
+ opacity: 1;
295
+ }
296
+
297
+ // Hide on mobile
298
+ @include below-md {
299
+ display: none;
300
+ }
301
+ }
302
+
303
+ // ============================================
304
+ // Hamburger (mobile trigger)
305
+ // ============================================
306
+
307
+ .hamburger {
308
+ @include button-reset;
309
+ @include interactive-base;
310
+
311
+ display: none;
312
+ align-items: center;
313
+ justify-content: center;
314
+ width: var(--fui-touch-lg, $fui-touch-lg);
315
+ height: var(--fui-touch-lg, $fui-touch-lg);
316
+ border-radius: var(--fui-radius-md, $fui-radius-md);
317
+ color: var(--fui-text-primary, $fui-text-primary);
318
+ flex-shrink: 0;
319
+
320
+ &:hover {
321
+ background-color: var(--fui-bg-hover, $fui-bg-hover);
322
+ }
323
+
324
+ svg {
325
+ width: var(--fui-icon-xl, $fui-icon-xl);
326
+ height: var(--fui-icon-xl, $fui-icon-xl);
327
+ }
328
+
329
+ @include below-md {
330
+ display: flex;
331
+ }
332
+ }
333
+
334
+ // ============================================
335
+ // Mobile Drawer
336
+ // ============================================
337
+
338
+ .drawerBackdrop {
339
+ position: fixed;
340
+ inset: 0;
341
+ background: var(--fui-backdrop, $fui-backdrop);
342
+ z-index: calc(var(--fui-header-z-index, $fui-header-z-index) + 10);
343
+ animation: fadeIn var(--fui-transition-normal, $fui-transition-normal) ease;
344
+ }
345
+
346
+ .drawer {
347
+ position: fixed;
348
+ top: 0;
349
+ bottom: 0;
350
+ left: 0;
351
+ width: min(320px, 85vw);
352
+ max-width: 380px;
353
+ background-color: var(--fui-bg-primary, $fui-bg-primary);
354
+ z-index: calc(var(--fui-header-z-index, $fui-header-z-index) + 11);
355
+ display: flex;
356
+ flex-direction: column;
357
+ overflow-y: auto;
358
+ animation: slideInLeft var(--fui-transition-normal, $fui-transition-normal) ease;
359
+
360
+ @media (min-width: 480px) {
361
+ width: min(380px, 85vw);
362
+ }
363
+ }
364
+
365
+ .drawerRight {
366
+ left: auto;
367
+ right: 0;
368
+ animation: slideInRight var(--fui-transition-normal, $fui-transition-normal) ease;
369
+ }
370
+
371
+ .drawerHeader {
372
+ display: flex;
373
+ align-items: center;
374
+ justify-content: space-between;
375
+ padding: var(--fui-space-3, $fui-space-3) var(--fui-padding-container-md, $fui-padding-container-md);
376
+ border-bottom: 1px solid var(--fui-border, $fui-border);
377
+ min-height: var(--fui-appshell-header-height, $fui-appshell-header-height);
378
+ }
379
+
380
+ .drawerClose {
381
+ @include button-reset;
382
+ @include interactive-base;
383
+
384
+ display: flex;
385
+ align-items: center;
386
+ justify-content: center;
387
+ width: var(--fui-touch-md, $fui-touch-md);
388
+ height: var(--fui-touch-md, $fui-touch-md);
389
+ border-radius: var(--fui-radius-md, $fui-radius-md);
390
+ color: var(--fui-text-secondary, $fui-text-secondary);
391
+
392
+ &:hover {
393
+ background-color: var(--fui-bg-hover, $fui-bg-hover);
394
+ color: var(--fui-text-primary, $fui-text-primary);
395
+ }
396
+ }
397
+
398
+ .drawerBody {
399
+ flex: 1;
400
+ overflow-y: auto;
401
+ padding: var(--fui-space-2, $fui-space-2) 0;
402
+ }
403
+
404
+ .drawerNav {
405
+ display: flex;
406
+ flex-direction: column;
407
+ }
408
+
409
+ .drawerLink {
410
+ @include button-reset;
411
+ @include text-base;
412
+
413
+ display: flex;
414
+ align-items: center;
415
+ width: 100%;
416
+ padding: var(--fui-padding-item-sm, $fui-padding-item-sm) var(--fui-padding-container-md, $fui-padding-container-md);
417
+ color: var(--fui-text-secondary, $fui-text-secondary);
418
+ text-decoration: none;
419
+ min-height: var(--fui-sidebar-item-height, $fui-sidebar-item-height);
420
+ transition: background-color var(--fui-transition-fast, $fui-transition-fast);
421
+
422
+ &:hover {
423
+ background-color: var(--fui-bg-hover, $fui-bg-hover);
424
+ color: var(--fui-text-primary, $fui-text-primary);
425
+ }
426
+ }
427
+
428
+ .drawerSectionLabel {
429
+ @include section-label-text;
430
+
431
+ padding: var(--fui-space-3, $fui-space-3) var(--fui-padding-container-md, $fui-padding-container-md)
432
+ var(--fui-space-1, $fui-space-1);
433
+ }
434
+
435
+ .drawerCollapsibleTrigger {
436
+ @include button-reset;
437
+ @include text-base;
438
+
439
+ display: flex;
440
+ align-items: center;
441
+ justify-content: space-between;
442
+ width: 100%;
443
+ padding: var(--fui-padding-item-sm, $fui-padding-item-sm) var(--fui-padding-container-md, $fui-padding-container-md);
444
+ color: var(--fui-text-primary, $fui-text-primary);
445
+ font-weight: var(--fui-font-weight-medium, $fui-font-weight-medium);
446
+ min-height: var(--fui-sidebar-item-height, $fui-sidebar-item-height);
447
+ transition: background-color var(--fui-transition-fast, $fui-transition-fast);
448
+
449
+ &:hover {
450
+ background-color: var(--fui-bg-hover, $fui-bg-hover);
451
+ }
452
+ }
453
+
454
+ .drawerCollapsibleChevron {
455
+ transition: transform var(--fui-transition-fast, $fui-transition-fast);
456
+ color: var(--fui-text-secondary, $fui-text-secondary);
457
+ flex-shrink: 0;
458
+
459
+ &[data-open='true'] {
460
+ transform: rotate(90deg);
461
+ }
462
+ }
463
+
464
+ .drawerCollapsibleContent {
465
+ padding-left: var(--fui-space-3, $fui-space-3);
466
+ }
467
+
468
+ // ============================================
469
+ // Animations
470
+ // ============================================
471
+
472
+ @keyframes fadeIn {
473
+ from { opacity: 0; }
474
+ to { opacity: 1; }
475
+ }
476
+
477
+ @keyframes slideInLeft {
478
+ from { transform: translateX(-100%); }
479
+ to { transform: translateX(0); }
480
+ }
481
+
482
+ @keyframes slideInRight {
483
+ from { transform: translateX(100%); }
484
+ to { transform: translateX(0); }
485
+ }
486
+
487
+ // ============================================
488
+ // Reduced Motion
489
+ // ============================================
490
+
491
+ @include prefers-reduced-motion {
492
+ .content {
493
+ animation: none;
494
+ }
495
+
496
+ .viewport {
497
+ transition: none;
498
+ }
499
+
500
+ .triggerChevron {
501
+ transition: none;
502
+ }
503
+
504
+ .indicator {
505
+ transition: none;
506
+ }
507
+
508
+ .drawer,
509
+ .drawerBackdrop {
510
+ animation: none;
511
+ }
512
+
513
+ .drawerCollapsibleChevron {
514
+ transition: none;
515
+ }
516
+ }