nexus-shared 3.1.0 → 3.2.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 (104) hide show
  1. package/CHANGELOG.md +704 -446
  2. package/LICENSE +21 -21
  3. package/README.md +44 -5
  4. package/dist/Client.Index.d.ts +3 -0
  5. package/dist/Client.Index.js +3 -0
  6. package/dist/Components/Forms/Crud.js +322 -161
  7. package/dist/Components/Forms/CrudHistory.d.ts +66 -0
  8. package/dist/Components/Forms/CrudHistory.js +140 -0
  9. package/dist/Components/Forms/CrudParts.js +2 -1
  10. package/dist/Components/Forms/Form.js +4 -1
  11. package/dist/Components/Inputs/CodeBox.d.ts +69 -0
  12. package/dist/Components/Inputs/CodeBox.js +316 -0
  13. package/dist/Components/Inputs/DatePicker.js +4 -1
  14. package/dist/Components/Inputs/DateRangePicker.js +4 -1
  15. package/dist/Components/Inputs/DateTimePicker.js +4 -1
  16. package/dist/Components/Inputs/Dropdown.js +4 -1
  17. package/dist/Components/Inputs/InputRenderer.js +3 -0
  18. package/dist/Components/Inputs/NumberBox.js +4 -2
  19. package/dist/Components/Inputs/TextArea.js +4 -1
  20. package/dist/Components/Inputs/TextBox.js +4 -1
  21. package/dist/Components/Inputs/TimePicker.js +4 -1
  22. package/dist/Components/Inputs/TreeView.d.ts +55 -5
  23. package/dist/Components/Inputs/TreeView.js +372 -23
  24. package/dist/Components/Layouts/ThemePicker.d.ts +3 -2
  25. package/dist/Components/Layouts/ThemePicker.js +16 -4
  26. package/dist/Components/Viewers/DataTable.js +63 -21
  27. package/dist/Components/Viewers/DataTableParts.d.ts +26 -8
  28. package/dist/Components/Viewers/DataTableParts.js +39 -10
  29. package/dist/Helpers/ApiModules.d.ts +3 -34
  30. package/dist/Helpers/ApiModules.js +3 -3
  31. package/dist/Helpers/ApiRoutes.d.ts +68 -26
  32. package/dist/Helpers/ApiRoutes.js +31 -27
  33. package/dist/Helpers/ArrayHelpers.d.ts +0 -0
  34. package/dist/Helpers/ArrayHelpers.js +2 -0
  35. package/dist/Helpers/CodeHelpers.d.ts +97 -0
  36. package/dist/Helpers/CodeHelpers.js +332 -0
  37. package/dist/Helpers/CrudBackend.d.ts +94 -4
  38. package/dist/Helpers/CrudBackend.js +168 -9
  39. package/dist/Helpers/CrudColumns.d.ts +51 -0
  40. package/dist/Helpers/CrudColumns.js +69 -0
  41. package/dist/Helpers/CrudHelpers.d.ts +50 -5
  42. package/dist/Helpers/CrudHelpers.js +109 -12
  43. package/dist/Helpers/InputParamsHelpers.js +8 -0
  44. package/dist/Helpers/MessageBuilder.js +2 -0
  45. package/dist/Helpers/NexusHelpers.d.ts +0 -0
  46. package/dist/Helpers/NexusHelpers.js +1 -0
  47. package/dist/Helpers/RequestCache.d.ts +35 -0
  48. package/dist/Helpers/RequestCache.js +113 -0
  49. package/dist/Helpers/TableExport.js +12 -12
  50. package/dist/Helpers/TableHelpers.d.ts +1 -1
  51. package/dist/Helpers/TableHelpers.js +7 -2
  52. package/dist/Helpers/TableJoins.d.ts +70 -0
  53. package/dist/Helpers/TableJoins.js +250 -0
  54. package/dist/Helpers/TableStore.d.ts +5 -0
  55. package/dist/Helpers/TableStore.js +9 -0
  56. package/dist/Helpers/TreeStore.d.ts +225 -11
  57. package/dist/Helpers/TreeStore.js +683 -90
  58. package/dist/Helpers/UserPreferences.d.ts +8 -0
  59. package/dist/Helpers/UserPreferences.js +17 -0
  60. package/dist/Interfaces/CrudInterfaces.d.ts +47 -9
  61. package/dist/Interfaces/FormInterfaces.d.ts +4 -1
  62. package/dist/Interfaces/InputInterfaces.d.ts +24 -0
  63. package/dist/Interfaces/MessageInterfaces.d.ts +1 -1
  64. package/dist/Interfaces/PreferenceInterfaces.d.ts +8 -0
  65. package/dist/Interfaces/PreferenceInterfaces.js +2 -5
  66. package/dist/Interfaces/TableInterfaces.d.ts +86 -4
  67. package/dist/Services/ApiProxy.d.ts +36 -1
  68. package/dist/Services/ApiProxy.js +182 -52
  69. package/dist/Services/ApiProxyRules.d.ts +203 -0
  70. package/dist/Services/ApiProxyRules.js +426 -0
  71. package/dist/Services/JoinSources.d.ts +48 -0
  72. package/dist/Services/JoinSources.js +74 -0
  73. package/dist/Services/ServerApi.d.ts +13 -2
  74. package/dist/Services/ServerApi.js +8 -3
  75. package/dist/Shared.Index.d.ts +4 -0
  76. package/dist/Shared.Index.js +4 -0
  77. package/package.json +87 -85
  78. package/src/Styles/Nexus.Avatar.css +79 -79
  79. package/src/Styles/Nexus.Base.css +117 -117
  80. package/src/Styles/Nexus.Button.css +180 -180
  81. package/src/Styles/Nexus.Calendar.css +273 -273
  82. package/src/Styles/Nexus.Chat.css +1443 -1443
  83. package/src/Styles/Nexus.Choice.css +343 -343
  84. package/src/Styles/Nexus.Crud.css +168 -168
  85. package/src/Styles/Nexus.DateTime.css +81 -81
  86. package/src/Styles/Nexus.Dropdown.css +725 -725
  87. package/src/Styles/Nexus.Editor.css +295 -295
  88. package/src/Styles/Nexus.Excel.css +389 -389
  89. package/src/Styles/Nexus.Form.css +279 -279
  90. package/src/Styles/Nexus.Index.css +37 -37
  91. package/src/Styles/Nexus.Input.css +196 -4
  92. package/src/Styles/Nexus.Markdown.css +237 -237
  93. package/src/Styles/Nexus.Menu.css +237 -237
  94. package/src/Styles/Nexus.Popup.css +724 -724
  95. package/src/Styles/Nexus.Rows.css +637 -637
  96. package/src/Styles/Nexus.Slider.css +276 -276
  97. package/src/Styles/Nexus.Tab.Buttons.css +432 -432
  98. package/src/Styles/Nexus.Table.css +31 -30
  99. package/src/Styles/Nexus.Theme.Picker.css +59 -3
  100. package/src/Styles/Nexus.Themes.css +194 -194
  101. package/src/Styles/Nexus.Time.css +144 -144
  102. package/src/Styles/Nexus.Toast.css +263 -263
  103. package/src/Styles/Nexus.Tokens.css +89 -89
  104. package/src/Styles/Nexus.Tree.css +500 -431
