@jungherz-de/glasskit 1.20.0 → 1.21.1

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/glasskit.css CHANGED
@@ -1,11 +1,12 @@
1
1
  /* ============================================================
2
2
  GLASSKIT COMPONENT LIBRARY
3
- Jungherz GmbH – v1.20.0
3
+ Jungherz GmbH – v1.21.1
4
4
 
5
5
  Features:
6
6
  - Scoped Reset (box-sizing fix)
7
7
  - Dark Mode (default)
8
8
  - Light Mode via [data-theme="light"]
9
+ - Compact density via [data-density="compact"]
9
10
  - 34 components (incl. floating Tab-Bar variant + Accessory)
10
11
  ============================================================ */
11
12
 
@@ -200,6 +201,29 @@
200
201
  --gl-space-3xl: 40px;
201
202
  --gl-space-4xl: 56px;
202
203
 
204
+ /* ---- Density: control sizes ----
205
+ The sizes GlassKit has always drawn its controls at, as tokens; the
206
+ rules read them with that value as fallback, like --gl-modal-max-width.
207
+ [data-density="compact"] (1c below) swaps in a denser set. The toggle's
208
+ thumb inset and travel and the first-line alignment of toggle, checkbox
209
+ and radio are derived from these, so any value set here stays aligned.
210
+ Two more are left unset on purpose, like --gl-toast-top:
211
+ --gl-control-padding-x (inner left and right of input, select and
212
+ textarea) and --gl-list-item-padding-y. Unset, the rules fall back to
213
+ --gl-space-md as before, so a spacing override still reaches them
214
+ wherever it is declared. */
215
+ --gl-control-height: 52px; /* input, select */
216
+ --gl-btn-height: 56px;
217
+ --gl-btn-height-sm: 44px;
218
+ --gl-btn-height-lg: 64px;
219
+ --gl-textarea-min-height: 120px;
220
+ --gl-list-item-min-height: 56px;
221
+ --gl-toggle-width: 52px;
222
+ --gl-toggle-height: 30px;
223
+ --gl-toggle-thumb-size: 22px;
224
+ --gl-check-size: 24px; /* checkbox, radio */
225
+ --gl-modal-action-height: 52px;
226
+
203
227
  /* ---- Typography ---- */
204
228
  --gl-font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display',
205
229
  'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
@@ -352,6 +376,37 @@
352
376
  }
353
377
 
354
378
 
379
+ /* ============================================================
380
+ 1c. DESIGN TOKENS – COMPACT DENSITY
381
+ ============================================================ */
382
+ /* Opt-in, next to the theme: <html data-density="compact">. Fields and
383
+ buttons at 40px instead of 52 and 56, smaller toggles and boxes, denser
384
+ list rows — for admin screens, desktop layouts and narrow forms. Only
385
+ the density tokens change; colours, type and spacing stay as they are.
386
+
387
+ A bare attribute selector, like [data-theme="light"]: it matches <html>,
388
+ and a theme wrapper that carries the attribute in a shadow root that
389
+ adopts the full sheet. build-styles-js.mjs moves it into tokensCss with
390
+ the theme blocks. It stays after them: the dark one declares the
391
+ defaults with the same specificity, and where both match, the later
392
+ block wins. */
393
+ [data-density="compact"] {
394
+ --gl-control-height: 40px;
395
+ --gl-control-padding-x: var(--gl-space-sm);
396
+ --gl-btn-height: 40px;
397
+ --gl-btn-height-sm: 32px;
398
+ --gl-btn-height-lg: 48px;
399
+ --gl-textarea-min-height: 88px;
400
+ --gl-list-item-min-height: 48px;
401
+ --gl-list-item-padding-y: 10px;
402
+ --gl-toggle-width: 44px;
403
+ --gl-toggle-height: 26px;
404
+ --gl-toggle-thumb-size: 18px;
405
+ --gl-check-size: 20px;
406
+ --gl-modal-action-height: 44px;
407
+ }
408
+
409
+
355
410
  /* ============================================================
356
411
  2. HINTERGRUND
357
412
  ============================================================ */
@@ -524,7 +579,7 @@
524
579
  ============================================================ */
