@fpkit/acss 3.4.0 → 3.6.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 (44) hide show
  1. package/libs/index.cjs +5 -5
  2. package/libs/index.cjs.map +1 -1
  3. package/libs/index.css +1 -1
  4. package/libs/index.css.map +1 -1
  5. package/libs/index.d.cts +64 -13
  6. package/libs/index.d.ts +64 -13
  7. package/libs/index.js +4 -4
  8. package/libs/index.js.map +1 -1
  9. package/package.json +2 -2
  10. package/src/components/col/README.mdx +138 -9
  11. package/src/components/col/col.stories.tsx +1711 -2
  12. package/src/components/col/col.test.tsx +45 -0
  13. package/src/components/col/col.tsx +3 -1
  14. package/src/components/col/col.types.ts +18 -4
  15. package/src/components/row/row.tsx +9 -0
  16. package/src/components/row/row.types.ts +24 -7
  17. package/src/sass/_columns.scss +396 -81
  18. package/src/styles/index.css +515 -7
  19. package/src/styles/index.css.map +1 -1
  20. package/src/types/layout-primitives.ts +22 -2
  21. package/libs/components/alert/alert.min.min.css +0 -2
  22. package/libs/components/badge/badge.min.min.css +0 -2
  23. package/libs/components/box/box.min.min.css +0 -2
  24. package/libs/components/breadcrumbs/breadcrumb.min.min.css +0 -2
  25. package/libs/components/buttons/button.min.min.css +0 -2
  26. package/libs/components/cards/card-style.min.min.css +0 -2
  27. package/libs/components/cards/card.min.min.css +0 -2
  28. package/libs/components/cluster/cluster.min.min.css +0 -2
  29. package/libs/components/details/details.min.min.css +0 -2
  30. package/libs/components/dialog/dialog.min.min.css +0 -2
  31. package/libs/components/flexbox/flex.min.min.css +0 -2
  32. package/libs/components/form/form.min.min.css +0 -2
  33. package/libs/components/grid/grid.min.min.css +0 -2
  34. package/libs/components/icons/icon.min.min.css +0 -2
  35. package/libs/components/images/img.min.min.css +0 -2
  36. package/libs/components/layout/landmarks.min.min.css +0 -2
  37. package/libs/components/link/link.min.min.css +0 -2
  38. package/libs/components/list/list.min.min.css +0 -2
  39. package/libs/components/nav/nav.min.min.css +0 -2
  40. package/libs/components/progress/progress.min.min.css +0 -2
  41. package/libs/components/stack/stack.min.min.css +0 -2
  42. package/libs/components/styles/index.min.min.css +0 -2
  43. package/libs/components/tag/tag.min.min.css +0 -2
  44. package/libs/components/text-to-speech/text-to-speech.min.min.css +0 -2
@@ -18,8 +18,9 @@ const meta: Meta<typeof Col> = {
18
18
  argTypes: {
19
19
  span: {
20
20
  control: "select",
21
- options: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
22
- description: "Column span (1-12 columns)",
21
+ options: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, "flex"],
22
+ description:
23
+ "Column span (1-12 columns) or 'flex' for flex-grow behavior",
23
24
  },
24
25
  offset: {
25
26
  control: "select",
@@ -422,3 +423,1711 @@ export const ResponsiveGrid: Story = {
422
423
  },
423
424
  },
424
425
  };