@@ -466,14 +466,51 @@
466
466
  top: calc(var(--nx-field-pad-y) + var(--nx-field-font) * 0.7);
467
467
  }
468
468
 
469
- /* Outlined: the raised label sits on the top border. Its backing covers only the lower half, so it blends with any panel. */
469
+ /*
470
+ * Outlined: the raised label sits on the top border, centred on its inner edge, and opens a gap in it: behind the
471
+ * label the field's colour runs from the box's top edge down, and never above it, where it shows on any panel whose
472
+ * colour is not the field's (a read-only box, a dark popover). No CSS length finds that edge at every scale: a 1px
473
+ * border is one device pixel thick at 125% and two at 200%. So the backing is placed by the same length the label is
474
+ * lifted by (half its 1.2 line height: the two cancel, and it starts on the border's inner edge), and its 1px outline
475
+ * covers the border, because the browser snaps an outline exactly as it snaps a border. The label's overflow keeps
476
+ * the outline's sides and foot inside it. A gradient on the label instead was half a pixel off at most scales from 67%
477
+ * to 300%: the field's colour a row above the box, or a hairline of border through the gap.
478
+ */
470
479
  .nx-field--outlined:is([data-raised], :focus-within, :has(.nx-field__control:not(:placeholder-shown))) .nx-field__label {
471
- top: 0;
480
+ top: -0.6em;
472
481
  left: calc(var(--nx-field-pad-x) - 4px);
473
482
  padding: 0 4px;
474
- background: linear-gradient(to bottom, transparent calc(50% - 1px), var(--nx-field-bg) calc(50% - 1px));
475
483
  font-size: var(--nx-text-xs);
476
484
  font-weight: 500;
485
+ transform: none;
486
+ }
487
+
488
+ .nx-field--outlined:is([data-raised], :focus-within, :has(.nx-field__control:not(:placeholder-shown))) .nx-field__label::before {
489
+ content: "";
490
+ position: absolute;
491
+ z-index: -1;
492
+ inset: 0.6em 0 0;
493
+ outline: 1px solid var(--nx-field-bg);
494
+ background: var(--nx-field-bg);
495
+ }
496
+
497
+ /* Forced colours would paint that outline in the text's colour; the browser's backplate behind the text opens the gap. */
498
+ @media (forced-colors: active) {
499
+ .nx-field--outlined .nx-field__label::before {
500
+ display: none;
501
+ }
502
+ }
503
+
504
+ /*
505
+ * Outlined, with focus: the border thickens to 2px instead of taking the ring. A ring lies outside the box, past the
506
+ * label's backing, so it ran on behind the label; this edge lies on the border and a pixel inside it, where the
507
+ * backing opens the same gap in it. One 2px outline over the border, not a second pixel beside it, which showed a
508
+ * seam at 150%; and an outline, so it is drawn over the control (an autofilled one is opaque) and under the label.
509
+ */
510
+ .nx-field--outlined:not([data-readonly], [data-disabled]) .nx-field__box:focus-within {
511
+ outline: 2px solid var(--nx-field-accent);
512
+ outline-offset: -2px;
513
+ box-shadow: var(--nx-shadow-sm);
477
514
  }
