srcdev-nuxt-components 9.1.50 → 9.1.52

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 (34) hide show
  1. package/.claude/settings.json +8 -27
  2. package/.claude/settings.local.json +24 -52
  3. package/.claude/skills/components/action-menu.md +141 -0
  4. package/.claude/skills/components/stepper-list.md +52 -18
  5. package/.claude/skills/css-nesting-conventions.md +121 -0
  6. package/.claude/skills/index.md +3 -0
  7. package/.claude/skills/pull-request-description.md +48 -0
  8. package/.claude/skills/testing-add-unit-test.md +40 -2
  9. package/README.md +26 -5
  10. package/app/components/02.molecules/action-menu/ActionMenu.vue +218 -0
  11. package/app/components/02.molecules/action-menu/ActionMenuItemCore.vue +123 -0
  12. package/app/components/02.molecules/action-menu/CONSUMER-STYLING.md +125 -0
  13. package/app/components/02.molecules/action-menu/stories/ActionMenu.stories.ts +326 -0
  14. package/app/components/02.molecules/action-menu/tests/ActionMenu.spec.ts +458 -0
  15. package/app/components/02.molecules/action-menu/tests/ActionMenuItemCore.spec.ts +199 -0
  16. package/app/components/02.molecules/action-menu/tests/__snapshots__/ActionMenu.spec.ts.snap +28 -0
  17. package/app/components/02.molecules/action-menu/tests/__snapshots__/ActionMenuItemCore.spec.ts.snap +27 -0
  18. package/app/components/02.molecules/display-chip/tests/DisplayChip.spec.ts +5 -1
  19. package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +2 -1
  20. package/app/components/02.molecules/stepper-list/CONSUMER-STYLING.md +138 -0
  21. package/app/components/02.molecules/stepper-list/StepperList.vue +50 -24
  22. package/app/components/03.organisms/image-galleries/slider-gallery/tests/SliderGallery.spec.ts +5 -1
  23. package/app/components/05.forms/input-button/InputButtonCore.vue +1 -1
  24. package/app/components/carousels/tests/CarouselFlip.spec.ts +1 -0
  25. package/app/components/responsive-header/NavigationItems.vue +302 -81
  26. package/app/components/responsive-header/ResponsiveHeader.vue +360 -56
  27. package/app/layouts/default.vue +43 -352
  28. package/app/layouts/site-navigation-demo.vue +36 -34
  29. package/app/pages/page-hero-highlights.vue +3 -3
  30. package/app/pages/ui/scroll-reveal-image.vue +3 -3
  31. package/app/pages/ui/simple-grid.vue +9 -20
  32. package/modules/colour-scheme.ts +1 -1
  33. package/nuxt.config.ts +11 -2
  34. package/package.json +17 -16
@@ -16,12 +16,12 @@
16
16
  <ResponsiveHeader
17
17
  :responsive-nav-links
18
18
  :gap-between-first-and-second-nav="12"
19
- :style-class-passthrough="['your-scope-class']"
19
+ :style-class-passthrough="['site-header-nav']"
20
20
  :overflow-details-summary-icons="{
21
21
  more: 'gravity-ui:ellipsis',
22
22
  burger: 'gravity-ui:bars',
23
23
  }"
24
- :collapse-at-main-nav-intersection="true"
24
+ :collapse-at-main-nav-intersection="false"
25
25
  :allow-expand-on-gesture="false"
26
26
  >
27
27
  <template #secondaryNavigation>