525
580
  .glass-btn {
526
581
  display: flex; align-items: center; justify-content: center;
527
- gap: 10px; width: 100%; height: 56px;
582
+ gap: 10px; width: 100%; height: var(--gl-btn-height, 56px);
528
583
  border: none; border-radius: var(--gl-radius-btn);
529
584
  font-family: var(--gl-font-family);
530
585
  font-size: var(--gl-font-size-btn);
@@ -603,8 +658,8 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
603
658
  .glass-btn--tertiary:active { transform: translateY(1px); }
604
659
 
605
660
  /* Sizes */
606
- .glass-btn--sm { height: 44px; font-size: var(--gl-font-size-sm); border-radius: var(--gl-radius-sm); }
607
- .glass-btn--lg { height: 64px; font-size: var(--gl-font-size-lg); }
661
+ .glass-btn--sm { height: var(--gl-btn-height-sm, 44px); font-size: var(--gl-font-size-sm); border-radius: var(--gl-radius-sm); }
662
+ .glass-btn--lg { height: var(--gl-btn-height-lg, 64px); font-size: var(--gl-font-size-lg); }
608
663
  .glass-btn--auto { width: auto; padding: 0 var(--gl-space-xl); }
609
664
 
610
665
 
@@ -652,8 +707,8 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
652
707
  }
653
708
 