478
515
 
479
516
  /* Inbox: a taller box with the raised label inside its top edge. */
@@ -590,11 +627,166 @@
590
627
  }
591
628
  }
592
629
 
630
+ /*
631
+ * Code box: a box per character, drawn from one input that lies over them unseen. The boxes wear the field's own
632
+ * variables, so sizes, states, densities, and themes come with them; the field's single frame steps aside.
633
+ */
634
+ .nx-field--code .nx-field__box,
635
+ .nx-field--code .nx-field__box:focus-within {
636
+ min-height: 0;
637
+ border: 0;
638
+ background: none;
639
+ box-shadow: none;
640
+ }
641
+
642
+ .nx-code {
643
+ position: relative;
644
+ display: flex;
645
+ min-width: 0;
646
+ }
647
+
648
+ .nx-code[data-block] {
649
+ flex: 1 1 auto;
650
+ }
651
+
652
+ /* On a phone the gaps and the characters scale with the screen, so an SSN's nine boxes fit a 390px screen. */
653
+ .nx-code__slots,
654
+ .nx-code__group {
655
+ display: flex;
656
+ align-items: center;
657
+ gap: min(var(--nx-space-2), 1.2vw);
658
+ min-width: 0;
659
+ }
660
+
661
+ .nx-code[data-block] :is(.nx-code__slots, .nx-code__group) {
662
+ flex: 1 1 auto;
663
+ }
664
+
665
+ .nx-code__separator {
666
+ flex: none;
667
+ color: var(--nx-text-muted);
668
+ font-size: var(--nx-field-font);
669
+ }
670
+
671
+ /*
672
+ * A box is a little taller than the field's line and about as wide; its character is larger than the field's text.
673
+ * Boxes shrink alike rather than spill out of their field: a code too long for its room is cramped, never cut off.
674
+ */
675
+ .nx-code__slot {
676
+ position: relative;
677
+ display: grid;
678
+ flex: 0 1 calc(var(--nx-field-height) + var(--nx-space-1));
679
+ place-items: center;
680
+ min-width: 0;
681
+ height: calc(var(--nx-field-height) + var(--nx-space-3));
682
+ border: 1px solid var(--nx-field-border);
683
+ border-radius: var(--nx-radius);
684
+ background: var(--nx-field-bg);
685
+ box-shadow: var(--nx-shadow-sm);
686
+ color: var(--nx-text);
687
+ font-size: min(calc(var(--nx-field-font) * 1.4), 5vw);
688
+ font-variant-numeric: tabular-nums;
689
+ font-weight: 600;
690
+ line-height: 1;
691
+ transition:
692
+ border-color var(--nx-duration),
693
+ box-shadow var(--nx-duration),
694
+ background-color var(--nx-duration);
695
+ }
696
+
697
+ /*
698
+ * Without `block` the rows around the boxes are as wide as their content, and Chromium counts each box's width there,
699
+ * not its flex-basis: with a basis alone an empty box was its 2px border and a filled one its character. A width
700
+ * gives each box its size; `min-width: 0` still lets them shrink alike on a narrow screen.
701
+ */
702
+ .nx-code:not([data-block]) .nx-code__slot {
703
+ width: calc(var(--nx-field-height) + var(--nx-space-1));
704
+ }
705
+
706
+ .nx-code[data-block] .nx-code__slot {
707
+ flex: 1 1 0;
708
+ }
709
+
710
+ .nx-code:hover .nx-code__slot {
711
+ border-color: var(--nx-field-border-hover);
712
+ }
713
+
714
+ .nx-code__slot[data-active] {
715
+ border-color: var(--nx-field-accent);
716
+ box-shadow: var(--nx-field-ring);
717
+ }
718
+
719
+ .nx-code__slot[data-selected] {
720
+ background: color-mix(in oklab, var(--nx-field-accent) 14%, var(--nx-field-bg));
721
+ }
722
+
723
+ .nx-code__slot:empty::before {
724
+ content: attr(data-placeholder);
725
+ color: var(--nx-text-subtle);
726
+ font-weight: 400;
727
+ }
728
+
729
+ /* The caret in an empty box, blinking as a text caret does. */
730
+ .nx-code__slot[data-caret]::after {
731
+ content: "";
732
+ position: absolute;
733
+ width: 2px;
734
+ height: 45%;
735
+ border-radius: 1px;
736
+ background: var(--nx-text);
737
+ animation: nx-code-caret 1s step-end infinite;
738
+ }
739
+
740
+ @keyframes nx-code-caret {
741
+ 50% {
742
+ opacity: 0;
743
+ }
744
+ }
745
+
746
+ .nx-field:is([data-readonly], [data-disabled]) .nx-code__slot {
747
+ box-shadow: none;
748
+ }
749
+
750
+ /* The input that holds the code lies over the boxes, never seen. At 16px a phone does not zoom in on focus. */
751
+ .nx-code__input {
752
+ position: absolute;
753
+ inset: 0;
754
+ width: 100%;
755
+ margin: 0;
756
+ padding: 0;
757
+ border: 0;
758
+ outline: none;
759
+ background: transparent;
760
+ color: transparent;
761
+ caret-color: transparent;
762
+ font-size: 16px;
763
+ cursor: text;
764
+ }
765
+
766
+ .nx-code__input::selection {
767
+ background: transparent;
768
+ }
769
+
770
+ /* An offered code fills the input without its yellow: the boxes show it. */
771
+ .nx-code__input:is(:autofill, :-webkit-autofill) {
772
+ -webkit-text-fill-color: transparent;
773
+ transition: background-color 600000s;
774
+ }
775
+
776
+ .nx-code__input:disabled {
777
+ cursor: not-allowed;
778
+ }
779
+
593
780
  [data-nx-motion="reduce"] .nx-field__label,
