@visns-studio/visns-components 6.32.0 → 6.32.2

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.
package/README.md CHANGED
@@ -9,6 +9,31 @@ A comprehensive React component library used by the VISNS Studio team for CRM an
9
9
 
10
10
  VISNS Components is a React-based UI component library that provides a set of reusable, consistent, and customizable components for building web applications. It includes components for authentication, data grids, forms, navigation, and more, designed to work seamlessly together.
11
11
 
12
+ ## Recent Updates (v6.32.2)
13
+
14
+ ### Boxed overview: no panel around the cards
15
+
16
+ Follow-up to 6.32.1. With every section drawn as its own card, the tab-body
17
+ panel around them was a card holding cards — a white frame with its own
18
+ border and shadow around five framed sections. In boxed mode the panel is now
19
+ transparent and the section cards sit directly on the page, flush with the
20
+ tab strip (CSS only: `.grid__subcontent:has(.gridtxt--boxed)` and
21
+ `.grid__full:has(.gridtxt--boxed)` drop their surface and padding). Plain
22
+ mode keeps its panel; nothing changes for apps that did not opt in.
23
+
24
+ ## Recent Updates (v6.32.1)
25
+
26
+ ### Boxed overview: one card per section, no note accent
27
+
28
+ Follow-up to 6.32.0's opt-in boxed overview. The tinted heading bar alone did
29
+ not separate sections once every field was a box, so in boxed mode each
30
+ section is now its own bordered card with its heading as the card's header
31
+ strip — Transport and PPE Requirement read as two things rather than one long
32
+ run of boxes. Note-shaped fields (Description, Comments) are ordinary fields
33
+ here too: the same neutral border as every other box, with no accent colour.
34
+ Plain mode renders byte-identical markup; nothing changes for apps that did
35
+ not opt in.
36
+
12
37
  ## Recent Updates (v6.32.0)
13
38
 
14
39
  ### The pre-6.15 boxed overview is back, as an opt-in
package/package.json CHANGED
@@ -93,7 +93,7 @@
93
93
  "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
94
94
  },
95
95
  "name": "@visns-studio/visns-components",
96
- "version": "6.32.0",
96
+ "version": "6.32.2",
97
97
  "description": "Various packages to assist in the development of our Custom Applications.",
98
98
  "main": "src/index.js",