654
709
  .glass-input {
655
- width: 100%; height: 52px;
656
- padding: 0 var(--gl-space-md);
710
+ width: 100%; height: var(--gl-control-height, 52px);
711
+ padding: 0 var(--gl-control-padding-x, var(--gl-space-md));
657
712
  background: var(--gl-surface-2);
658
713
  backdrop-filter: blur(var(--gl-blur-light));
659
714
  -webkit-backdrop-filter: blur(var(--gl-blur-light));
@@ -708,8 +763,8 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
708
763
 
709
764
  /* Textarea */
710
765
  .glass-textarea {
711
- width: 100%; min-height: 120px;
712
- padding: var(--gl-space-md);
766
+ width: 100%; min-height: var(--gl-textarea-min-height, 120px);
767
+ padding: var(--gl-space-md) var(--gl-control-padding-x, var(--gl-space-md));
713
768
  background: var(--gl-surface-2);
714
769
  backdrop-filter: blur(var(--gl-blur-light));
715
770
  -webkit-backdrop-filter: blur(var(--gl-blur-light));
@@ -735,8 +790,8 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
735
790
  9. SELECT
736
791
  ============================================================ */
737
792
  .glass-select {
738
- width: 100%; height: 52px;
739
- padding: 0 var(--gl-space-3xl) 0 var(--gl-space-md);
793
+ width: 100%; height: var(--gl-control-height, 52px);
794
+ padding: 0 var(--gl-space-3xl) 0 var(--gl-control-padding-x, var(--gl-space-md));
740
795
  background: var(--gl-surface-2);
741
796
  backdrop-filter: blur(var(--gl-blur-light));
742
797
  -webkit-backdrop-filter: blur(var(--gl-blur-light));
@@ -757,7 +812,7 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
757
812
  /* Right to left: the chevron and the room kept for it move to the left —
758
813
  together, under :dir(), so a browser without it keeps both on the right. */
759
814
  .glass-select:dir(rtl) {
760
- padding: 0 var(--gl-space-md) 0 var(--gl-space-3xl);
815
+ padding: 0 var(--gl-control-padding-x, var(--gl-space-md)) 0 var(--gl-space-3xl);
761
816
  background-position: left 16px center;
762
817
  }
763
818
  .glass-select:focus {
@@ -795,7 +850,8 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
795
850
  /* ============================================================
796
851
  11. TOGGLE SWITCH
797
852
  ============================================================ */
798
- /* First-line alignment — see the note on .glass-checkbox below. Track is 30px. */
853
+ /* First-line alignment — see the note on .glass-checkbox below. The track
854
+ is --gl-toggle-height high (30px by default). */
799
855
  .glass-toggle {
800
856
  display: inline-flex; align-items: flex-start;
801
857
  gap: var(--gl-space-sm); cursor: pointer;
@@ -812,12 +868,12 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
812
868
  the lh unit drops it and keeps margin: 0, as the track does. */
813
869
  .glass-toggle__input {
814
870
  position: absolute; z-index: 1; opacity: 0; cursor: inherit;
815
- width: 52px; height: 30px; margin: 0; font: inherit;
816
- margin-top: max(0px, calc((1lh - 30px) / 2));
871
+ width: var(--gl-toggle-width, 52px); height: var(--gl-toggle-height, 30px); margin: 0; font: inherit;
872
+ margin-top: max(0px, calc((1lh - var(--gl-toggle-height, 30px)) / 2));
817
873
  }
818
874
 
819
875
  .glass-toggle__track {
820
- position: relative; width: 52px; height: 30px;
876
+ position: relative; width: var(--gl-toggle-width, 52px); height: var(--gl-toggle-height, 30px);
821
877
  background: var(--gl-surface-2);
822
878
  backdrop-filter: blur(var(--gl-blur-soft));
823
879
  -webkit-backdrop-filter: blur(var(--gl-blur-soft));
@@ -826,12 +882,19 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
826
882
  transition: var(--gl-transition);
827
883
  box-shadow: var(--gl-inset-subtle);
828
884
  flex-shrink: 0;
829
- margin-top: max(0px, calc((1lh - 30px) / 2));
885
+ margin-top: max(0px, calc((1lh - var(--gl-toggle-height, 30px)) / 2));
830
886
  }
831
887
 
888
+ /* Inset and travel follow the track. Top and left (right, right to left)
889
+ are (height − thumb) / 2 − 1px inside the 1.5px border: 3px at 52 × 30,
890
+ where the thumb has always sat (taking off the whole border would move
891
+ it by half a pixel). It travels width − height, so the gap at the end
892
+ mirrors the one below. */
832
893
  .glass-toggle__thumb {
833
- position: absolute; top: 3px; left: 3px;
834
- width: 22px; height: 22px;
894
+ position: absolute;
895
+ top: calc((var(--gl-toggle-height, 30px) - var(--gl-toggle-thumb-size, 22px)) / 2 - 1px);
896
+ left: calc((var(--gl-toggle-height, 30px) - var(--gl-toggle-thumb-size, 22px)) / 2 - 1px);
897
+ width: var(--gl-toggle-thumb-size, 22px); height: var(--gl-toggle-thumb-size, 22px);
835
898
  border-radius: var(--gl-radius-pill);
836
899
  background: var(--gl-toggle-thumb-bg);
837
900
  box-shadow: 0 2px 6px rgba(0,0,0,0.2), var(--gl-inset-milk);
@@ -846,13 +909,15 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
846
909
  }
847
910
 
848
911
  .glass-toggle__input:checked + .glass-toggle__track .glass-toggle__thumb {
849
- transform: translateX(22px);
912
+ transform: translateX(calc(var(--gl-toggle-width, 52px) - var(--gl-toggle-height, 30px)));
850
913
  }
851
914
  /* Right to left the thumb starts on the right and travels left — both
852
915
  under :dir(), so a browser without it keeps the left-to-right switch. */
853
- .glass-toggle__thumb:dir(rtl) { left: auto; right: 3px; }
916
+ .glass-toggle__thumb:dir(rtl) {
917
+ left: auto; right: calc((var(--gl-toggle-height, 30px) - var(--gl-toggle-thumb-size, 22px)) / 2 - 1px);
918
+ }
854
919
  .glass-toggle__input:checked + .glass-toggle__track .glass-toggle__thumb:dir(rtl) {
855
- transform: translateX(-22px);
920
+ transform: translateX(calc(var(--gl-toggle-height, 30px) - var(--gl-toggle-width, 52px)));
856
921
  }
857
922
 
858
923
  .glass-toggle__input:focus-visible + .glass-toggle__track { box-shadow: var(--gl-shadow-focus); }
@@ -861,7 +926,7 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
861
926
  font-size: var(--gl-font-size-base);
862
927
  color: var(--gl-color-text);
863
928
  user-select: none;
864
- margin-top: max(0px, calc((30px - 1lh) / 2));
929
+ margin-top: max(0px, calc((var(--gl-toggle-height, 30px) - 1lh) / 2));
865
930
  }
866
931
  /* A control without a label keeps no gap for one. */
867
932
  .glass-toggle__label:empty,
@@ -874,11 +939,12 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
874
939
  ============================================================ */
875
940
  /* Control and label are aligned on the *first line*, not on the middle of the
876
941
  text block — a consent label runs over several lines and a centred box then
877
- points at nothing. The two margins below centre the 24px box on that first
878
- line; whichever is the shorter of the two gets the offset, so exactly one is
879
- ever non-zero. For a single-line label this is pixel-identical to the
880
- `align-items: center` of pre-1.11.0. Repeated on .glass-radio (24px) and
881
- .glass-toggle (30px) — keep the three in step. */
942
+ points at nothing. The two margins below centre the box (--gl-check-size,
943
+ 24px by default) on that first line; whichever is the shorter of the two
944
+ gets the offset, so exactly one is ever non-zero. For a single-line label
945
+ this is pixel-identical to the `align-items: center` of pre-1.11.0.
946
+ Repeated on .glass-radio (--gl-check-size) and .glass-toggle
947
+ (--gl-toggle-height) — keep the three in step. */
882
948
  .glass-checkbox {
883
949
  display: inline-flex; align-items: flex-start;
884
950
  gap: var(--gl-space-sm); cursor: pointer;
@@ -887,12 +953,12 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
887
953
  /* On top of the box, covering it only — see .glass-toggle__input. */
888
954
  .glass-checkbox__input {
889
955
  position: absolute; z-index: 1; opacity: 0; cursor: inherit;
890
- width: 24px; height: 24px; margin: 0; font: inherit;
891
- margin-top: max(0px, calc((1lh - 24px) / 2));
956
+ width: var(--gl-check-size, 24px); height: var(--gl-check-size, 24px); margin: 0; font: inherit;
957
+ margin-top: max(0px, calc((1lh - var(--gl-check-size, 24px)) / 2));
892
958
  }
893
959
 
894
960
  .glass-checkbox__box {
895
- width: 24px; height: 24px;
961
+ width: var(--gl-check-size, 24px); height: var(--gl-check-size, 24px);
896
962
  border-radius: var(--gl-radius-xs);
897
963
  background: var(--gl-surface-2);
898
964
  backdrop-filter: blur(var(--gl-blur-soft));
@@ -902,7 +968,7 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
902
968
  transition: var(--gl-transition);
903
969
  box-shadow: var(--gl-inset-subtle);
904
970
  flex-shrink: 0;
905
- margin-top: max(0px, calc((1lh - 24px) / 2));
971
+ margin-top: max(0px, calc((1lh - var(--gl-check-size, 24px)) / 2));
906
972
  }
907
973
 
908
974
  .glass-checkbox__box svg {
@@ -925,7 +991,7 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
925
991
  .glass-checkbox__label {
926
992
  font-size: var(--gl-font-size-base);
927
993
  color: var(--gl-color-text); user-select: none;
928
- margin-top: max(0px, calc((24px - 1lh) / 2));
994
+ margin-top: max(0px, calc((var(--gl-check-size, 24px) - 1lh) / 2));
929
995
  }
930
996
 
931
997
 
@@ -941,12 +1007,12 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
941
1007
  /* On top of the circle, covering it only — see .glass-toggle__input. */
942
1008
  .glass-radio__input {
943
1009
  position: absolute; z-index: 1; opacity: 0; cursor: inherit;
944
- width: 24px; height: 24px; margin: 0; font: inherit;
945
- margin-top: max(0px, calc((1lh - 24px) / 2));
1010
+ width: var(--gl-check-size, 24px); height: var(--gl-check-size, 24px); margin: 0; font: inherit;
1011
+ margin-top: max(0px, calc((1lh - var(--gl-check-size, 24px)) / 2));
946
1012
  }
947
1013
 
948
1014
  .glass-radio__circle {
949
- width: 24px; height: 24px;
1015
+ width: var(--gl-check-size, 24px); height: var(--gl-check-size, 24px);
950
1016
  border-radius: var(--gl-radius-pill);
951
1017
  background: var(--gl-surface-2);
952
1018
  backdrop-filter: blur(var(--gl-blur-soft));
@@ -955,7 +1021,7 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
955
1021
  transition: var(--gl-transition);
956
1022
  box-shadow: var(--gl-inset-subtle);
957
1023
  flex-shrink: 0;
958
- margin-top: max(0px, calc((1lh - 24px) / 2));
1024
+ margin-top: max(0px, calc((1lh - var(--gl-check-size, 24px)) / 2));
959
1025
  }
960
1026
 
961
1027
  .glass-radio__dot {
@@ -978,7 +1044,7 @@ a.glass-btn { display: inline-flex; text-decoration: none; }
978
1044
  .glass-radio__label {
979
1045
  font-size: var(--gl-font-size-base);
980
1046
  color: var(--gl-color-text); user-select: none;
981
- margin-top: max(0px, calc((24px - 1lh) / 2));
1047
+ margin-top: max(0px, calc((var(--gl-check-size, 24px) - 1lh) / 2));
982
1048
  }
983
1049
 
984
1050
 
@@ -1166,7 +1232,7 @@ dialog.glass-modal-overlay::backdrop { background: transparent; }
1166
1232
  .glass-modal__footer { display: flex; border-top: 1px solid var(--gl-border-subtle); }
1167
1233
 
1168
1234
  .glass-modal__action {
1169
- flex: 1; height: 52px;
1235
+ flex: 1; height: var(--gl-modal-action-height, 52px);
1170
1236
  background: transparent; border: none;
1171
1237
  font-family: var(--gl-font-family);
1172
1238
  font-size: var(--gl-font-size-btn);
@@ -1894,8 +1960,8 @@ dialog.glass-modal-overlay::backdrop { background: transparent; }
1894
1960
  display: flex;
1895
1961
  align-items: center;
1896
1962
  gap: var(--gl-space-sm);
1897
- padding: var(--gl-space-md) var(--gl-space-lg);
1898
- min-height: 56px;
1963
+ padding: var(--gl-list-item-padding-y, var(--gl-space-md)) var(--gl-space-lg);
1964
+ min-height: var(--gl-list-item-min-height, 56px);
1899
1965
  color: var(--gl-color-text);
1900
1966
  font-size: var(--gl-font-size-base);
1901
1967
  text-decoration: none;
@@ -2619,3 +2685,36 @@ dialog.glass-modal-overlay::backdrop { background: transparent; }
2619
2685
  /* Escape hatch: deliberately filled icons (e.g. brand logos),
2620
2686
  overrides the outline defaults of the components */
2621
2687
  svg.glass-icon--fill { fill: currentColor; stroke: none; }
2688
+
2689
+
2690
+ /* ============================================================
2691
+ 37. PRINT
2692
+ ============================================================ */
2693
+ /* Printing drops backgrounds unless "Background graphics" is ticked, and it
2694
+ is off by default in the print dialogs. Several states are drawn with a
2695
+ background only: the checked box and its white tick, the chosen radio and
2696
+ its dot, the toggle's on track, the progress fill, the current step, the
2697
+ chosen day of date strip and calendar, the slider thumb, and the tone dots
2698
+ of calendar, date strip and segmented control. On paper a checked box
2699
+ printed like an empty one and the chosen day came out paler than the rest.
2700
+ These parts print as on screen; thumb, tick, dot and marks inherit the
2701
+ setting from the part they sit in. Everything else keeps the economical
2702
+ mode — including the browser darkening light text for white paper, which
2703
+ is why whole day buttons or step numbers are not listed, only the chosen
2704
+ and the current ones. Both spellings: browsers differ in which they read. */
2705
+ @media print {
2706
+ .glass-toggle__track,
2707
+ .glass-checkbox__box,
2708
+ .glass-radio__circle,
2709
+ .glass-progress__fill,
2710
+ .glass-range,
2711
+ .glass-steps__item--current .glass-steps__num,
2712
+ .glass-date-strip__day[aria-pressed="true"],
2713
+ .glass-calendar__day[aria-pressed="true"],
2714
+ .glass-date-strip__mark,
2715
+ .glass-calendar__mark,
2716
+ .glass-segmented__dot {
2717
+ -webkit-print-color-adjust: exact;
2718
+ print-color-adjust: exact;
2719
+ }
2720
+ }