426
+
427
+ /**
428
+ * Flex Column - Demonstrates flex-grow behavior to fill remaining space.
429
+ * Shows how flex columns differ from auto columns and adapt responsively.
430
+ */
431
+ export const FlexColumn: Story = {
432
+ render: () => (
433
+ <div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
434
+ {/* Flex vs Auto comparison */}
435
+ <div>
436
+ <h3 style={{ marginBottom: "0.5rem" }}>Flex vs Auto Comparison</h3>
437
+ <Row>
438
+ <Col span={3} style={colStyle}>
439
+ Fixed (25%)
440
+ </Col>
441
+ <Col
442
+ span="flex"
443
+ style={{
444
+ ...colStyle,
445
+ background: "#fef3c7",
446
+ borderColor: "#f59e0b",
447
+ }}
448
+ >
449
+ Flex (grows to fill 75%)
450
+ </Col>
451
+ </Row>
452
+ </div>
453
+
454
+ <div>
455
+ <Row>
456
+ <Col span={3} style={colStyle}>
457
+ Fixed (25%)
458
+ </Col>
459
+ <Col auto style={{ ...colStyle, background: "#e0e7ff" }}>
460
+ Auto (sizes to content)
461
+ </Col>
462
+ </Row>
463
+ </div>
464
+
465
+ {/* Multiple flex columns */}
466
+ <div>
467
+ <h3 style={{ marginBottom: "0.5rem" }}>
468
+ Multiple Flex Columns (Equal Distribution)
469
+ </h3>
470
+ <Row>
471
+ <Col span={2} style={colStyle}>
472
+ Fixed col-2
473
+ </Col>
474
+ <Col
475
+ span="flex"
476
+ style={{
477
+ ...colStyle,
478
+ background: "#fef3c7",
479
+ borderColor: "#f59e0b",
480
+ }}
481
+ >
482
+ Flex 1
483
+ </Col>
484
+ <Col
485
+ span="flex"
486
+ style={{
487
+ ...colStyle,
488
+ background: "#fef3c7",
489
+ borderColor: "#f59e0b",
490
+ }}
491
+ >
492
+ Flex 2
493
+ </Col>
494
+ </Row>
495
+ </div>
496
+
497
+ {/* Flex with auto */}
498
+ <div>
499
+ <h3 style={{ marginBottom: "0.5rem" }}>Flex + Auto Combination</h3>
500
+ <Row>
501
+ <Col auto style={{ ...colStyle, background: "#e0e7ff" }}>
502
+ Button
503
+ </Col>
504
+ <Col
505
+ span="flex"
506
+ style={{
507
+ ...colStyle,
508
+ background: "#fef3c7",
509
+ borderColor: "#f59e0b",
510
+ }}
511
+ >
512
+ Main Content (fills remaining)
513
+ </Col>
514
+ <Col auto style={{ ...colStyle, background: "#e0e7ff" }}>
515
+ Icon
516
+ </Col>
517
+ </Row>
518
+ </div>
519
+
520
+ {/* Complex layout */}
521
+ <div>
522
+ <h3 style={{ marginBottom: "0.5rem" }}>Complex Layout</h3>
523
+ <Row>
524
+ <Col span={2} style={colStyle}>
525
+ Sidebar
526
+ </Col>
527
+ <Col
528
+ span="flex"
529
+ style={{
530
+ ...colStyle,
531
+ background: "#fef3c7",
532
+ borderColor: "#f59e0b",
533
+ }}
534
+ >
535
+ Main Content (grows)
536
+ </Col>
537
+ <Col span={3} style={colStyle}>
538
+ Aside
539
+ </Col>
540
+ </Row>
541
+ </div>
542
+ </div>
543
+ ),
544
+ play: async ({ canvasElement, step }) => {
545
+ await step("Flex classes are applied correctly", async () => {
546
+ const flexElements = canvasElement.querySelectorAll(".col-flex");
547
+ expect(flexElements.length).toBeGreaterThan(0);
548
+ });
549
+
550
+ await step("Flex columns exist alongside fixed columns", async () => {
551
+ const rows = canvasElement.querySelectorAll(".col-row");
552
+ const firstRow = rows[0];
553
+ expect(firstRow.querySelector(".col-3")).toBeInTheDocument();
554
+ expect(firstRow.querySelector(".col-flex")).toBeInTheDocument();
555
+ });
556
+ },
557
+ parameters: {
558
+ docs: {
559
+ description: {
560
+ story:
561
+ "Flex columns use `flex-grow: 1` to fill remaining space after fixed-width columns. Multiple flex columns share space equally. On mobile (<768px), all columns stack to 100% width. Yellow background indicates flex columns, blue indicates fixed/auto columns.",
562
+ },
563
+ },
564
+ },
565
+ };
566
+
567
+ /**
568
+ * NEW: Responsive Utilities - Mobile-First Layout
569
+ * Demonstrates the new responsive column utilities (.col-sm-*, .col-md-*, .col-lg-*).
570
+ * Shows columns adapting across breakpoints: mobile (100%), tablet (50%), desktop (33.33%).
571
+ */
572
+ export const ResponsiveUtilities: Story = {
573
+ render: () => (
574
+ <div style={{ display: "flex", flexDirection: "column", gap: "2rem" }}>
575
+ <div>
576
+ <h3
577
+ style={{
578
+ marginBottom: "0.5rem",
579
+ fontSize: "1.125rem",
580
+ fontWeight: 600,
581
+ }}
582
+ >
583
+ Mobile-First Responsive Grid
584
+ </h3>
585
+ <p
586
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
587
+ >
588
+ Resize viewport: Mobile &lt;480px (stacked), Tablet ≥480px (2 cols),
589
+ Desktop ≥1024px (3 cols)
590
+ </p>
591
+ <Row>
592
+ <div className="col-12 col-sm-6 col-lg-4" style={colStyle}>
593
+ .col-12.col-sm-6.col-lg-4
594
+ </div>
595
+ <div className="col-12 col-sm-6 col-lg-4" style={colStyle}>
596
+ .col-12.col-sm-6.col-lg-4
597
+ </div>
598
+ <div className="col-12 col-sm-6 col-lg-4" style={colStyle}>
599
+ .col-12.col-sm-6.col-lg-4
600
+ </div>
601
+ <div className="col-12 col-sm-6 col-lg-4" style={colStyle}>
602
+ .col-12.col-sm-6.col-lg-4
603
+ </div>
604
+ <div className="col-12 col-sm-6 col-lg-4" style={colStyle}>
605
+ .col-12.col-sm-6.col-lg-4
606
+ </div>
607
+ <div className="col-12 col-sm-6 col-lg-4" style={colStyle}>
608
+ .col-12.col-sm-6.col-lg-4
609
+ </div>
610
+ </Row>
611
+ </div>
612
+
613
+ <div>
614
+ <h3
615
+ style={{
616
+ marginBottom: "0.5rem",
617
+ fontSize: "1.125rem",
618
+ fontWeight: 600,
619
+ }}
620
+ >
621
+ Different Widths Per Breakpoint
622
+ </h3>
623
+ <p
624
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
625
+ >
626
+ Mobile: full width | Tablet ≥480px: 3 cols | Desktop ≥1024px: 2 cols
627
+ </p>
628
+ <Row>
629
+ <div
630
+ className="col-12 col-sm-4 col-lg-6"
631
+ style={{ ...colStyle, background: "#fef3c7" }}
632
+ >
633
+ .col-12.col-sm-4.col-lg-6
634
+ </div>
635
+ <div
636
+ className="col-12 col-sm-4 col-lg-6"
637
+ style={{ ...colStyle, background: "#dbeafe" }}
638
+ >
639
+ .col-12.col-sm-4.col-lg-6
640
+ </div>
641
+ <div
642
+ className="col-12 col-sm-4 col-lg-12"
643
+ style={{ ...colStyle, background: "#fce7f3" }}
644
+ >
645
+ .col-12.col-sm-4.col-lg-12
646
+ </div>
647
+ </Row>
648
+ </div>
649
+
650
+ <div>
651
+ <h3
652
+ style={{
653
+ marginBottom: "0.5rem",
654
+ fontSize: "1.125rem",
655
+ fontWeight: 600,
656
+ }}
657
+ >
658
+ Sidebar Layout (Responsive)
659
+ </h3>
660
+ <p
661
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
662
+ >
663
+ Mobile: stacked | Tablet+: sidebar (25%) + main (75%)
664
+ </p>
665
+ <Row>
666
+ <div
667
+ className="col-12 col-md-3"
668
+ style={{ ...colStyle, background: "#e0e7ff" }}
669
+ >
670
+ Sidebar
671
+ <br />
672
+ .col-12.col-md-3
673
+ </div>
674
+ <div
675
+ className="col-12 col-md-9"
676
+ style={{ ...colStyle, background: "#fef3c7" }}
677
+ >
678
+ Main Content
679
+ <br />
680
+ .col-12.col-md-9
681
+ </div>
682
+ </Row>
683
+ </div>
684
+ </div>
685
+ ),
686
+ play: async ({ canvasElement, step }) => {
687
+ await step("Responsive utility classes are applied", async () => {
688
+ const sm6Elements = canvasElement.querySelectorAll(".col-sm-6");
689
+ expect(sm6Elements.length).toBeGreaterThan(0);
690
+
691
+ const lg4Elements = canvasElement.querySelectorAll(".col-lg-4");
692
+ expect(lg4Elements.length).toBeGreaterThan(0);
693
+
694
+ const md3Element = canvasElement.querySelector(".col-md-3");
695
+ expect(md3Element).toBeInTheDocument();
696
+ });
697
+ },
698
+ parameters: {
699
+ docs: {
700
+ description: {
701
+ story:
702
+ "NEW responsive utility classes enable mobile-first layouts. Use `.col-{breakpoint}-{span}` to control column widths at different screen sizes. Breakpoints: sm (≥480px), md (≥768px), lg (≥1024px). Classes cascade: smaller breakpoints apply unless overridden by larger ones.",
703
+ },
704
+ },
705
+ viewport: {
706
+ defaultViewport: "responsive",
707
+ },
708
+ },
709
+ };
710
+
711
+ /**
712
+ * NEW: Responsive Offsets - Centering and Positioning
713
+ * Demonstrates responsive offset utilities (.col-*-offset-*).
714
+ * Shows columns centering at different breakpoints.
715
+ */
716
+ export const ResponsiveOffsets: Story = {
717
+ render: () => (
718
+ <div style={{ display: "flex", flexDirection: "column", gap: "2rem" }}>
719
+ <div>
720
+ <h3
721
+ style={{
722
+ marginBottom: "0.5rem",
723
+ fontSize: "1.125rem",
724
+ fontWeight: 600,
725
+ }}
726
+ >
727
+ Responsive Centering
728
+ </h3>
729
+ <p
730
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
731
+ >
732
+ Mobile: full width | Tablet+: centered with offset
733
+ </p>
734
+ <Row>
735
+ <div
736
+ className="col-12 col-md-6 col-md-offset-3"
737
+ style={{ ...colStyle, background: "#dbeafe" }}
738
+ >
739
+ .col-12.col-md-6.col-md-offset-3
740
+ <br />
741
+ <small>Centered on tablet+</small>
742
+ </div>
743
+ </Row>
744
+ </div>
745
+
746
+ <div>
747
+ <h3
748
+ style={{
749
+ marginBottom: "0.5rem",
750
+ fontSize: "1.125rem",
751
+ fontWeight: 600,
752
+ }}
753
+ >
754
+ Different Offsets Per Breakpoint
755
+ </h3>
756
+ <p
757
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
758
+ >
759
+ Offset changes at different screen sizes
760
+ </p>
761
+ <Row>
762
+ <div
763
+ className="col-12 col-sm-6 col-sm-offset-0 col-lg-4 col-lg-offset-2"
764
+ style={{ ...colStyle, background: "#fef3c7" }}
765
+ >
766
+ .col-sm-6.col-sm-offset-0
767
+ <br />
768
+ .col-lg-4.col-lg-offset-2
769
+ </div>
770
+ <div
771
+ className="col-12 col-sm-6 col-sm-offset-0 col-lg-4 col-lg-offset-0"
772
+ style={{ ...colStyle, background: "#fce7f3" }}
773
+ >
774
+ .col-sm-6.col-sm-offset-0
775
+ <br />
776
+ .col-lg-4.col-lg-offset-0
777
+ </div>
778
+ </Row>
779
+ </div>
780
+
781
+ <div>
782
+ <h3
783
+ style={{
784
+ marginBottom: "0.5rem",
785
+ fontSize: "1.125rem",
786
+ fontWeight: 600,
787
+ }}
788
+ >
789
+ Push/Pull Layout
790
+ </h3>
791
+ <p
792
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
793
+ >
794
+ Create space between columns responsively
795
+ </p>
796
+ <Row>
797
+ <div className="col-12 col-md-4" style={colStyle}>
798
+ Left column
799
+ <br />
800
+ .col-md-4
801
+ </div>
802
+ <div
803
+ className="col-12 col-md-4 col-md-offset-4"
804
+ style={{ ...colStyle, background: "#e0e7ff" }}
805
+ >
806
+ Right column
807
+ <br />
808
+ .col-md-4.col-md-offset-4
809
+ <br />
810
+ <small>(4 column gap in middle)</small>
811
+ </div>
812
+ </Row>
813
+ </div>
814
+ </div>
815
+ ),
816
+ play: async ({ canvasElement, step }) => {
817
+ await step("Responsive offset classes are applied", async () => {
818
+ const mdOffset3 = canvasElement.querySelector(".col-md-offset-3");
819
+ expect(mdOffset3).toBeInTheDocument();
820
+
821
+ const lgOffset2 = canvasElement.querySelector(".col-lg-offset-2");
822
+ expect(lgOffset2).toBeInTheDocument();
823
+ });
824
+ },
825
+ parameters: {
826
+ docs: {
827
+ description: {
828
+ story:
829
+ "Responsive offsets enable different spacing at different breakpoints. Use `.col-{breakpoint}-offset-{0-11}` to push columns right with margin. Perfect for centering or creating responsive gaps between columns.",
830
+ },
831
+ },
832
+ },
833
+ };
834
+
835
+ /**
836
+ * NEW: Responsive Ordering - Visual Reordering
837
+ * Demonstrates responsive order utilities (.col-*-order-*).
838
+ * Shows columns reordering at different breakpoints.
839
+ */
840
+ export const ResponsiveOrdering: Story = {
841
+ render: () => (
842
+ <div style={{ display: "flex", flexDirection: "column", gap: "2rem" }}>
843
+ <div>
844
+ <h3
845
+ style={{
846
+ marginBottom: "0.5rem",
847
+ fontSize: "1.125rem",
848
+ fontWeight: 600,
849
+ }}
850
+ >
851
+ Reverse Order on Desktop
852
+ </h3>
853
+ <p
854
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
855
+ >
856
+ Mobile: 1-2-3 | Desktop ≥1024px: 3-2-1
857
+ </p>
858
+ <Row>
859
+ <div
860
+ className="col-12 col-lg-4 col-lg-order-3"
861
+ style={{ ...colStyle, background: "#dbeafe" }}
862
+ >
863
+ DOM: 1st
864
+ <br />
865
+ Mobile: 1st
866
+ <br />
867
+ Desktop: 3rd
868
+ </div>
869
+ <div
870
+ className="col-12 col-lg-4 col-lg-order-2"
871
+ style={{ ...colStyle, background: "#fef3c7" }}
872
+ >
873
+ DOM: 2nd
874
+ <br />
875
+ Mobile: 2nd
876
+ <br />
877
+ Desktop: 2nd
878
+ </div>
879
+ <div
880
+ className="col-12 col-lg-4 col-lg-order-1"
881
+ style={{ ...colStyle, background: "#fce7f3" }}
882
+ >
883
+ DOM: 3rd
884
+ <br />
885
+ Mobile: 3rd
886
+ <br />
887
+ Desktop: 1st
888
+ </div>
889
+ </Row>
890
+ </div>
891
+
892
+ <div>
893
+ <h3
894
+ style={{
895
+ marginBottom: "0.5rem",
896
+ fontSize: "1.125rem",
897
+ fontWeight: 600,
898
+ }}
899
+ >
900
+ Content Before/After Sidebar
901
+ </h3>
902
+ <p
903
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
904
+ >
905
+ Mobile: sidebar first | Tablet+: sidebar last
906
+ </p>
907
+ <Row>
908
+ <div
909
+ className="col-12 col-md-3 col-md-order-last"
910
+ style={{ ...colStyle, background: "#e0e7ff" }}
911
+ >
912
+ Sidebar
913
+ <br />
914
+ .col-md-order-last
915
+ <br />
916
+ <small>(First on mobile, last on tablet+)</small>
917
+ </div>
918
+ <div
919
+ className="col-12 col-md-9 col-md-order-first"
920
+ style={{ ...colStyle, background: "#fef3c7" }}
921
+ >
922
+ Main Content
923
+ <br />
924
+ .col-md-order-first
925
+ <br />
926
+ <small>(Second on mobile, first on tablet+)</small>
927
+ </div>
928
+ </Row>
929
+ </div>
930
+
931
+ <div
932
+ style={{
933
+ padding: "1rem",
934
+ background: "#fef3c7",
935
+ border: "1px solid #f59e0b",
936
+ borderRadius: "0.25rem",
937
+ marginTop: "1rem",
938
+ }}
939
+ >
940
+ <strong>⚠️ Accessibility Note:</strong> Visual order changes don't
941
+ affect DOM order. Screen readers and keyboard navigation follow DOM
942
+ order, not visual order. Use ordering sparingly and ensure content makes
943
+ sense in both orders.
944
+ </div>
945
+ </div>
946
+ ),
947
+ play: async ({ canvasElement, step }) => {
948
+ await step("Responsive order classes are applied", async () => {
949
+ const lgOrder1 = canvasElement.querySelector(".col-lg-order-1");
950
+ expect(lgOrder1).toBeInTheDocument();
951
+
952
+ const mdOrderLast = canvasElement.querySelector(".col-md-order-last");
953
+ expect(mdOrderLast).toBeInTheDocument();
954
+
955
+ const mdOrderFirst = canvasElement.querySelector(".col-md-order-first");
956
+ expect(mdOrderFirst).toBeInTheDocument();
957
+ });
958
+ },
959
+ parameters: {
960
+ docs: {
961
+ description: {
962
+ story:
963
+ "Responsive ordering changes visual column order at different breakpoints. Use `.col-{breakpoint}-order-{0-12}` for numeric ordering, or `.col-{breakpoint}-order-first/last` for edge positioning. Remember: this only affects visual order, not DOM/accessibility order.",
964
+ },
965
+ },
966
+ },
967
+ };
968
+
969
+ /**
970
+ * NEW: Migration from alwaysProportional (DEPRECATED)
971
+ * Shows how to migrate from the deprecated alwaysProportional prop to responsive utilities.
972
+ */
973
+ export const MigrationFromAlwaysProportional: Story = {
974
+ render: () => (
975
+ <div style={{ display: "flex", flexDirection: "column", gap: "2rem" }}>
976
+ <div
977
+ style={{
978
+ padding: "1rem",
979
+ background: "#fef3c7",
980
+ border: "1px solid #f59e0b",
981
+ borderRadius: "0.25rem",
982
+ }}
983
+ >
984
+ <strong>⚠️ Deprecation Notice:</strong> The{" "}
985
+ <code>alwaysProportional</code> prop is deprecated and will be removed
986
+ in v5.0.0. Use responsive utility classes instead for better control.
987
+ </div>
988
+
989
+ <div>
990
+ <h3
991
+ style={{
992
+ marginBottom: "0.5rem",
993
+ fontSize: "1.125rem",
994
+ fontWeight: 600,
995
+ }}
996
+ >
997
+ Before (Deprecated) ❌
998
+ </h3>
999
+ <p
1000
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1001
+ >
1002
+ <code>
1003
+ &lt;Row alwaysProportional&gt;&lt;Col span=&#123;6&#125;
1004
+ /&gt;&lt;/Row&gt;
1005
+ </code>
1006
+ </p>
1007
+ <Row alwaysProportional>
1008
+ <Col span={6} style={{ ...colStyle, opacity: 0.6 }}>
1009
+ Old approach: span prop
1010
+ </Col>
1011
+ <Col span={6} style={{ ...colStyle, opacity: 0.6 }}>
1012
+ Limited to one breakpoint
1013
+ </Col>
1014
+ </Row>
1015
+ </div>
1016
+
1017
+ <div>
1018
+ <h3
1019
+ style={{
1020
+ marginBottom: "0.5rem",
1021
+ fontSize: "1.125rem",
1022
+ fontWeight: 600,
1023
+ }}
1024
+ >
1025
+ After (Recommended) ✅
1026
+ </h3>
1027
+ <p
1028
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1029
+ >
1030
+ <code>&lt;Row&gt;&lt;div className="col-sm-6" /&gt;&lt;/Row&gt;</code>
1031
+ </p>
1032
+ <Row>
1033
+ <div className="col-12 col-sm-6" style={colStyle}>
1034
+ New approach: utility classes
1035
+ </div>
1036
+ <div className="col-12 col-sm-6" style={colStyle}>
1037
+ More control across breakpoints
1038
+ </div>
1039
+ </Row>
1040
+ </div>
1041
+
1042
+ <div>
1043
+ <h3
1044
+ style={{
1045
+ marginBottom: "0.5rem",
1046
+ fontSize: "1.125rem",
1047
+ fontWeight: 600,
1048
+ }}
1049
+ >
1050
+ Better: Multiple Breakpoints ✨
1051
+ </h3>
1052
+ <p
1053
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1054
+ >
1055
+ Stack on mobile, 2 cols on tablet, 3 cols on desktop
1056
+ </p>
1057
+ <Row>
1058
+ <div className="col-12 col-sm-6 col-lg-4" style={colStyle}>
1059
+ Full control at each breakpoint
1060
+ </div>
1061
+ <div className="col-12 col-sm-6 col-lg-4" style={colStyle}>
1062
+ Mobile-first approach
1063
+ </div>
1064
+ <div className="col-12 col-sm-6 col-lg-4" style={colStyle}>
1065
+ Professional responsive layouts
1066
+ </div>
1067
+ </Row>
1068
+ </div>
1069
+
1070
+ <div
1071
+ style={{
1072
+ padding: "1rem",
1073
+ background: "#e0e7ff",
1074
+ border: "1px solid #6366f1",
1075
+ borderRadius: "0.25rem",
1076
+ marginTop: "1rem",
1077
+ }}
1078
+ >
1079
+ <strong>💡 Pro Tip:</strong> You can still use Col component with
1080
+ className:
1081
+ <br />
1082
+ <code>
1083
+ &lt;Col span=&#123;12&#125; className="col-sm-6
1084
+ col-lg-4"&gt;Content&lt;/Col&gt;
1085
+ </code>
1086
+ </div>
1087
+ </div>
1088
+ ),
1089
+ play: async ({ canvasElement, step }) => {
1090
+ await step("Deprecated alwaysProportional still works", async () => {
1091
+ const proportionalRow = canvasElement.querySelector(
1092
+ ".col-row-proportional"
1093
+ );
1094
+ expect(proportionalRow).toBeInTheDocument();
1095
+ });
1096
+
1097
+ await step("Recommended responsive utilities work", async () => {
1098
+ const sm6Elements = canvasElement.querySelectorAll(".col-sm-6");
1099
+ expect(sm6Elements.length).toBeGreaterThan(0);
1100
+ });
1101
+ },
1102
+ parameters: {
1103
+ docs: {
1104
+ description: {
1105
+ story:
1106
+ "Migration guide from deprecated `alwaysProportional` prop to responsive utility classes. The new approach provides more flexibility with multiple breakpoints (sm/md/lg) and is easier to customize. Both approaches currently work, but responsive utilities are recommended for all new code.",
1107
+ },
1108
+ },
1109
+ },
1110
+ };
1111
+
1112
+ /**
1113
+ * NEW: Real-World Layout Patterns
1114
+ * Demonstrates common responsive UI patterns found in production applications.
1115
+ * Shows practical examples: dashboard, product grid, pricing table, blog layout.
1116
+ */
1117
+ export const RealWorldLayouts: Story = {
1118
+ render: () => (
1119
+ <div style={{ display: "flex", flexDirection: "column", gap: "3rem" }}>
1120
+ {/* Dashboard Layout */}
1121
+ <div>
1122
+ <h3
1123
+ style={{
1124
+ marginBottom: "0.5rem",
1125
+ fontSize: "1.125rem",
1126
+ fontWeight: 600,
1127
+ }}
1128
+ >
1129
+ Dashboard Layout
1130
+ </h3>
1131
+ <p
1132
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1133
+ >
1134
+ Mobile: stacked | Tablet: 2 cols | Desktop: 4 cols
1135
+ </p>
1136
+ <Row gap="md">
1137
+ <div
1138
+ className="col-12 col-sm-6 col-lg-3"
1139
+ style={{ ...colStyle, background: "#dbeafe" }}
1140
+ >
1141
+ <strong>Total Users</strong>
1142
+ <br />
1143
+ <div
1144
+ style={{
1145
+ fontSize: "2rem",
1146
+ fontWeight: "bold",
1147
+ margin: "0.5rem 0",
1148
+ }}
1149
+ >
1150
+ 1,234
1151
+ </div>
1152
+ <small>+12% from last month</small>
1153
+ </div>
1154
+ <div
1155
+ className="col-12 col-sm-6 col-lg-3"
1156
+ style={{ ...colStyle, background: "#fef3c7" }}
1157
+ >
1158
+ <strong>Revenue</strong>
1159
+ <br />
1160
+ <div
1161
+ style={{
1162
+ fontSize: "2rem",
1163
+ fontWeight: "bold",
1164
+ margin: "0.5rem 0",
1165
+ }}
1166
+ >
1167
+ $45.2K
1168
+ </div>
1169
+ <small>+8% from last month</small>
1170
+ </div>
1171
+ <div
1172
+ className="col-12 col-sm-6 col-lg-3"
1173
+ style={{ ...colStyle, background: "#fce7f3" }}
1174
+ >
1175
+ <strong>Conversions</strong>
1176
+ <br />
1177
+ <div
1178
+ style={{
1179
+ fontSize: "2rem",
1180
+ fontWeight: "bold",
1181
+ margin: "0.5rem 0",
1182
+ }}
1183
+ >
1184
+ 892
1185
+ </div>
1186
+ <small>+15% from last month</small>
1187
+ </div>
1188
+ <div
1189
+ className="col-12 col-sm-6 col-lg-3"
1190
+ style={{ ...colStyle, background: "#e0e7ff" }}
1191
+ >
1192
+ <strong>Bounce Rate</strong>
1193
+ <br />
1194
+ <div
1195
+ style={{
1196
+ fontSize: "2rem",
1197
+ fontWeight: "bold",
1198
+ margin: "0.5rem 0",
1199
+ }}
1200
+ >
1201
+ 34%
1202
+ </div>
1203
+ <small>-5% from last month</small>
1204
+ </div>
1205
+ </Row>
1206
+ </div>
1207
+
1208
+ {/* Product Grid */}
1209
+ <div>
1210
+ <h3
1211
+ style={{
1212
+ marginBottom: "0.5rem",
1213
+ fontSize: "1.125rem",
1214
+ fontWeight: 600,
1215
+ }}
1216
+ >
1217
+ Product Grid
1218
+ </h3>
1219
+ <p
1220
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1221
+ >
1222
+ Mobile: 1 col | Tablet: 2 cols | Desktop: 3 cols
1223
+ </p>
1224
+ <Row gap="lg">
1225
+ {[1, 2, 3, 4, 5, 6].map((item) => (
1226
+ <div
1227
+ key={item}
1228
+ className="col-12 col-sm-6 col-lg-4"
1229
+ style={colStyle}
1230
+ >
1231
+ <div
1232
+ style={{
1233
+ width: "100%",
1234
+ height: "150px",
1235
+ background: "#e5e7eb",
1236
+ borderRadius: "0.25rem",
1237
+ marginBottom: "0.5rem",
1238
+ }}
1239
+ />
1240
+ <strong>Product {item}</strong>
1241
+ <br />
1242
+ <small>$99.99</small>
1243
+ </div>
1244
+ ))}
1245
+ </Row>
1246
+ </div>
1247
+
1248
+ {/* Pricing Table */}
1249
+ <div>
1250
+ <h3
1251
+ style={{
1252
+ marginBottom: "0.5rem",
1253
+ fontSize: "1.125rem",
1254
+ fontWeight: 600,
1255
+ }}
1256
+ >
1257
+ Pricing Table
1258
+ </h3>
1259
+ <p
1260
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1261
+ >
1262
+ Mobile: stacked | Desktop: 3 equal columns
1263
+ </p>
1264
+ <Row gap="md">
1265
+ <div
1266
+ className="col-12 col-md-4"
1267
+ style={{ ...colStyle, background: "#f3f4f6" }}
1268
+ >
1269
+ <strong style={{ fontSize: "1.25rem" }}>Starter</strong>
1270
+ <br />
1271
+ <div
1272
+ style={{
1273
+ fontSize: "2.5rem",
1274
+ fontWeight: "bold",
1275
+ margin: "1rem 0",
1276
+ }}
1277
+ >
1278
+ $9
1279
+ </div>
1280
+ <ul
1281
+ style={{
1282
+ textAlign: "left",
1283
+ paddingLeft: "1.5rem",
1284
+ margin: "1rem 0",
1285
+ }}
1286
+ >
1287
+ <li>5 Projects</li>
1288
+ <li>10 GB Storage</li>
1289
+ <li>Email Support</li>
1290
+ </ul>
1291
+ </div>
1292
+ <div
1293
+ className="col-12 col-md-4"
1294
+ style={{ ...colStyle, background: "#6366f1", color: "white" }}
1295
+ >
1296
+ <strong style={{ fontSize: "1.25rem" }}>Pro ⭐</strong>
1297
+ <br />
1298
+ <div
1299
+ style={{
1300
+ fontSize: "2.5rem",
1301
+ fontWeight: "bold",
1302
+ margin: "1rem 0",
1303
+ }}
1304
+ >
1305
+ $29
1306
+ </div>
1307
+ <ul
1308
+ style={{
1309
+ textAlign: "left",
1310
+ paddingLeft: "1.5rem",
1311
+ margin: "1rem 0",
1312
+ }}
1313
+ >
1314
+ <li>Unlimited Projects</li>
1315
+ <li>100 GB Storage</li>
1316
+ <li>Priority Support</li>
1317
+ </ul>
1318
+ </div>
1319
+ <div
1320
+ className="col-12 col-md-4"
1321
+ style={{ ...colStyle, background: "#f3f4f6" }}
1322
+ >
1323
+ <strong style={{ fontSize: "1.25rem" }}>Enterprise</strong>
1324
+ <br />
1325
+ <div
1326
+ style={{
1327
+ fontSize: "2.5rem",
1328
+ fontWeight: "bold",
1329
+ margin: "1rem 0",
1330
+ }}
1331
+ >
1332
+ $99
1333
+ </div>
1334
+ <ul
1335
+ style={{
1336
+ textAlign: "left",
1337
+ paddingLeft: "1.5rem",
1338
+ margin: "1rem 0",
1339
+ }}
1340
+ >
1341
+ <li>Unlimited Everything</li>
1342
+ <li>1 TB Storage</li>
1343
+ <li>24/7 Phone Support</li>
1344
+ </ul>
1345
+ </div>
1346
+ </Row>
1347
+ </div>
1348
+
1349
+ {/* Blog Layout */}
1350
+ <div>
1351
+ <h3
1352
+ style={{
1353
+ marginBottom: "0.5rem",
1354
+ fontSize: "1.125rem",
1355
+ fontWeight: 600,
1356
+ }}
1357
+ >
1358
+ Blog Layout (Sidebar + Content)
1359
+ </h3>
1360
+ <p
1361
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1362
+ >
1363
+ Mobile: stacked (sidebar first) | Desktop: sidebar (25%) + content
1364
+ (75%)
1365
+ </p>
1366
+ <Row gap="lg">
1367
+ <div
1368
+ className="col-12 col-lg-3 col-lg-order-1"
1369
+ style={{ ...colStyle, background: "#e0e7ff" }}
1370
+ >
1371
+ <strong>Sidebar</strong>
1372
+ <br />
1373
+ <ul
1374
+ style={{
1375
+ textAlign: "left",
1376
+ paddingLeft: "1.5rem",
1377
+ marginTop: "0.5rem",
1378
+ }}
1379
+ >
1380
+ <li>Categories</li>
1381
+ <li>Recent Posts</li>
1382
+ <li>Archive</li>
1383
+ <li>Tags</li>
1384
+ </ul>
1385
+ </div>
1386
+ <div
1387
+ className="col-12 col-lg-9 col-lg-order-2"
1388
+ style={{ ...colStyle, background: "#fef3c7" }}
1389
+ >
1390
+ <strong style={{ fontSize: "1.5rem" }}>Article Title</strong>
1391
+ <br />
1392
+ <p style={{ margin: "1rem 0", textAlign: "left" }}>
1393
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mobile
1394
+ users see this content below the sidebar, while desktop users see
1395
+ it to the right of the sidebar.
1396
+ </p>
1397
+ </div>
1398
+ </Row>
1399
+ </div>
1400
+ </div>
1401
+ ),
1402
+ play: async ({ canvasElement, step }) => {
1403
+ await step("Dashboard uses 4-column responsive layout", async () => {
1404
+ const dashboardCols =
1405
+ canvasElement.querySelectorAll(".col-sm-6.col-lg-3");
1406
+ expect(dashboardCols.length).toBeGreaterThan(0);
1407
+ });
1408
+
1409
+ await step("Product grid uses 3-column responsive layout", async () => {
1410
+ const productCols = canvasElement.querySelectorAll(".col-sm-6.col-lg-4");
1411
+ expect(productCols.length).toBeGreaterThan(0);
1412
+ });
1413
+
1414
+ await step("Pricing table uses equal columns", async () => {
1415
+ const pricingCols = canvasElement.querySelectorAll(".col-md-4");
1416
+ expect(pricingCols.length).toBe(3);
1417
+ });
1418
+ },
1419
+ parameters: {
1420
+ docs: {
1421
+ description: {
1422
+ story:
1423
+ "Real-world responsive layout patterns commonly used in production applications. Includes dashboard stats, product grids, pricing tables, and blog layouts. Each pattern demonstrates mobile-first responsive design with appropriate breakpoints.",
1424
+ },
1425
+ },
1426
+ },
1427
+ };
1428
+
1429
+ /**
1430
+ * NEW: Hero Section Patterns
1431
+ * Demonstrates responsive hero section layouts with content and media.
1432
+ * Shows different approaches: centered, split, full-width with offset.
1433
+ */
1434
+ export const HeroSectionPatterns: Story = {
1435
+ render: () => (
1436
+ <div style={{ display: "flex", flexDirection: "column", gap: "3rem" }}>
1437
+ {/* Centered Hero */}
1438
+ <div>
1439
+ <h3
1440
+ style={{
1441
+ marginBottom: "0.5rem",
1442
+ fontSize: "1.125rem",
1443
+ fontWeight: 600,
1444
+ }}
1445
+ >
1446
+ Centered Hero
1447
+ </h3>
1448
+ <p
1449
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1450
+ >
1451
+ Mobile: full width | Desktop: centered with offset
1452
+ </p>
1453
+ <Row>
1454
+ <div
1455
+ className="col-12 col-md-8 col-md-offset-2 col-lg-6 col-lg-offset-3"
1456
+ style={{ ...colStyle, padding: "2rem" }}
1457
+ >
1458
+ <h1 style={{ fontSize: "2.5rem", marginBottom: "1rem" }}>
1459
+ Welcome to Our Product
1460
+ </h1>
1461
+ <p
1462
+ style={{
1463
+ fontSize: "1.125rem",
1464
+ marginBottom: "1.5rem",
1465
+ color: "#666",
1466
+ }}
1467
+ >
1468
+ Build amazing things with our platform. Start your free trial
1469
+ today.
1470
+ </p>
1471
+ <div
1472
+ style={{ display: "flex", gap: "1rem", justifyContent: "center" }}
1473
+ >
1474
+ <button style={{ padding: "0.75rem 1.5rem", fontSize: "1rem" }}>
1475
+ Get Started
1476
+ </button>
1477
+ <button style={{ padding: "0.75rem 1.5rem", fontSize: "1rem" }}>
1478
+ Learn More
1479
+ </button>
1480
+ </div>
1481
+ </div>
1482
+ </Row>
1483
+ </div>
1484
+
1485
+ {/* Split Hero (Image + Content) */}
1486
+ <div>
1487
+ <h3
1488
+ style={{
1489
+ marginBottom: "0.5rem",
1490
+ fontSize: "1.125rem",
1491
+ fontWeight: 600,
1492
+ }}
1493
+ >
1494
+ Split Hero (50/50)
1495
+ </h3>
1496
+ <p
1497
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1498
+ >
1499
+ Mobile: stacked | Desktop: side-by-side
1500
+ </p>
1501
+ <Row gap="lg" align="center">
1502
+ <div
1503
+ className="col-12 col-md-6"
1504
+ style={{ ...colStyle, background: "#dbeafe", padding: "2rem" }}
1505
+ >
1506
+ <h2 style={{ fontSize: "2rem", marginBottom: "1rem" }}>
1507
+ Beautiful Design
1508
+ </h2>
1509
+ <p
1510
+ style={{ fontSize: "1rem", marginBottom: "1rem", color: "#666" }}
1511
+ >
1512
+ Create stunning interfaces with our component library. Responsive,
1513
+ accessible, and customizable.
1514
+ </p>
1515
+ <button style={{ padding: "0.75rem 1.5rem" }}>View Features</button>
1516
+ </div>
1517
+ <div
1518
+ className="col-12 col-md-6"
1519
+ style={{
1520
+ ...colStyle,
1521
+ background: "#e5e7eb",
1522
+ height: "300px",
1523
+ display: "flex",
1524
+ alignItems: "center",
1525
+ justifyContent: "center",
1526
+ }}
1527
+ >
1528
+ <span style={{ fontSize: "4rem" }}>🖼️</span>
1529
+ </div>
1530
+ </Row>
1531
+ </div>
1532
+
1533
+ {/* Asymmetric Hero */}
1534
+ <div>
1535
+ <h3
1536
+ style={{
1537
+ marginBottom: "0.5rem",
1538
+ fontSize: "1.125rem",
1539
+ fontWeight: 600,
1540
+ }}
1541
+ >
1542
+ Asymmetric Hero (60/40)
1543
+ </h3>
1544
+ <p
1545
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1546
+ >
1547
+ Mobile: stacked | Desktop: 60% content, 40% image
1548
+ </p>
1549
+ <Row gap="lg" align="center">
1550
+ <div
1551
+ className="col-12 col-lg-7"
1552
+ style={{ ...colStyle, background: "#fef3c7", padding: "2rem" }}
1553
+ >
1554
+ <h2 style={{ fontSize: "2rem", marginBottom: "1rem" }}>
1555
+ Enterprise Solutions
1556
+ </h2>
1557
+ <p
1558
+ style={{ fontSize: "1rem", marginBottom: "1rem", color: "#666" }}
1559
+ >
1560
+ Powerful tools for teams of all sizes. Scalable infrastructure,
1561
+ advanced security, and dedicated support.
1562
+ </p>
1563
+ <ul style={{ textAlign: "left", marginBottom: "1rem" }}>
1564
+ <li>99.9% Uptime SLA</li>
1565
+ <li>Advanced Analytics</li>
1566
+ <li>Priority Support</li>
1567
+ </ul>
1568
+ <button style={{ padding: "0.75rem 1.5rem" }}>Contact Sales</button>
1569
+ </div>
1570
+ <div
1571
+ className="col-12 col-lg-5"
1572
+ style={{
1573
+ ...colStyle,
1574
+ background: "#e5e7eb",
1575
+ height: "350px",
1576
+ display: "flex",
1577
+ alignItems: "center",
1578
+ justifyContent: "center",
1579
+ }}
1580
+ >
1581
+ <span style={{ fontSize: "5rem" }}>📊</span>
1582
+ </div>
1583
+ </Row>
1584
+ </div>
1585
+ </div>
1586
+ ),
1587
+ play: async ({ canvasElement, step }) => {
1588
+ await step("Centered hero uses responsive offset", async () => {
1589
+ const centeredHero = canvasElement.querySelector(
1590
+ ".col-md-offset-2.col-lg-offset-3"
1591
+ );
1592
+ expect(centeredHero).toBeInTheDocument();
1593
+ });
1594
+
1595
+ await step("Split hero uses equal columns on desktop", async () => {
1596
+ const splitCols = canvasElement.querySelectorAll(".col-md-6");
1597
+ expect(splitCols.length).toBeGreaterThan(0);
1598
+ });
1599
+
1600
+ await step("Asymmetric hero uses 60/40 split", async () => {
1601
+ const col7 = canvasElement.querySelector(".col-lg-7");
1602
+ const col5 = canvasElement.querySelector(".col-lg-5");
1603
+ expect(col7).toBeInTheDocument();
1604
+ expect(col5).toBeInTheDocument();
1605
+ });
1606
+ },
1607
+ parameters: {
1608
+ docs: {
1609
+ description: {
1610
+ story:
1611
+ "Common hero section patterns for landing pages and marketing sites. Includes centered heroes with responsive offsets, 50/50 split layouts, and asymmetric layouts. All patterns stack on mobile and display side-by-side on larger screens.",
1612
+ },
1613
+ },
1614
+ },
1615
+ };
1616
+
1617
+ /**
1618
+ * NEW: Complex Responsive Combinations
1619
+ * Demonstrates advanced patterns combining spans, offsets, and ordering.
1620
+ * Shows how to create sophisticated layouts with multiple responsive features.
1621
+ */
1622
+ export const ComplexResponsiveCombinations: Story = {
1623
+ render: () => (
1624
+ <div style={{ display: "flex", flexDirection: "column", gap: "3rem" }}>
1625
+ {/* Responsive Grid with Visual Reordering */}
1626
+ <div>
1627
+ <h3
1628
+ style={{
1629
+ marginBottom: "0.5rem",
1630
+ fontSize: "1.125rem",
1631
+ fontWeight: 600,
1632
+ }}
1633
+ >
1634
+ Content Priority Reordering
1635
+ </h3>
1636
+ <p
1637
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1638
+ >
1639
+ Mobile: Primary content first | Desktop: Image first (visual order
1640
+ change)
1641
+ </p>
1642
+ <Row gap="lg">
1643
+ <div
1644
+ className="col-12 col-md-6 col-md-order-2"
1645
+ style={{ ...colStyle, background: "#dbeafe" }}
1646
+ >
1647
+ <strong>Primary Content</strong>
1648
+ <br />
1649
+ <p style={{ margin: "0.5rem 0", textAlign: "left" }}>
1650
+ On mobile, users see this content first because it's higher in the
1651
+ DOM. On desktop, it appears second (right side) due to visual
1652
+ ordering.
1653
+ </p>
1654
+ </div>
1655
+ <div
1656
+ className="col-12 col-md-6 col-md-order-1"
1657
+ style={{
1658
+ ...colStyle,
1659
+ background: "#e5e7eb",
1660
+ height: "200px",
1661
+ display: "flex",
1662
+ alignItems: "center",
1663
+ justifyContent: "center",
1664
+ }}
1665
+ >
1666
+ <span style={{ fontSize: "3rem" }}>📷</span>
1667
+ <br />
1668
+ <small>Image (visual first on desktop)</small>
1669
+ </div>
1670
+ </Row>
1671
+ </div>
1672
+
1673
+ {/* Changing Column Widths AND Offsets */}
1674
+ <div>
1675
+ <h3
1676
+ style={{
1677
+ marginBottom: "0.5rem",
1678
+ fontSize: "1.125rem",
1679
+ fontWeight: 600,
1680
+ }}
1681
+ >
1682
+ Dynamic Widths + Offsets
1683
+ </h3>
1684
+ <p
1685
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1686
+ >
1687
+ Tablet: 2 cols centered | Desktop: 3 cols left-aligned
1688
+ </p>
1689
+ <Row gap="md">
1690
+ <div
1691
+ className="col-12 col-md-5 col-md-offset-1 col-lg-4 col-lg-offset-0"
1692
+ style={{ ...colStyle, background: "#fef3c7" }}
1693
+ >
1694
+ <strong>.col-md-5.col-md-offset-1</strong>
1695
+ <br />
1696
+ <strong>.col-lg-4.col-lg-offset-0</strong>
1697
+ <br />
1698
+ <small>Centered on tablet, left-aligned on desktop</small>
1699
+ </div>
1700
+ <div
1701
+ className="col-12 col-md-5 col-md-offset-0 col-lg-4 col-lg-offset-0"
1702
+ style={{ ...colStyle, background: "#fce7f3" }}
1703
+ >
1704
+ <strong>.col-md-5.col-lg-4</strong>
1705
+ <br />
1706
+ <small>Width changes across breakpoints</small>
1707
+ </div>
1708
+ <div
1709
+ className="col-12 col-md-10 col-md-offset-1 col-lg-4 col-lg-offset-0"
1710
+ style={{ ...colStyle, background: "#dbeafe" }}
1711
+ >
1712
+ <strong>.col-md-10.col-md-offset-1</strong>
1713
+ <br />
1714
+ <strong>.col-lg-4.col-lg-offset-0</strong>
1715
+ <br />
1716
+ <small>Full row centered on tablet, third of row on desktop</small>
1717
+ </div>
1718
+ </Row>
1719
+ </div>
1720
+
1721
+ {/* Magazine-Style Layout */}
1722
+ <div>
1723
+ <h3
1724
+ style={{
1725
+ marginBottom: "0.5rem",
1726
+ fontSize: "1.125rem",
1727
+ fontWeight: 600,
1728
+ }}
1729
+ >
1730
+ Magazine-Style Layout
1731
+ </h3>
1732
+ <p
1733
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1734
+ >
1735
+ Mobile: stacked | Desktop: featured + grid
1736
+ </p>
1737
+ <Row gap="lg">
1738
+ <div
1739
+ className="col-12 col-lg-8"
1740
+ style={{
1741
+ ...colStyle,
1742
+ background: "#6366f1",
1743
+ color: "white",
1744
+ padding: "2rem",
1745
+ minHeight: "300px",
1746
+ }}
1747
+ >
1748
+ <h2 style={{ fontSize: "2rem", marginBottom: "1rem" }}>
1749
+ Featured Article
1750
+ </h2>
1751
+ <p>Large featured content area on desktop, full width on mobile</p>
1752
+ </div>
1753
+ <div
1754
+ className="col-12 col-sm-6 col-lg-4"
1755
+ style={{ ...colStyle, background: "#fef3c7" }}
1756
+ >
1757
+ <strong>Sidebar Item 1</strong>
1758
+ <br />
1759
+ <small>Half width on tablet, quarter on desktop</small>
1760
+ </div>
1761
+ <div
1762
+ className="col-12 col-sm-6 col-lg-4"
1763
+ style={{ ...colStyle, background: "#fce7f3" }}
1764
+ >
1765
+ <strong>Article 2</strong>
1766
+ </div>
1767
+ <div
1768
+ className="col-12 col-sm-6 col-lg-4"
1769
+ style={{ ...colStyle, background: "#dbeafe" }}
1770
+ >
1771
+ <strong>Article 3</strong>
1772
+ </div>
1773
+ <div
1774
+ className="col-12 col-sm-6 col-lg-4"
1775
+ style={{ ...colStyle, background: "#e0e7ff" }}
1776
+ >
1777
+ <strong>Article 4</strong>
1778
+ </div>
1779
+ </Row>
1780
+ </div>
1781
+
1782
+ {/* Responsive Gap Pattern */}
1783
+ <div>
1784
+ <h3
1785
+ style={{
1786
+ marginBottom: "0.5rem",
1787
+ fontSize: "1.125rem",
1788
+ fontWeight: 600,
1789
+ }}
1790
+ >
1791
+ Form Layout with Responsive Grouping
1792
+ </h3>
1793
+ <p
1794
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1795
+ >
1796
+ Mobile: stacked | Tablet: 2 cols | Desktop: mixed widths
1797
+ </p>
1798
+ <Row gap="md">
1799
+ <div className="col-12 col-md-6" style={colStyle}>
1800
+ <label
1801
+ style={{
1802
+ display: "block",
1803
+ marginBottom: "0.25rem",
1804
+ fontWeight: 600,
1805
+ }}
1806
+ >
1807
+ First Name
1808
+ </label>
1809
+ <input type="text" style={{ width: "100%", padding: "0.5rem" }} />
1810
+ </div>
1811
+ <div className="col-12 col-md-6" style={colStyle}>
1812
+ <label
1813
+ style={{
1814
+ display: "block",
1815
+ marginBottom: "0.25rem",
1816
+ fontWeight: 600,
1817
+ }}
1818
+ >
1819
+ Last Name
1820
+ </label>
1821
+ <input type="text" style={{ width: "100%", padding: "0.5rem" }} />
1822
+ </div>
1823
+ <div className="col-12" style={colStyle}>
1824
+ <label
1825
+ style={{
1826
+ display: "block",
1827
+ marginBottom: "0.25rem",
1828
+ fontWeight: 600,
1829
+ }}
1830
+ >
1831
+ Email
1832
+ </label>
1833
+ <input type="email" style={{ width: "100%", padding: "0.5rem" }} />
1834
+ </div>
1835
+ <div className="col-12 col-md-8" style={colStyle}>
1836
+ <label
1837
+ style={{
1838
+ display: "block",
1839
+ marginBottom: "0.25rem",
1840
+ fontWeight: 600,
1841
+ }}
1842
+ >
1843
+ Street Address
1844
+ </label>
1845
+ <input type="text" style={{ width: "100%", padding: "0.5rem" }} />
1846
+ </div>
1847
+ <div className="col-12 col-md-4" style={colStyle}>
1848
+ <label
1849
+ style={{
1850
+ display: "block",
1851
+ marginBottom: "0.25rem",
1852
+ fontWeight: 600,
1853
+ }}
1854
+ >
1855
+ ZIP Code
1856
+ </label>
1857
+ <input type="text" style={{ width: "100%", padding: "0.5rem" }} />
1858
+ </div>
1859
+ </Row>
1860
+ </div>
1861
+ </div>
1862
+ ),
1863
+ play: async ({ canvasElement, step }) => {
1864
+ await step("Content reordering works across breakpoints", async () => {
1865
+ const orderedCol = canvasElement.querySelector(".col-md-order-2");
1866
+ expect(orderedCol).toBeInTheDocument();
1867
+ });
1868
+
1869
+ await step("Dynamic offsets are applied correctly", async () => {
1870
+ const offsetCol = canvasElement.querySelector(
1871
+ ".col-md-offset-1.col-lg-offset-0"
1872
+ );
1873
+ expect(offsetCol).toBeInTheDocument();
1874
+ });
1875
+
1876
+ await step("Magazine layout uses 8-column featured area", async () => {
1877
+ const featured = canvasElement.querySelector(".col-lg-8");
1878
+ expect(featured).toBeInTheDocument();
1879
+ });
1880
+ },
1881
+ parameters: {
1882
+ docs: {
1883
+ description: {
1884
+ story:
1885
+ "Advanced responsive patterns combining multiple features: spans + offsets + ordering. Demonstrates magazine layouts, form grouping, content priority reordering, and complex responsive behaviors. These patterns show how responsive utilities enable sophisticated designs without media queries in your components.",
1886
+ },
1887
+ },
1888
+ },
1889
+ };
1890
+
1891
+ /**
1892
+ * NEW: Responsive with Row Props
1893
+ * Demonstrates combining responsive column utilities with Row component props.
1894
+ * Shows how gap, justify, and align props work with responsive layouts.
1895
+ */
1896
+ export const ResponsiveWithRowProps: Story = {
1897
+ render: () => (
1898
+ <div style={{ display: "flex", flexDirection: "column", gap: "3rem" }}>
1899
+ {/* Responsive Gap */}
1900
+ <div>
1901
+ <h3
1902
+ style={{
1903
+ marginBottom: "0.5rem",
1904
+ fontSize: "1.125rem",
1905
+ fontWeight: 600,
1906
+ }}
1907
+ >
1908
+ Custom Gap Spacing
1909
+ </h3>
1910
+ <p
1911
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1912
+ >
1913
+ Large gap between columns (mobile stacks, desktop side-by-side)
1914
+ </p>
1915
+ <Row gap="xl">
1916
+ <div className="col-12 col-md-6" style={colStyle}>
1917
+ Column with xl gap
1918
+ </div>
1919
+ <div className="col-12 col-md-6" style={colStyle}>
1920
+ Column with xl gap
1921
+ </div>
1922
+ </Row>
1923
+ </div>
1924
+
1925
+ <div>
1926
+ <h3
1927
+ style={{
1928
+ marginBottom: "0.5rem",
1929
+ fontSize: "1.125rem",
1930
+ fontWeight: 600,
1931
+ }}
1932
+ >
1933
+ Compact Gap
1934
+ </h3>
1935
+ <p
1936
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1937
+ >
1938
+ Minimal gap for dense layouts
1939
+ </p>
1940
+ <Row gap="xs">
1941
+ {[1, 2, 3, 4].map((item) => (
1942
+ <div
1943
+ key={item}
1944
+ className="col-12 col-sm-6 col-lg-3"
1945
+ style={colStyle}
1946
+ >
1947
+ Compact {item}
1948
+ </div>
1949
+ ))}
1950
+ </Row>
1951
+ </div>
1952
+
1953
+ {/* Centered Content */}
1954
+ <div>
1955
+ <h3
1956
+ style={{
1957
+ marginBottom: "0.5rem",
1958
+ fontSize: "1.125rem",
1959
+ fontWeight: 600,
1960
+ }}
1961
+ >
1962
+ Centered Columns (justify="center")
1963
+ </h3>
1964
+ <p
1965
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1966
+ >
1967
+ Columns centered horizontally when they don't fill full width
1968
+ </p>
1969
+ <Row justify="center" gap="md">
1970
+ <div className="col-auto col-md-3" style={colStyle}>
1971
+ Auto width
1972
+ </div>
1973
+ <div className="col-auto col-md-3" style={colStyle}>
1974
+ Centered
1975
+ </div>
1976
+ <div className="col-auto col-md-3" style={colStyle}>
1977
+ Content
1978
+ </div>
1979
+ </Row>
1980
+ </div>
1981
+
1982
+ {/* Space Between */}
1983
+ <div>
1984
+ <h3
1985
+ style={{
1986
+ marginBottom: "0.5rem",
1987
+ fontSize: "1.125rem",
1988
+ fontWeight: 600,
1989
+ }}
1990
+ >
1991
+ Spaced Columns (justify="between")
1992
+ </h3>
1993
+ <p
1994
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
1995
+ >
1996
+ Maximum space between columns
1997
+ </p>
1998
+ <Row justify="between" gap="0">
1999
+ <div className="col-auto col-md-3" style={colStyle}>
2000
+ Left
2001
+ </div>
2002
+ <div className="col-auto col-md-3" style={colStyle}>
2003
+ Center
2004
+ </div>
2005
+ <div className="col-auto col-md-3" style={colStyle}>
2006
+ Right
2007
+ </div>
2008
+ </Row>
2009
+ </div>
2010
+
2011
+ {/* Vertical Alignment */}
2012
+ <div>
2013
+ <h3
2014
+ style={{
2015
+ marginBottom: "0.5rem",
2016
+ fontSize: "1.125rem",
2017
+ fontWeight: 600,
2018
+ }}
2019
+ >
2020
+ Vertical Alignment (align="center")
2021
+ </h3>
2022
+ <p
2023
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
2024
+ >
2025
+ Columns with different heights vertically centered
2026
+ </p>
2027
+ <Row align="center" gap="md">
2028
+ <div
2029
+ className="col-12 col-md-4"
2030
+ style={{ ...colStyle, minHeight: "100px" }}
2031
+ >
2032
+ Short content
2033
+ </div>
2034
+ <div
2035
+ className="col-12 col-md-4"
2036
+ style={{ ...colStyle, minHeight: "200px" }}
2037
+ >
2038
+ Tall content
2039
+ <br />
2040
+ with
2041
+ <br />
2042
+ multiple
2043
+ <br />
2044
+ lines
2045
+ </div>
2046
+ <div
2047
+ className="col-12 col-md-4"
2048
+ style={{ ...colStyle, minHeight: "150px" }}
2049
+ >
2050
+ Medium content
2051
+ <br />
2052
+ vertically centered
2053
+ </div>
2054
+ </Row>
2055
+ </div>
2056
+
2057
+ {/* Flex Column with Row Props */}
2058
+ <div>
2059
+ <h3
2060
+ style={{
2061
+ marginBottom: "0.5rem",
2062
+ fontSize: "1.125rem",
2063
+ fontWeight: 600,
2064
+ }}
2065
+ >
2066
+ Flex Columns with Alignment
2067
+ </h3>
2068
+ <p
2069
+ style={{ marginBottom: "1rem", fontSize: "0.875rem", color: "#666" }}
2070
+ >
2071
+ Flex-grow columns combined with justify and align
2072
+ </p>
2073
+ <Row justify="between" align="center" gap="md">
2074
+ <div className="col-auto col-md-3" style={colStyle}>
2075
+ Fixed width
2076
+ </div>
2077
+ <div
2078
+ className="col-12 col-md-flex"
2079
+ style={{
2080
+ ...colStyle,
2081
+ background: "#fef3c7",
2082
+ borderColor: "#f59e0b",
2083
+ }}
2084
+ >
2085
+ Flex-grow (fills remaining space)
2086
+ </div>
2087
+ <div className="col-auto col-md-auto" style={colStyle}>
2088
+ Auto width
2089
+ </div>
2090
+ </Row>
2091
+ </div>
2092
+ </div>
2093
+ ),
2094
+ play: async ({ canvasElement, step }) => {
2095
+ await step("Row gap utilities are applied", async () => {
2096
+ const xlGapRow = canvasElement.querySelector(".col-row-gap-xl");
2097
+ expect(xlGapRow).toBeInTheDocument();
2098
+
2099
+ const xsGapRow = canvasElement.querySelector(".col-row-gap-xs");
2100
+ expect(xsGapRow).toBeInTheDocument();
2101
+ });
2102
+
2103
+ await step("Row justify utilities are applied", async () => {
2104
+ const centerRow = canvasElement.querySelector(".col-row-justify-center");
2105
+ expect(centerRow).toBeInTheDocument();
2106
+
2107
+ const betweenRow = canvasElement.querySelector(
2108
+ ".col-row-justify-between"
2109
+ );
2110
+ expect(betweenRow).toBeInTheDocument();
2111
+ });
2112
+
2113
+ await step("Row align utilities are applied", async () => {
2114
+ const alignCenterRow = canvasElement.querySelector(
2115
+ ".col-row-align-center"
2116
+ );
2117
+ expect(alignCenterRow).toBeInTheDocument();
2118
+ });
2119
+
2120
+ await step("Flex columns work with Row props", async () => {
2121
+ const flexCol = canvasElement.querySelector(".col-md-flex");
2122
+ expect(flexCol).toBeInTheDocument();
2123
+ });
2124
+ },
2125
+ parameters: {
2126
+ docs: {
2127
+ description: {
2128
+ story:
2129
+ "Demonstrates combining responsive column utilities with Row component props (gap, justify, align). Shows how to control spacing, horizontal alignment, and vertical alignment while maintaining responsive behavior. Flex columns can be combined with Row props for sophisticated layouts.",
2130
+ },
2131
+ },
2132
+ },
2133
+ };