99
99
  "files": [
@@ -300,6 +300,22 @@ function GenericDetail({
300
300
  const overviewStyle = resolveOverviewStyle(page?.overviewStyle);
301
301
  const overviewIsBoxed = overviewStyle === 'boxed';
302
302
 
303
+ /**
304
+ * How one overview section is wrapped.
305
+ *
306
+ * Boxed mode draws every section as its own card, so it needs a real
307
+ * element around the heading and the field list. Plain mode must NOT gain
308
+ * one: its rules are written as `.gridtxt > ul.customer__overview`, and a
309
+ * wrapper would stop the list being a direct child — so it keeps the
310
+ * `React.Fragment` it has always used and its markup is unchanged. A
311
+ * Fragment accepts `key` but nothing else, hence the separate props
312
+ * object rather than a className passed unconditionally.
313
+ */
314
+ const SectionWrap = overviewIsBoxed ? 'section' : React.Fragment;
315
+ const sectionWrapProps = overviewIsBoxed
316
+ ? { className: styles.gridtxt__section }
317
+ : {};
318
+
303
319
  /** Fileupload states */
304
320
  const [files, setFiles] = useState([]);
305
321
 
@@ -2940,8 +2956,9 @@ function GenericDetail({
2940
2956
  >
2941
2957
  {activeTabConfig.sections.map(
2942
2958
  (section, sectionIndex) => (
2943
- <React.Fragment
2959
+ <SectionWrap
2944
2960
  key={`section-${activeTabConfig.id}-${sectionIndex}`}
2961
+ {...sectionWrapProps}
2945
2962
  >
2946
2963
  <div
2947
2964
  className={
@@ -3154,7 +3171,7 @@ function GenericDetail({
3154
3171
  )}
3155
3172
  </ul>
3156
3173
  )}
3157
- </React.Fragment>
3174
+ </SectionWrap>
3158
3175
  )
3159
3176
  )}
3160
3177
  </div>
@@ -485,6 +485,28 @@
485
485
  `page.overviewStyle`), GenericDetail adds `.gridtxt--boxed`, and these
486
486
  rules put the 5.26 geometry back.
487
487
 
488
+ Each section is also its own card here, wrapped in `.gridtxt__section`.
489
+ The tinted heading bar on its own was enough to separate sections while the
490
+ fields below it were plain stacked pairs, but once every field is a tinted,
491
+ bordered box the bar reads as one more box in the run: bar, boxes, bar,
492
+ boxes, all inside a single panel, with nothing saying where Transport ends
493
+ and PPE Requirement begins. So the section gets a bordered card and the
494
+ heading becomes that card's header strip — square, full-bleed, hairline
495
+ underneath. Plain mode keeps emitting the header and the `<ul>` as direct
496
+ children of `.gridtxt` (the rules above depend on it), so every selector
497
+ below reaches through `> .gridtxt__section >` and only boxed markup has
498
+ one.
499
+
500
+ One thing from 5.26 is deliberately NOT restored: the red accent on a
501
+ `.notecolor` field. Description and Comments are ordinary fields here too,
502
+ and the brand red read as an error on a page with nothing wrong — the same
503
+ reasoning that removed it from the plain overview. There is no boxed
504
+ `.notecolor` rule below because there does not need to be: the generic
505
+ boxed `li` rule is `.gridtxt.gridtxt--boxed > .gridtxt__section >
506
+ ul.customer__overview li` (0,4,2) and the plain accent it has to beat is
507
+ `.gridtxt > ul .notecolor` (0,2,1), so a note field simply takes the same
508
+ neutral border and tint as every other box.
509
+
488
510
  Specificity is doing real work here. The rules being undone are
489
511
  `.gridtxt > ul.customer__overview li` above AND the bare `.overviewLabel` /
490
512
  `.gridtxt__header` in the 2026 pass at the bottom of the file, which win on
@@ -496,11 +518,62 @@
496
518
  this file: a bare var() for a token the host has not declared is invalid at
497
519
  computed-value time and the declaration is simply dropped. */
498
520
 
499
- /* The heading, back to a centred tinted bar. `display: flex` is kept so a
500
- section's optional `.gridtxt__meta` still renders; it is centred with the
501
- title rather than pushed to the far edge, since there is no edge to push to
502
- once the bar is tinted. */
503
- .gridtxt.gridtxt--boxed > .gridtxt__header {
521
+ /* The panel's own inset is dialled back once the sections are cards: the tab
522
+ card already pads, and `.gridtxt`'s 1rem/1.5rem on top of a card border on
523
+ top of the `<ul>`'s 0.85rem stacked three insets between the panel edge and
524
+ the first field. Zero: the panel around the boxed overview is transparent
525
+ (next rule), so the section cards ARE the surface and there is no panel
526
+ border to sit off. */
527
+ .gridtxt.gridtxt--boxed {
528
+ padding: 0;
529
+ }
530
+
531
+ /* The tab-body panel is a card (`card-surface`). Around a boxed overview that
532
+ is a card holding cards — a white frame with its own border and shadow drawn
533
+ around five framed sections — so the panel gives up its surface and the
534
+ section cards sit directly on the page. Same `:has()` device the DataGrid
535
+ repair below uses; `:has` is the only way this file can reach an ancestor
536
+ from the modifier the JSX sets on the overview. Plain mode never carries
537
+ `.gridtxt--boxed`, so it keeps its panel.
538
+
539
+ Both panels are named: `.grid__subcontent` is the tab-body column that
540
+ actually frames the overview in the stacked layout, and `.grid__full` is
541
+ the card the older rail layout and the stage-bar branch wrap it in. The
542
+ padding goes with the frame — with nothing drawn around them the cards
543
+ align to the tab strip's own edge — and overflow is released so the last
544
+ card's shadow is not clipped. */
545
+ .grid__subcontent:has(.gridtxt--boxed),
546
+ .grid__full:has(.gridtxt--boxed) {
547
+ background: transparent;
548
+ border: 0;
549
+ box-shadow: none;
550
+ border-radius: 0;
551
+ padding: 0;
552
+ overflow: visible;
553
+ }
554
+
555
+ /* One section, one card. `overflow: hidden` is what lets the square heading
556
+ strip below sit flush inside the rounded corners. */
557
+ .gridtxt.gridtxt--boxed > .gridtxt__section {
558
+ display: block;
559
+ box-sizing: border-box;
560
+ background: var(--surface-color, #fff);
561
+ border: 1px solid rgba(var(--primary-rgb, 27, 57, 51), 0.12);
562
+ border-radius: var(--br, 5px);
563
+ overflow: hidden;
564
+ margin: 0 0 var(--spacing-md, 1rem);
565
+ }
566
+
567
+ .gridtxt.gridtxt--boxed > .gridtxt__section:last-child {
568
+ margin-bottom: 0;
569
+ }
570
+
571
+ /* The heading, back to a centred tinted bar — and now the card's header
572
+ strip, so it runs the full width with square corners and a hairline under
573
+ it. `display: flex` is kept so a section's optional `.gridtxt__meta` still
574
+ renders; it is centred with the title rather than pushed to the far edge,
575
+ since there is no edge to push to once the bar is tinted. */
576
+ .gridtxt.gridtxt--boxed > .gridtxt__section > .gridtxt__header {
504
577
  width: 100%;
505
578
  display: flex;
506
579
  align-items: baseline;
@@ -509,8 +582,8 @@
509
582
  flex-wrap: wrap;
510
583
  box-sizing: border-box;
511
584
  padding: 10px 20px;
512
- border-bottom: 0;
513
- border-radius: var(--br, 5px);
585
+ border-bottom: 1px solid rgba(var(--primary-rgb, 27, 57, 51), 0.08);
586
+ border-radius: 0;
514
587
  margin-bottom: 0;
515
588
  background: rgba(var(--primary-rgb, 27, 57, 51), 0.05);
516
589
  font-size: var(--font-size-md, 0.9rem);
@@ -523,13 +596,13 @@
523
596
 
524
597
  /* The meta sits beside the centred title, not opposite it, so it needs its own
525
598
  small gap where the header's `space-between` used to provide one. */
526
- .gridtxt.gridtxt--boxed > .gridtxt__header > .gridtxt__meta {
599
+ .gridtxt.gridtxt--boxed > .gridtxt__section > .gridtxt__header > .gridtxt__meta {
527
600
  margin-left: var(--spacing-sm, 0.5rem);
528
601
  }
529
602
 
530
603
  /* A wrapping row of boxes, not a two-column grid: a full-width field can then
531
604
  sit between two half-width ones without leaving a hole in a grid track. */
532
- .gridtxt.gridtxt--boxed > ul.customer__overview {
605
+ .gridtxt.gridtxt--boxed > .gridtxt__section > ul.customer__overview {
533
606
  width: 100%;
534
607
  display: flex;
535
608
  justify-content: flex-start;
@@ -544,7 +617,7 @@
544
617
 
545
618
  /* The box itself. `display: block` is the whole point — the label and the
546
619
  value are inline text in one paragraph, not two stacked rows. */
547
- .gridtxt.gridtxt--boxed > ul.customer__overview li {
620
+ .gridtxt.gridtxt--boxed > .gridtxt__section > ul.customer__overview li {
548
621
  width: auto;
549
622
  flex: 0 0 calc(50% - 10px);
550
623
  min-width: 0;
@@ -560,16 +633,11 @@
560
633
  line-height: 1.45;
561
634
  }
562
635
 
563
- .gridtxt.gridtxt--boxed > ul.customer__overview .fw-grid-item {
636
+ .gridtxt.gridtxt--boxed > .gridtxt__section > ul.customer__overview .fw-grid-item {
564
637
  flex: 0 0 calc(100% - 10px);
565
638
  grid-column: auto;
566
639
  }
567
640
 
568
- /* The accent on a note-shaped field, as it was before 6.15. */
569
- .gridtxt.gridtxt--boxed > ul.customer__overview .notecolor {
570
- border: 1px solid var(--secondary-color, #b23c3c);
571
- }
572
-
573
641
  /* Run-in label: ordinary bold text with a colon after it, not the eyebrow the
574
642
  stacked layout wears. */
575
643
  .gridtxt--boxed .overviewLabel {
@@ -590,8 +658,8 @@
590
658
 
591
659
  /* One column on a phone — half of a narrow screen is not a readable box. */
592
660
  @media (max-width: 759px) {
593
- .gridtxt.gridtxt--boxed > ul.customer__overview li,
594
- .gridtxt.gridtxt--boxed > ul.customer__overview .fw-grid-item {
661
+ .gridtxt.gridtxt--boxed > .gridtxt__section > ul.customer__overview li,
662
+ .gridtxt.gridtxt--boxed > .gridtxt__section > ul.customer__overview .fw-grid-item {
595
663
  flex: 0 0 calc(100% - 10px);
596
664
  }
597
665
  }