594
- [data-nx-motion="reduce"] .nx-field--inbox :is(.nx-field__icon, .nx-field__affix, .nx-field__actions) {
781
+ [data-nx-motion="reduce"] .nx-field--inbox :is(.nx-field__icon, .nx-field__affix, .nx-field__actions),
782
+ [data-nx-motion="reduce"] .nx-code__slot {
595
783
  transition: none;
596
784
  }
597
785
 
786
+ [data-nx-motion="reduce"] .nx-code__slot[data-caret]::after {
787
+ animation: none;
788
+ }
789
+
598
790
  [data-nx-motion="reduce"] .nx-field__lock[data-nudge],
599
791
  [data-nx-motion="reduce"] .nx-field-notice:popover-open {
600
792
  animation: none;
@@ -1,237 +1,237 @@
1
- @layer nexus.components {
2
- /*
3
- * Markdown editor: the text and its preview inside the editor frame (Nexus.Editor.css), which brings the bar, the
4
- * height handle, and full screen.
5
- */
6
- .nx-md .nx-editor__body[data-mode="split"] {
7
- grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
8
- }
9
-
10
- .nx-md .nx-editor__body[data-mode="preview"] .nx-md__input {
11
- display: none;
12
- }
13
-
14
- .nx-md .nx-md__input {
15
- height: 100%;
16
- min-height: 0;
17
- padding: 10px var(--nx-space-3);
18
- border-radius: 0;
19
- line-height: 1.6;
20
- resize: none;
21
- }
22
-
23
- .nx-md--mono .nx-md__input {
24
- font-family: var(--nx-font-mono);
25
- font-size: calc(var(--nx-field-font) - 0.5px);
26
- }
27
-
28
- .nx-md__preview {
29
- min-width: 0;
30
- min-height: 0;
31
- padding: 10px var(--nx-space-4);
32
- overflow: auto;
33
- overscroll-behavior: contain;
34
- }
35
-
36
- .nx-md .nx-editor__body[data-mode="split"] .nx-md__preview {
37
- border-left: 1px solid var(--nx-border);
38
- }
39
-
40
- .nx-md__preview:focus-visible {
41
- outline: 2px solid var(--nx-primary);
42
- outline-offset: -2px;
43
- }
44
-
45
- @container nx-editor (width < 560px) {
46
- .nx-md .nx-editor__body[data-mode="split"] {
47
- grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
48
- grid-template-columns: minmax(0, 1fr);
49
- }
50
-
51
- .nx-md .nx-editor__body[data-mode="split"] .nx-md__preview {
52
- border-top: 1px solid var(--nx-border);
53
- border-left: 0;
54
- }
55
- }
56
-
57
- /*
58
- * Markdown content (MarkdownView), in the editor's preview and anywhere else. Sizes are in em, so the text follows
59
- * the size of the element it sits in.
60
- */
61
- .nx-markdown {
62
- color: var(--nx-text);
63
- font-size: var(--nx-text-md);
64
- line-height: 1.65;
65
- overflow-wrap: break-word;
66
- }
67
-
68
- .nx-markdown > :first-child {
69
- margin-top: 0;
70
- }
71
-
72
- .nx-markdown > :last-child {
73
- margin-bottom: 0;
74
- }
75
-
76
- .nx-markdown :is(p, ul, ol, blockquote, pre, hr, .nx-markdown__table) {
77
- margin: 0 0 0.9em;
78
- }
79
-
80
- .nx-markdown :is(h1, h2, h3, h4, h5, h6) {
81
- margin: 1.4em 0 0.55em;
82
- font-weight: 650;
83
- line-height: 1.3;
84
- letter-spacing: -0.01em;
85
- }
86
-
87
- .nx-markdown :is(h1, h2) {
88
- padding-bottom: 0.3em;
89
- border-bottom: 1px solid var(--nx-border);
90
- }
91
-
92
- .nx-markdown h1 {
93
- font-size: 1.6em;
94
- }
95
-
96
- .nx-markdown h2 {
97
- font-size: 1.3em;
98
- }
99
-
100
- .nx-markdown h3 {
101
- font-size: 1.12em;
102
- }
103
-
104
- .nx-markdown h4 {
105
- font-size: 1em;
106
- }
107
-
108
- .nx-markdown h5 {
109
- font-size: 0.9em;
110
- }
111
-
112
- .nx-markdown h6 {
113
- color: var(--nx-text-muted);
114
- font-size: 0.85em;
115
- }
116
-
117
- .nx-markdown a {
118
- color: var(--nx-primary);
119
- text-decoration: underline;
120
- text-decoration-color: color-mix(in oklab, currentColor 40%, transparent);
121
- text-underline-offset: 0.18em;
122
- }
123
-
124
- .nx-markdown a:hover {
125
- text-decoration-color: currentColor;
126
- }
127
-
128
- .nx-markdown :is(ul, ol) {
129
- padding-left: 1.6em;
130
- }
131
-
132
- .nx-markdown li + li {
133
- margin-top: 0.25em;
134
- }
135
-
136
- .nx-markdown li > :is(ul, ol) {
137
- margin: 0.25em 0 0;
138
- }
139
-
140
- .nx-markdown li > p {
141
- margin-bottom: 0.5em;
142
- }
143
-
144
- /* Tasks: the box sits where the bullet would. */
145
- .nx-markdown__task {
146
- position: relative;
147
- list-style: none;
148
- }
149
-
150
- .nx-markdown__task > input {
151
- position: absolute;
152
- top: 0.32em;
153
- left: -1.45em;
154
- width: 1em;
155
- height: 1em;
156
- margin: 0;
157
- accent-color: var(--nx-primary-solid);
158
- }
159
-
160
- .nx-markdown__task > input:enabled {
161
- cursor: pointer;
162
- }
163
-
164
- .nx-markdown blockquote {
165
- padding: 0 0 0 1em;
166
- border-left: 3px solid var(--nx-border-strong);
167
- color: var(--nx-text-muted);
168
- }
169
-
170
- .nx-markdown code {
171
- padding: 0.12em 0.38em;
172
- border-radius: var(--nx-radius-sm);
173
- background: color-mix(in oklab, var(--nx-text) 8%, transparent);
174
- font-family: var(--nx-font-mono);
175
- font-size: 0.875em;
176
- }
177
-
178
- .nx-markdown pre {
179
- overflow: auto;
180
- padding: 0.8em 1em;
181
- border-radius: var(--nx-radius);
182
- background: color-mix(in oklab, var(--nx-text) 5%, transparent);
183
- line-height: 1.5;
184
- }
185
-
186
- .nx-markdown pre code {
187
- padding: 0;
188
- background: none;
189
- font-size: 0.86em;
190
- white-space: pre;
191
- }
192
-
193
- .nx-markdown hr {
194
- height: 0;
195
- margin-block: 1.4em;
196
- border: 0;
197
- border-top: 1px solid var(--nx-border-strong);
198
- }
199
-
200
- .nx-markdown img {
201
- max-width: 100%;
202
- height: auto;
203
- border-radius: var(--nx-radius-sm);
204
- vertical-align: middle;
205
- }
206
-
207
- .nx-markdown del {
208
- color: var(--nx-text-muted);
209
- }
210
-
211
- .nx-markdown__table {
212
- max-width: 100%;
213
- overflow-x: auto;
214
- }
215
-
216
- .nx-markdown table {
217
- border-collapse: collapse;
218
- font-size: 0.95em;
219
- }
220
-
221
- .nx-markdown :is(th, td) {
222
- padding: 0.4em 0.8em;
223
- border: 1px solid var(--nx-border);
224
- text-align: left;
225
- vertical-align: top;
226
- }
227
-
228
- .nx-markdown th {
229
- background: color-mix(in oklab, var(--nx-text) 4%, transparent);
230
- font-weight: 600;
231
- }
232
-
233
- .nx-markdown__empty {
234
- color: var(--nx-text-muted);
235
- font-style: italic;
236
- }
237
- }
1
+ @layer nexus.components {
2
+ /*
3
+ * Markdown editor: the text and its preview inside the editor frame (Nexus.Editor.css), which brings the bar, the
4
+ * height handle, and full screen.
5
+ */
6
+ .nx-md .nx-editor__body[data-mode="split"] {
7
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
8
+ }
9
+
10
+ .nx-md .nx-editor__body[data-mode="preview"] .nx-md__input {
11
+ display: none;
12
+ }
13
+
14
+ .nx-md .nx-md__input {
15
+ height: 100%;
16
+ min-height: 0;
17
+ padding: 10px var(--nx-space-3);
18
+ border-radius: 0;
19
+ line-height: 1.6;
20
+ resize: none;
21
+ }
22
+
23
+ .nx-md--mono .nx-md__input {
24
+ font-family: var(--nx-font-mono);
25
+ font-size: calc(var(--nx-field-font) - 0.5px);
26
+ }
27
+
28
+ .nx-md__preview {
29
+ min-width: 0;
30
+ min-height: 0;
31
+ padding: 10px var(--nx-space-4);
32
+ overflow: auto;
33
+ overscroll-behavior: contain;
34
+ }
35
+
36
+ .nx-md .nx-editor__body[data-mode="split"] .nx-md__preview {
37
+ border-left: 1px solid var(--nx-border);
38
+ }
39
+
40
+ .nx-md__preview:focus-visible {
41
+ outline: 2px solid var(--nx-primary);
42
+ outline-offset: -2px;
43
+ }
44
+
45
+ @container nx-editor (width < 560px) {
46
+ .nx-md .nx-editor__body[data-mode="split"] {
47
+ grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
48
+ grid-template-columns: minmax(0, 1fr);
49
+ }
50
+
51
+ .nx-md .nx-editor__body[data-mode="split"] .nx-md__preview {
52
+ border-top: 1px solid var(--nx-border);
53
+ border-left: 0;
54
+ }
55
+ }
56
+
57
+ /*
58
+ * Markdown content (MarkdownView), in the editor's preview and anywhere else. Sizes are in em, so the text follows
59
+ * the size of the element it sits in.
60
+ */
61
+ .nx-markdown {
62
+ color: var(--nx-text);
63
+ font-size: var(--nx-text-md);
64
+ line-height: 1.65;
65
+ overflow-wrap: break-word;
66
+ }
67
+
68
+ .nx-markdown > :first-child {
69
+ margin-top: 0;
70
+ }
71
+
72
+ .nx-markdown > :last-child {
73
+ margin-bottom: 0;
74
+ }
75
+
76
+ .nx-markdown :is(p, ul, ol, blockquote, pre, hr, .nx-markdown__table) {
77
+ margin: 0 0 0.9em;
78
+ }
79
+
80
+ .nx-markdown :is(h1, h2, h3, h4, h5, h6) {
81
+ margin: 1.4em 0 0.55em;
82
+ font-weight: 650;
83
+ line-height: 1.3;
84
+ letter-spacing: -0.01em;
85
+ }
86
+
87
+ .nx-markdown :is(h1, h2) {
88
+ padding-bottom: 0.3em;
89
+ border-bottom: 1px solid var(--nx-border);
90
+ }
91
+
92
+ .nx-markdown h1 {
93
+ font-size: 1.6em;
94
+ }
95
+
96
+ .nx-markdown h2 {
97
+ font-size: 1.3em;
98
+ }
99
+
100
+ .nx-markdown h3 {
101
+ font-size: 1.12em;
102
+ }
103
+
104
+ .nx-markdown h4 {
105
+ font-size: 1em;
106
+ }
107
+
108
+ .nx-markdown h5 {
109
+ font-size: 0.9em;
110
+ }
111
+
112
+ .nx-markdown h6 {
113
+ color: var(--nx-text-muted);
114
+ font-size: 0.85em;
115
+ }
116
+
117
+ .nx-markdown a {
118
+ color: var(--nx-primary);
119
+ text-decoration: underline;
120
+ text-decoration-color: color-mix(in oklab, currentColor 40%, transparent);
121
+ text-underline-offset: 0.18em;
122
+ }
123
+
124
+ .nx-markdown a:hover {
125
+ text-decoration-color: currentColor;
126
+ }
127
+
128
+ .nx-markdown :is(ul, ol) {
129
+ padding-left: 1.6em;
130
+ }
131
+
132
+ .nx-markdown li + li {
133
+ margin-top: 0.25em;
134
+ }
135
+
136
+ .nx-markdown li > :is(ul, ol) {
137
+ margin: 0.25em 0 0;
138
+ }
139
+
140
+ .nx-markdown li > p {
141
+ margin-bottom: 0.5em;
142
+ }
143
+
144
+ /* Tasks: the box sits where the bullet would. */
145
+ .nx-markdown__task {
146
+ position: relative;
147
+ list-style: none;
148
+ }
149
+
150
+ .nx-markdown__task > input {
151
+ position: absolute;
152
+ top: 0.32em;
153
+ left: -1.45em;
154
+ width: 1em;
155
+ height: 1em;
156
+ margin: 0;
157
+ accent-color: var(--nx-primary-solid);
158
+ }
159
+
160
+ .nx-markdown__task > input:enabled {
161
+ cursor: pointer;
162
+ }
163
+
164
+ .nx-markdown blockquote {
165
+ padding: 0 0 0 1em;
166
+ border-left: 3px solid var(--nx-border-strong);
167
+ color: var(--nx-text-muted);
168
+ }
169
+
170
+ .nx-markdown code {
171
+ padding: 0.12em 0.38em;
172
+ border-radius: var(--nx-radius-sm);
173
+ background: color-mix(in oklab, var(--nx-text) 8%, transparent);
174
+ font-family: var(--nx-font-mono);
175
+ font-size: 0.875em;
176
+ }
177
+
178
+ .nx-markdown pre {
179
+ overflow: auto;
180
+ padding: 0.8em 1em;
181
+ border-radius: var(--nx-radius);
182
+ background: color-mix(in oklab, var(--nx-text) 5%, transparent);
183
+ line-height: 1.5;
184
+ }
185
+
186
+ .nx-markdown pre code {
187
+ padding: 0;
188
+ background: none;
189
+ font-size: 0.86em;
190
+ white-space: pre;
191
+ }
192
+
193
+ .nx-markdown hr {
194
+ height: 0;
195
+ margin-block: 1.4em;
196
+ border: 0;
197
+ border-top: 1px solid var(--nx-border-strong);
198
+ }
199
+
200
+ .nx-markdown img {
201
+ max-width: 100%;
202
+ height: auto;
203
+ border-radius: var(--nx-radius-sm);
204
+ vertical-align: middle;
205
+ }
206
+
207
+ .nx-markdown del {
208
+ color: var(--nx-text-muted);
209
+ }
210
+
211
+ .nx-markdown__table {
212
+ max-width: 100%;
213
+ overflow-x: auto;
214
+ }
215
+
216
+ .nx-markdown table {
217
+ border-collapse: collapse;
218
+ font-size: 0.95em;
219
+ }
220
+
221
+ .nx-markdown :is(th, td) {
222
+ padding: 0.4em 0.8em;
223
+ border: 1px solid var(--nx-border);
224
+ text-align: left;
225
+ vertical-align: top;
226
+ }
227
+
228
+ .nx-markdown th {
229
+ background: color-mix(in oklab, var(--nx-text) 4%, transparent);
230
+ font-weight: 600;
231
+ }
232
+
233
+ .nx-markdown__empty {
234
+ color: var(--nx-text-muted);
235
+ font-style: italic;
236
+ }
237
+ }