@@ -215,13 +215,14 @@ onMounted(() => {
215
215
  display: grid;
216
216
  grid-template-columns: 1fr;
217
217
  grid-template-rows: auto 1fr auto;
218
+ align-items: start;
218
219
 
219
220
  .main-content {
220
221
  container-type: inline-size;
221
222
  }
222
223
  }
223
224
 
224
- /* Modifiers for ResposiveHeader */
225
+ /* ─── Header row layout ─────────────────────────────────────────────────── */
225
226
  .header {
226
227
  .debug-grid {
227
228
  display: none !important;
@@ -266,354 +267,44 @@ onMounted(() => {
266
267
  }
267
268
  }
268
269
 
269
- .navigation {
270
- margin: 1.2rem;
271
- border-radius: 0.8rem;
272
- background-color: #efefef05;
273
- border: 1px solid transparent;
274
- padding-block: 1rem;
275
- padding-inline: 1.2rem;
276
- inline-size: 100%;
277
- max-height: 6.4rem;
278
-
279
- /* max-block-size: 4.2rem; */
280
-
281
- .main-navigation {
282
- gap: 60px;
283
-
284
- .main-navigation-list {
285
- &:nth-of-type(1) {
286
- gap: 30px;
287
- }
288
-
289
- &:nth-of-type(2) {
290
- gap: 30px;
291
- }
292
-
293
- .main-navigation-item {
294
- width: initial;
295
-
296
- .main-navigation-link {
297
- position: relative;
298
- display: block;
299
- color: var(--slate-00);
300
- text-decoration: none;
301
- margin-inline-start: 0;
302
-
303
- padding: 8px 2px;
304
- border-bottom: 0.2rem solid #efefef25;
305
-
306
- &:before {
307
- content: "";
308
- position: absolute;
309
- bottom: 0;
310
- left: 0;
311
- width: 0%;
312
- height: 0.2rem;
313
- background-color: transparent;
314
- transition: all 0.3s;
315
- }
316
-
317
- &:hover {
318
- &:before {
319
- width: 100%;
320
- height: 0.2rem;
321
- background-color: var(--green-08);
322
- }
323
- }
324
- }
325
-
326
- .main-navigation-details {
327
- margin-inline-start: 0;
328
-
329
- .has-toggle-icon {
330
- gap: 6px;
331
- }
332
-
333
- .main-navigation-details-summary {
334
- position: relative;
335
- color: var(--slate-00);
336
- white-space: nowrap;
337
- border-bottom: 0.2rem solid #efefef25;
338
-
339
- &:before {
340
- content: "";
341
- position: absolute;
342
- bottom: 0;
343
- left: 0;
344
- width: 0%;
345
- height: 0.2rem;
346
- background-color: transparent;
347
- transition: all 0.3s;
348
- }
349
- }
350
-
351
- &[open] {
352
- .main-navigation-details-summary {
353
- &:before {
354
- width: 100%;
355
- height: 0.2rem;
356
- background-color: var(--green-08);
357
- }
358
- }
359
- }
360
-
361
- .main-navigation-sub-nav {
362
- padding: 8px;
363
- border: 1px solid #efefef75;
364
- border-radius: 8px;
365
- background-color: #000;
366
- translate: 0 12px;
367
-
368
- .main-navigation-sub-nav-list {
369
- display: grid;
370
- grid-template-columns: repeat(2, auto);
371
- gap: 12px;
372
-
373
- .main-navigation-sub-nav-item {
374
- display: block;
375
- margin-bottom: 0;
376
-
377
- &:last-child {
378
- margin-bottom: 0;
379
- }
380
-
381
- .main-navigation-sub-nav-link {
382
- position: relative;
383
- display: block;
384
- text-wrap-mode: nowrap;
385
- text-decoration: none;
386
- color: var(--slate-00);
387
- padding: 8px 2px;
388
- border-bottom: 0.2rem solid #efefef25;
389
- min-width: 170px;
390
-
391
- &:before {
392
- content: "";
393
- position: absolute;
394
- bottom: 0;
395
- left: 0;
396
- width: 0%;
397
- height: 0.2rem;
398
- background-color: transparent;
399
- transition: all 0.3s;
400
- }
401
-
402
- &:hover {
403
- &:before {
404
- width: 100%;
405
- height: 0.2rem;
406
- background-color: var(--green-08);
407
- }
408
- }
409
- }
410
- }
411
- }
412
- }
413
- }
414
- }
415
- }
416
- }
417
-
418
- .secondary-navigation {
419
- gap: 12px;
420
-
421
- .secondary-navigation-list {
422
- .secondary-navigation-item {
423
- .secondary-navigation-link {
424
- font: inherit;
425
- color: var(--slate-00);
426
-
427
- .icon {
428
- height: 1.35em;
429
- width: 1.35em;
430
- }
431
- }
432
- }
433
- }
434
-
435
- .main-navigation-link {
436
- color: var(--slate-00);
437
-
438
- .icon {
439
- height: 1.35em;
440
- width: 1.35em;
441
- }
442
- }
443
-
444
- .overflow-details {
445
- padding: 0;
446
- margin: 0;
447
-
448
- .overflow-details-summary {
449
- --_icon-zoom: 1;
450
- --_icon-size: 20px;
451
- --_border-width: 1px;
452
- --_outline-width: 1px;
453
- padding-inline: 5px;
454
-
455
- border-radius: 4px;
456
- border: var(--_border-width) solid #ffffff90;
457
- outline: var(--_outline-width) solid #ffffff10;
458
- background-color: var(--slate-08);
459
-
460
- width: 3rem;
461
- height: 3rem;
462
-
463
- &:hover,
464
- &:focus-visible {
465
- --_icon-zoom: 1.2;
466
- outline: 2px solid var(--green-08);
467
- outline-offset: 0.3rem;
468
-
469
- .icon {
470
- scale: 0.9;
471
- }
472
- }
473
-
474
- .icon {
475
- color: var(--slate-00);
476
- width: 2.6rem;
477
- height: 2.6rem;
478
- }
479
- }
480
-
481
- .overflow-details-nav {
482
- top: 135%;
483
- right: 0;
484
- background-color: #000;
485
- border: 0.1rem solid #ffffff90;
486
- border-radius: 8px;
487
- padding-block: 0;
488
- margin-block-end: -0.1rem;
489
- gap: 0.8rem;
490
-
491
- .overflow-navigation-wrapper {
492
- --overflow-nav-padding-inline: 0.8rem;
493
- --overflow-nav-items-gap: 0px;
494
- --overflow-nav-items-padding-block: 0.8rem;
495
- display: flex;
496
- flex-direction: column;
497
- gap: var(--overflow-nav-items-gap);
498
-
499
- .overflow-navigation-list {
500
- display: none;
501
-
502
- &.visible {
503
- display: flex;
504
- flex-direction: column;
505
- gap: var(--overflow-nav-items-gap);
506
- min-width: var(--_overflow-navigation-list-min-width, auto);
507
- }
508
-
509
- .overflow-navigation-item {
510
- display: none;
511
-
512
- &.visible {
513
- display: block;
514
- }
515
-
516
- .overflow-navigation-link {
517
- text-decoration: none;
518
- color: inherit;
519
- padding-block: var(--overflow-nav-items-padding-block);
520
- padding-inline: var(--overflow-nav-padding-inline);
521
- display: flex;
522
- color: var(--slate-00);
523
- border-bottom: 0.2rem solid #efefef75;
524
-
525
- &:hover {
526
- background-color: var(--slate-07);
527
- border-color: var(--green-08);
528
- }
529
- }
530
-
531
- .overflow-navigation-details {
532
- &.expanding-panel {
533
- margin-block-end: 0;
534
-
535
- .expanding-panel-details {
536
- .expanding-panel-summary {
537
- padding-block: var(--overflow-nav-items-padding-block);
538
- padding-inline: var(--overflow-nav-padding-inline);
539
- gap: 1rem;
540
- color: var(--slate-00);
541
- border-bottom: 0.2rem solid #efefef75;
542
-
543
- &:hover {
544
- background-color: var(--slate-07);
545
- border-color: var(--green-08);
546
- }
547
-
548
- .label-wrapper {
549
- .overflow-navigation-text {
550
- text-wrap: nowrap;
551
- }
552
- }
553
- .icon-wrapper {
554
- padding: 0;
555
- }
556
- }
557
-
558
- &[open] {
559
- .expanding-panel-summary {
560
- border-color: transparent;
561
-
562
- &:hover {
563
- background-color: var(--slate-07);
564
- border-color: var(--green-08);
565
- }
566
- }
567
- + .expanding-panel-content {
568
- border-bottom: 0.2rem solid #efefef75;
569
- .inner {
570
- .overflow-navigation-sub-nav-inner {
571
- margin-top: var(--overflow-nav-items-gap);
572
- }
573
- }
574
- }
575
- }
576
- }
577
-
578
- .expanding-panel-content {
579
- border-bottom: 0.2rem solid transparent;
580
-
581
- .inner {
582
- margin-top: 0;
583
-
584
- .overflow-navigation-sub-nav-inner {
585
- margin-top: 0;
586
-
587
- .overflow-navigation-sub-nav-list {
588
- display: flex;
589
- flex-direction: column;
590
- gap: 2px;
591
-
592
- .overflow-navigation-sub-nav-item {
593
- padding-block: var(--overflow-nav-items-padding-block);
594
- padding-inline: var(--overflow-nav-padding-inline);
595
- font-size: var(--step-4);
596
- color: var(--slate-00);
597
-
598
- &:hover {
599
- background-color: var(--slate-07);
600
- border-color: var(--green-08);
601
- }
602
- .overflow-navigation-sub-nav-link {
603
- text-decoration: none;
604
- }
605
- }
606
- }
607
- }
608
- }
609
- }
610
- }
611
- }
612
- }
613
- }
614
- }
615
- }
616
- }
617
- }
270
+ /* ─── ResponsiveHeader token overrides for this layout ──────────────────── */
271
+ .site-header-nav {
272
+ --responsive-header-margin: 1.2rem;
273
+ --responsive-header-bg: #efefef05;
274
+ --responsive-header-border: 1px solid transparent;
275
+ --responsive-header-border-radius: 0.8rem;
276
+ --responsive-header-padding-block: 1rem;
277
+ --responsive-header-padding-inline: 1.2rem;
278
+ --responsive-header-max-height: 6.4rem;
279
+ --responsive-header-inline-size: 100%;
280
+
281
+ --responsive-header-color: var(--slate-00);
282
+ --responsive-header-link-color: var(--slate-00);
283
+
284
+ --responsive-header-sub-nav-bg: #000;
285
+ --responsive-header-sub-nav-border: 1px solid #efefef75;
286
+
287
+ --responsive-header-overflow-btn-bg: var(--slate-08);
288
+ --responsive-header-overflow-btn-size: 3rem;
289
+ --responsive-header-overflow-btn-border: 1px solid #ffffff90;
290
+ --responsive-header-overflow-btn-outline: 1px solid #ffffff10;
291
+ --responsive-header-overflow-btn-icon-color: var(--slate-00);
292
+ --responsive-header-overflow-btn-hover-outline: 2px solid var(--green-08);
293
+
294
+ --responsive-header-overflow-nav-bg: #000;
295
+ --responsive-header-overflow-nav-border: 0.1rem solid #ffffff90;
296
+ --responsive-header-overflow-nav-padding-block: 0;
297
+
298
+ --overflow-nav-link-color: var(--slate-00);
299
+ --overflow-nav-link-border-color: #efefef75;
300
+ --overflow-nav-sub-item-color: var(--slate-00);
301
+ --overflow-nav-sub-item-font-size: var(--step-4);
302
+
303
+ --responsive-nav-decorator-indicator-color: var(--slate-00);
304
+ --responsive-nav-decorator-hovered-indicator-color: var(--green-08);
305
+ --responsive-nav-decorator-hovered-bg: oklch(100% 0 0 / 8%);
306
+ --overflow-nav-decorator-indicator-color: var(--slate-00);
307
+ --overflow-nav-decorator-hovered-indicator-color: var(--green-08);
308
+ --overflow-nav-decorator-hovered-bg: oklch(100% 0 0 / 6%);
618
309
  }
619
310
  </style>
@@ -103,15 +103,16 @@ const navItemData: NavItemData = {
103
103
  grid-template-columns: repeat(3, 1fr);
104
104
  gap: 1.6rem;
105
105
 
106
- &--wide {
106
+ @media (max-width: 600px) {
107
107
  grid-template-columns: repeat(2, 1fr);
108
108
  }
109
+ }
110
+
111
+ .snav-demo-grid--wide {
112
+ grid-template-columns: repeat(2, 1fr);
109
113
 
110
114
  @media (max-width: 600px) {
111
- grid-template-columns: repeat(2, 1fr);
112
- &--wide {
113
- grid-template-columns: 1fr;
114
- }
115
+ grid-template-columns: 1fr;
115
116
  }
116
117
  }
117
118
 
@@ -131,31 +132,31 @@ const navItemData: NavItemData = {
131
132
  align-items: start;
132
133
  margin-block-end: 4rem;
133
134
 
134
- &__text {
135
- h2,
136
- h3 {
137
- margin-block-start: 2.4rem;
138
- }
139
- p {
140
- line-height: 1.6;
141
- margin-block-end: 1.6rem;
142
- }
135
+ @media (max-width: 650px) {
136
+ grid-template-columns: 1fr;
143
137
  }
138
+ }
144
139
 
145
- &__img {
146
- width: 100%;
147
- height: auto;
148
- aspect-ratio: 3 / 4;
149
- object-fit: cover;
150
- border-radius: 0.4rem;
151
- display: block;
140
+ .snav-demo-split__text {
141
+ h2,
142
+ h3 {
143
+ margin-block-start: 2.4rem;
152
144
  }
153
-
154
- @media (max-width: 650px) {
155
- grid-template-columns: 1fr;
145
+ p {
146
+ line-height: 1.6;
147
+ margin-block-end: 1.6rem;
156
148
  }
157
149
  }
158
150
 
151
+ .snav-demo-split__img {
152
+ width: 100%;
153
+ height: auto;
154
+ aspect-ratio: 3 / 4;
155
+ object-fit: cover;
156
+ border-radius: 0.4rem;
157
+ display: block;
158
+ }
159
+
159
160
  .snav-demo-services {
160
161
  display: grid;
161
162
  grid-template-columns: repeat(3, 1fr);
@@ -170,17 +171,18 @@ const navItemData: NavItemData = {
170
171
  border-radius: 0.8rem;
171
172
  overflow: hidden;
172
173
  background: oklch(100% 0 0 / 5%);
174
+ }
175
+
176
+ .snav-demo-service-card__body {
177
+ padding: 1.6rem;
173
178
 
174
- &__body {
175
- padding: 1.6rem;
176
- h3 {
177
- margin-block-end: 0.8rem;
178
- }
179
- p {
180
- font-size: 1.4rem;
181
- line-height: 1.6;
182
- opacity: 0.8;
183
- }
179
+ h3 {
180
+ margin-block-end: 0.8rem;
181
+ }
182
+ p {
183
+ font-size: 1.4rem;
184
+ line-height: 1.6;
185
+ opacity: 0.8;
184
186
  }
185
187
  }
186
188
  </style>
@@ -178,7 +178,7 @@ const highlightsJustifyData = ref<IFormMultipleOptions>({
178
178
  border-radius: 0.8rem;
179
179
  background: var(--slate-01);
180
180
 
181
- &__heading {
181
+ .demo-controls__heading {
182
182
  font-size: 1.1rem;
183
183
  font-weight: 600;
184
184
  text-transform: uppercase;
@@ -187,14 +187,14 @@ const highlightsJustifyData = ref<IFormMultipleOptions>({
187
187
  margin-block-end: 1.2rem;
188
188
  }
189
189
 
190
- &__toggles {
190
+ .demo-controls__toggles {
191
191
  display: flex;
192
192
  flex-wrap: wrap;
193
193
  gap: 0.4rem 2.4rem;
194
194
  margin-block-end: 1.6rem;
195
195
  }
196
196
 
197
- &__selects {
197
+ .demo-controls__selects {
198
198
  display: flex;
199
199
  flex-direction: column;
200
200
  gap: 0.8rem;
@@ -413,7 +413,7 @@ const radiusData = ref<IFormMultipleOptions>({
413
413
  grid-template-columns: 1fr 2fr;
414
414
  }
415
415
 
416
- &__info {
416
+ & .sri-demo-row__info {
417
417
  position: sticky;
418
418
  top: 2.4rem;
419
419
  }
@@ -464,7 +464,7 @@ const radiusData = ref<IFormMultipleOptions>({
464
464
  border-radius: 0.8rem;
465
465
  margin-block: 2.4rem;
466
466
 
467
- &__heading {
467
+ & .demo-controls__heading {
468
468
  font-size: 1.1rem;
469
469
  font-weight: 600;
470
470
  text-transform: uppercase;
@@ -473,7 +473,7 @@ const radiusData = ref<IFormMultipleOptions>({
473
473
  margin-block-end: 1.2rem;
474
474
  }
475
475
 
476
- &__fields {
476
+ & .demo-controls__fields {
477
477
  display: flex;
478
478
  flex-direction: column;
479
479
  gap: 1.2rem;
@@ -6,11 +6,7 @@
6
6
  <h1 class="page-heading-3">Simple Grid</h1>
7
7
  <p class="page-body-normal">Simple grid displaying dummy posts data</p>
8
8
 
9
- <GridCore
10
- v-if="status === 'success'"
11
- :grid-data="postsData?.posts.slice(0, displayCount) ?? ({} as Posts)"
12
- :style-class-passthrough="['display-posts']"
13
- >
9
+ <LayoutGridByWidth v-if="status === 'success'" column-width="300px" gap="2rem">
14
10
  <template v-for="(item, index) in postsData?.posts.slice(0, displayCount)" :key="item.id" #[item.id]>
15
11
  <div class="display-post-item">
16
12
  <div>Views: {{ item.views }}</div>
@@ -18,7 +14,7 @@
18
14
  <div>{{ item.body }}</div>
19
15
  </div>
20
16
  </template>
21
- </GridCore>
17
+ </LayoutGridByWidth>
22
18
 
23
19
  <p v-else class="page-body-normal">&hellip;Loading</p>
24
20
  </PageRow>
@@ -47,20 +43,13 @@ const { data: postsData, status } = await useFetch<Posts>("https://dummyjson.com
47
43
  </script>
48
44
 
49
45
  <style lang="css">
50
- .display-posts {
46
+ .display-post-item {
51
47
  display: grid;
52
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
53
-
54
- gap: 2rem;
55
-
56
- .display-post-item {
57
- display: grid;
58
- grid-template-rows: subgrid;
59
- grid-row: span 3;
60
- gap: 1.2rem;
61
- outline: 0.1rem solid green;
62
- border-radius: 0.4rem;
63
- padding: 1.2rem;
64
- }
48
+ grid-template-rows: subgrid;
49
+ grid-row: span 3;
50
+ gap: 1.2rem;
51
+ outline: 0.1rem solid green;
52
+ border-radius: 0.4rem;
53
+ padding: 1.2rem;
65
54
  }
66
55
  </style>
@@ -6,7 +6,7 @@ export default defineNuxtModule({
6
6
  configKey: "colourScheme",
7
7
  },
8
8
  setup(_, nuxt) {
9
- const enabled = (nuxt.options.runtimeConfig.public?.colourScheme as { enabled?: boolean } | undefined)?.enabled ?? true;
9
+ const enabled = ((nuxt.options.runtimeConfig.public as Record<string, unknown>).colourScheme as { enabled?: boolean } | undefined)?.enabled ?? true;
10
10
 
11
11
  if (!enabled) return;
12
12
 
package/nuxt.config.ts CHANGED
@@ -109,15 +109,24 @@ export default defineNuxtConfig({
109
109
  // (avoids /_vercel/image which has no source images in storybook-static/)
110
110
  provider: process.env.STORYBOOK ? "none" : undefined,
111
111
  },
112
+ nitro: {
113
+ externals: {
114
+ // Nitro's dependency tracer only copies vue's CJS build but Node.js 22 (ESM)
115
+ // resolves the "import"+"node" export condition → ./index.mjs, which doesn't exist
116
+ // in the output. Inlining forces Nitro/Rollup to bundle Vue directly, avoiding the
117
+ // runtime resolution entirely.
118
+ inline: ["vue", "@vue/runtime-core", "@vue/runtime-dom", "@vue/reactivity", "@vue/shared", "@vue/server-renderer"],
119
+ },
120
+ },
112
121
  vite: {
113
122
  optimizeDeps: {
114
- include: ["@oddbird/css-anchor-positioning"],
123
+ include: ["@oddbird/css-anchor-positioning", "@vue/devtools-core", "@vue/devtools-kit", "vue-qrcode-reader"],
115
124
  },
116
125
  },
117
126
  vue: {
118
127
  runtimeCompiler: true,
119
128
  },
120
- compatibilityDate: "2026-01-30",
129
+ compatibilityDate: "2026-05-20",
121
130
  typescript: {
122
131
  includeWorkspace: true,
123
132
  strict: true,