rei-kit 2.0.0 → 2.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.
@@ -0,0 +1,53 @@
1
+ //#region src/utils/inert.ts
2
+ /**
3
+ * How many open layers hold each element inert. An element set inert by the
4
+ * app itself is never in here, so releasing never undoes the app's own choice.
5
+ */
6
+ var holds = /* @__PURE__ */ new Map();
7
+ /**
8
+ * Takes everything on the page except the branch holding `keep` out of tab
9
+ * order and pointer events, and returns the function that gives it back.
10
+ *
11
+ * `inert` is a real focus trap without keydown bookkeeping, and the only one
12
+ * that also stops a screen reader's virtual cursor. It used to be applied to
13
+ * `document.getElementById('app')` — the id Vite's template happens to use —
14
+ * so an app mounted on `#root` got a dialog whose background was still
15
+ * reachable with Tab, and nothing said so. Working from `<body>`'s children
16
+ * instead holds whatever the app is mounted on, and anything else teleported
17
+ * there too.
18
+ *
19
+ * Counted per element, so a sheet opened over a sheet, or a tour over either,
20
+ * does not hand the page back when the inner one closes.
21
+ */
22
+ function inertOutside(keep) {
23
+ if (typeof document === "undefined") return () => {};
24
+ const taken = [];
25
+ for (const element of Array.from(document.body.children)) {
26
+ if (element.contains(keep)) continue;
27
+ const count = holds.get(element);
28
+ if (count === void 0) {
29
+ if (element.hasAttribute("inert")) continue;
30
+ element.setAttribute("inert", "");
31
+ }
32
+ holds.set(element, (count ?? 0) + 1);
33
+ taken.push(element);
34
+ }
35
+ let released = false;
36
+ return () => {
37
+ if (released) return;
38
+ released = true;
39
+ for (const element of taken) {
40
+ const count = (holds.get(element) ?? 1) - 1;
41
+ if (count > 0) {
42
+ holds.set(element, count);
43
+ continue;
44
+ }
45
+ holds.delete(element);
46
+ element.removeAttribute("inert");
47
+ }
48
+ };
49
+ }
50
+ //#endregion
51
+ export { inertOutside as t };
52
+
53
+ //# sourceMappingURL=inert-B441LoCD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inert-B441LoCD.js","names":[],"sources":["../src/utils/inert.ts"],"sourcesContent":["/**\n * How many open layers hold each element inert. An element set inert by the\n * app itself is never in here, so releasing never undoes the app's own choice.\n */\nconst holds = new Map<Element, number>()\n\n/**\n * Takes everything on the page except the branch holding `keep` out of tab\n * order and pointer events, and returns the function that gives it back.\n *\n * `inert` is a real focus trap without keydown bookkeeping, and the only one\n * that also stops a screen reader's virtual cursor. It used to be applied to\n * `document.getElementById('app')` — the id Vite's template happens to use —\n * so an app mounted on `#root` got a dialog whose background was still\n * reachable with Tab, and nothing said so. Working from `<body>`'s children\n * instead holds whatever the app is mounted on, and anything else teleported\n * there too.\n *\n * Counted per element, so a sheet opened over a sheet, or a tour over either,\n * does not hand the page back when the inner one closes.\n */\nexport function inertOutside(keep: Element): () => void {\n if (typeof document === 'undefined') return () => {}\n\n const taken: Element[] = []\n\n for (const element of Array.from(document.body.children)) {\n if (element.contains(keep)) continue\n\n const count = holds.get(element)\n if (count === undefined) {\n if (element.hasAttribute('inert')) continue\n element.setAttribute('inert', '')\n }\n holds.set(element, (count ?? 0) + 1)\n taken.push(element)\n }\n\n let released = false\n\n return () => {\n if (released) return\n released = true\n\n for (const element of taken) {\n const count = (holds.get(element) ?? 1) - 1\n if (count > 0) {\n holds.set(element, count)\n continue\n }\n holds.delete(element)\n element.removeAttribute('inert')\n }\n }\n}\n"],"mappings":";;;;;AAIA,IAAM,wBAAQ,IAAI,IAAqB;;;;;;;;;;;;;;;;AAiBvC,SAAgB,aAAa,MAA2B;CACtD,IAAI,OAAO,aAAa,aAAa,aAAa,CAAC;CAEnD,MAAM,QAAmB,CAAC;CAE1B,KAAK,MAAM,WAAW,MAAM,KAAK,SAAS,KAAK,QAAQ,GAAG;EACxD,IAAI,QAAQ,SAAS,IAAI,GAAG;EAE5B,MAAM,QAAQ,MAAM,IAAI,OAAO;EAC/B,IAAI,UAAU,KAAA,GAAW;GACvB,IAAI,QAAQ,aAAa,OAAO,GAAG;GACnC,QAAQ,aAAa,SAAS,EAAE;EAClC;EACA,MAAM,IAAI,UAAU,SAAS,KAAK,CAAC;EACnC,MAAM,KAAK,OAAO;CACpB;CAEA,IAAI,WAAW;CAEf,aAAa;EACX,IAAI,UAAU;EACd,WAAW;EAEX,KAAK,MAAM,WAAW,OAAO;GAC3B,MAAM,SAAS,MAAM,IAAI,OAAO,KAAK,KAAK;GAC1C,IAAI,QAAQ,GAAG;IACb,MAAM,IAAI,SAAS,KAAK;IACxB;GACF;GACA,MAAM,OAAO,OAAO;GACpB,QAAQ,gBAAgB,OAAO;EACjC;CACF;AACF"}
@@ -0,0 +1,27 @@
1
+ /* rei-kit, everything, for a phone-shaped app: the 430px column and the tab slides.
2
+ *
3
+ * @import 'tailwindcss';
4
+ * @import 'rei-kit/mobile.css';
5
+ *
6
+ * Two lines instead of seven, and the seven had a trap in them: Tailwind only
7
+ * builds classes it has seen, and it never looks in node_modules on its own,
8
+ * so every app had to write an `@source` with the right number of `../` for
9
+ * wherever its stylesheet happened to sit. Get it wrong and nothing fails —
10
+ * the components mount and render unstyled.
11
+ *
12
+ * Here the `@source` sits next to the files it points at, and Tailwind
13
+ * resolves it from this file, so it is right wherever the app is.
14
+ *
15
+ * Only the compiled JavaScript is scanned. The source maps and the type
16
+ * declarations mention classes too — in examples, in comments — and scanning
17
+ * them built rules no component uses.
18
+ *
19
+ * Want less? The parts are still importable one by one, and `web.css` is
20
+ * the same for a web app. Import one preset, never both. */
21
+ @import './tokens.css';
22
+ @import './shell/mobile.css';
23
+ @import './materials.css';
24
+ @import './palettes.css';
25
+ @import './styles.css';
26
+
27
+ @source './**/*.js';
package/dist/styles.css CHANGED
@@ -1,26 +1,26 @@
1
1
 
2
- .sheet-enter-active[data-v-6194b8f4],
3
- .sheet-leave-active[data-v-6194b8f4] {
2
+ .sheet-enter-active[data-v-2855eea3],
3
+ .sheet-leave-active[data-v-2855eea3] {
4
4
  transition: opacity var(--duration-base) ease;
5
5
  }
6
- .sheet-enter-from[data-v-6194b8f4],
7
- .sheet-leave-to[data-v-6194b8f4] {
6
+ .sheet-enter-from[data-v-2855eea3],
7
+ .sheet-leave-to[data-v-2855eea3] {
8
8
  opacity: 0;
9
9
  }
10
10
 
11
11
  /* The panel travels further than the scrim fades, which is what makes the
12
12
  sheet read as rising rather than appearing. */
13
- .sheet-enter-active .sheet-panel[data-v-6194b8f4],
14
- .sheet-leave-active .sheet-panel[data-v-6194b8f4] {
13
+ .sheet-enter-active .sheet-panel[data-v-2855eea3],
14
+ .sheet-leave-active .sheet-panel[data-v-2855eea3] {
15
15
  transition: transform var(--duration-slow) var(--ease-sheet);
16
16
  }
17
- .sheet-enter-from .sheet-panel[data-v-6194b8f4],
18
- .sheet-leave-to .sheet-panel[data-v-6194b8f4] {
17
+ .sheet-enter-from .sheet-panel[data-v-2855eea3],
18
+ .sheet-leave-to .sheet-panel[data-v-2855eea3] {
19
19
  transform: translateY(6%);
20
20
  }
21
21
  @media (prefers-reduced-motion: reduce) {
22
- .sheet-enter-from .sheet-panel[data-v-6194b8f4],
23
- .sheet-leave-to .sheet-panel[data-v-6194b8f4] {
22
+ .sheet-enter-from .sheet-panel[data-v-2855eea3],
23
+ .sheet-leave-to .sheet-panel[data-v-2855eea3] {
24
24
  transform: none;
25
25
  }
26
26
  }
@@ -209,12 +209,12 @@
209
209
  cannot reach slot content, which belongs to the caller's scope, so
210
210
  `.tour-forward-*` and `.tour-backward-*` ship unscoped in
211
211
  `rei-kit/shell/mobile.css` where the caller's slide can actually see them. */
212
- .tour-enter-active[data-v-3bbf95fc],
213
- .tour-leave-active[data-v-3bbf95fc] {
212
+ .tour-enter-active[data-v-88982fee],
213
+ .tour-leave-active[data-v-88982fee] {
214
214
  transition: opacity var(--duration-base) ease;
215
215
  }
216
- .tour-enter-from[data-v-3bbf95fc],
217
- .tour-leave-to[data-v-3bbf95fc] {
216
+ .tour-enter-from[data-v-88982fee],
217
+ .tour-leave-to[data-v-88982fee] {
218
218
  opacity: 0;
219
219
  }
220
220
 
@@ -650,7 +650,7 @@ to {
650
650
  /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
651
651
  @layer properties {
652
652
  @supports (((-webkit-hyphens: none)) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color: rgb(from red r g b)))) {
653
- [data-v-e9bd0632],[data-v-e9bd0632]:before,[data-v-e9bd0632]:after,[data-v-e9bd0632]::backdrop {
653
+ [data-v-a76891c4],[data-v-a76891c4]:before,[data-v-a76891c4]:after,[data-v-a76891c4]::backdrop {
654
654
  --tw-translate-x: 0;
655
655
  --tw-translate-y: 0;
656
656
  --tw-translate-z: 0;
@@ -664,7 +664,7 @@ to {
664
664
  }
665
665
  }
666
666
  }
667
- .tab-bar[data-v-e9bd0632] {
667
+ .tab-bar[data-v-a76891c4] {
668
668
  z-index: 40;
669
669
  --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);
670
670
  width: 100%;
@@ -675,18 +675,18 @@ to {
675
675
  bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
676
676
  position: absolute;
677
677
  }
678
- .tab-bar-inner[data-v-e9bd0632] {
678
+ .tab-bar-inner[data-v-a76891c4] {
679
679
  justify-content: space-between;
680
680
  align-items: center;
681
681
  gap: var(--spacing, .25rem);
682
682
  display: flex;
683
683
  }
684
684
  @supports (color: color-mix(in lab, red, red)) {
685
- .tab-bar-inner[data-v-e9bd0632] {
685
+ .tab-bar-inner[data-v-a76891c4] {
686
686
  background-color: color-mix(in oklab, var(--color-surface) var(--surface-opacity), transparent);
687
687
  }
688
688
  }
689
- .tab-bar-inner[data-v-e9bd0632] {
689
+ .tab-bar-inner[data-v-a76891c4] {
690
690
  border: var(--surface-border-width) solid var(--surface-border-color);
691
691
  box-shadow: var(--shadow-raised);
692
692
  -webkit-backdrop-filter: var(--surface-backdrop);
@@ -694,15 +694,15 @@ to {
694
694
  background-color: #fff;
695
695
  }
696
696
  @supports (color: color-mix(in lab, red, red)) {
697
- .tab-bar-inner[data-v-e9bd0632] {
697
+ .tab-bar-inner[data-v-a76891c4] {
698
698
  background-color: color-mix(in oklab, var(--color-surface) min(var(--surface-opacity), 88%), transparent);
699
699
  }
700
700
  }
701
- .tab-bar-inner[data-v-e9bd0632] {
701
+ .tab-bar-inner[data-v-a76891c4] {
702
702
  -webkit-backdrop-filter: var(--surface-backdrop, blur(12px));
703
703
  border-radius: var(--radius-shell);
704
704
  }
705
- .tab-link[data-v-e9bd0632] {
705
+ .tab-link[data-v-a76891c4] {
706
706
  cursor: pointer;
707
707
  justify-content: center;
708
708
  align-items: center;
@@ -710,16 +710,22 @@ to {
710
710
  min-height: 52px;
711
711
  padding-block: calc(var(--spacing, .25rem) * 1.5);
712
712
  color: var(--color-ink-soft, #5c7480);
713
- border-radius: calc(var(--radius-shell) - 6px);
714
- transition: color var(--duration-base) ease;
715
713
  flex-direction: column;
716
714
  flex: 1;
717
715
  display: flex;
718
716
  }
719
- .tab-link[data-v-e9bd0632]:hover {
717
+ .tab-link[data-v-a76891c4]:focus-visible {
718
+ outline: 2px solid var(--color-primary);
719
+ outline-offset: 2px;
720
+ }
721
+ .tab-link[data-v-a76891c4] {
722
+ border-radius: calc(var(--radius-shell) - 6px);
723
+ transition: color var(--duration-base) ease;
724
+ }
725
+ .tab-link[data-v-a76891c4]:hover {
720
726
  color: var(--color-ink, #0f2229);
721
727
  }
722
- .tab-icon-slot[data-v-e9bd0632] {
728
+ .tab-icon-slot[data-v-a76891c4] {
723
729
  height: calc(var(--spacing, .25rem) * 7);
724
730
  width: calc(var(--spacing, .25rem) * 12);
725
731
  transition-property: all;
@@ -734,16 +740,16 @@ to {
734
740
  align-items: center;
735
741
  display: flex;
736
742
  }
737
- .tab-link:active .tab-icon-slot[data-v-e9bd0632] {
743
+ .tab-link:active .tab-icon-slot[data-v-a76891c4] {
738
744
  transform: scale(.88);
739
745
  }
740
- .is-active[data-v-e9bd0632] {
746
+ .is-active[data-v-a76891c4] {
741
747
  color: var(--color-primary, #26667f);
742
748
  }
743
- .is-active .tab-icon-slot[data-v-e9bd0632] {
749
+ .is-active .tab-icon-slot[data-v-a76891c4] {
744
750
  background-color: var(--color-muted, #ddf4e7);
745
751
  }
746
- .tab-icon[data-v-e9bd0632] {
752
+ .tab-icon[data-v-a76891c4] {
747
753
  stroke-width: 2px;
748
754
  width: 18px;
749
755
  height: 18px;
@@ -753,29 +759,29 @@ to {
753
759
  --tw-duration: var(--duration-base);
754
760
  transition-duration: var(--duration-base);
755
761
  }
756
- .is-active .tab-icon[data-v-e9bd0632] {
762
+ .is-active .tab-icon[data-v-a76891c4] {
757
763
  --tw-scale-x: 110%;
758
764
  --tw-scale-y: 110%;
759
765
  --tw-scale-z: 110%;
760
766
  scale: var(--tw-scale-x) var(--tw-scale-y);
761
767
  stroke-width: 2.5px;
762
768
  }
763
- .tab-label[data-v-e9bd0632] {
769
+ .tab-label[data-v-a76891c4] {
764
770
  --tw-leading: 1;
765
771
  --tw-font-weight: var(--font-weight-medium, 500);
766
772
  font-size: 10px;
767
773
  line-height: 1;
768
774
  font-weight: var(--font-weight-medium, 500);
769
775
  }
770
- .is-active .tab-label[data-v-e9bd0632] {
776
+ .is-active .tab-label[data-v-a76891c4] {
771
777
  --tw-font-weight: var(--font-weight-semibold, 600);
772
778
  font-weight: var(--font-weight-semibold, 600);
773
779
  }
774
780
  @media (prefers-reduced-motion: reduce) {
775
- .tab-icon-slot[data-v-e9bd0632], .tab-icon[data-v-e9bd0632] {
781
+ .tab-icon-slot[data-v-a76891c4], .tab-icon[data-v-a76891c4] {
776
782
  transition: none;
777
783
  }
778
- .tab-link:active .tab-icon-slot[data-v-e9bd0632] {
784
+ .tab-link:active .tab-icon-slot[data-v-a76891c4] {
779
785
  transform: none;
780
786
  }
781
787
  }
@@ -1087,7 +1093,7 @@ to {
1087
1093
  }
1088
1094
  }
1089
1095
 
1090
- .rk-modal-scrim[data-v-c6537cc8] {
1096
+ .rk-modal-scrim[data-v-61956691] {
1091
1097
  position: fixed;
1092
1098
  inset: 0;
1093
1099
  z-index: 50;
@@ -1097,7 +1103,7 @@ to {
1097
1103
  background: color-mix(in srgb, var(--color-ink) 70%, transparent);
1098
1104
  backdrop-filter: blur(4px);
1099
1105
  }
1100
- .rk-modal-panel[data-v-c6537cc8] {
1106
+ .rk-modal-panel[data-v-61956691] {
1101
1107
  width: 100%;
1102
1108
  max-width: 28rem;
1103
1109
  max-height: 85vh;
@@ -1105,21 +1111,21 @@ to {
1105
1111
  border-radius: var(--radius-card);
1106
1112
  padding: 1.5rem;
1107
1113
  }
1108
- .rk-modal-panel[data-v-c6537cc8]:focus {
1114
+ .rk-modal-panel[data-v-61956691]:focus {
1109
1115
  outline: none;
1110
1116
  }
1111
- .rk-modal-head[data-v-c6537cc8] {
1117
+ .rk-modal-head[data-v-61956691] {
1112
1118
  display: flex;
1113
1119
  align-items: flex-start;
1114
1120
  justify-content: space-between;
1115
1121
  gap: 1rem;
1116
1122
  }
1117
- .rk-modal-title[data-v-c6537cc8] {
1123
+ .rk-modal-title[data-v-61956691] {
1118
1124
  font-size: 1.0625rem;
1119
1125
  font-weight: 600;
1120
1126
  color: var(--color-ink);
1121
1127
  }
1122
- .rk-modal-close[data-v-c6537cc8] {
1128
+ .rk-modal-close[data-v-61956691] {
1123
1129
  display: grid;
1124
1130
  place-items: center;
1125
1131
  flex-shrink: 0;
@@ -1129,58 +1135,58 @@ to {
1129
1135
  color: var(--color-ink-soft);
1130
1136
  transition: background-color var(--duration-fast);
1131
1137
  }
1132
- .rk-modal-close[data-v-c6537cc8]:hover {
1138
+ .rk-modal-close[data-v-61956691]:hover {
1133
1139
  background: var(--color-muted);
1134
1140
  }
1135
- .rk-modal-close[data-v-c6537cc8]:focus-visible {
1141
+ .rk-modal-close[data-v-61956691]:focus-visible {
1136
1142
  outline: 2px solid var(--color-primary);
1137
1143
  outline-offset: 2px;
1138
1144
  }
1139
- .rk-modal-close svg[data-v-c6537cc8] {
1145
+ .rk-modal-close svg[data-v-61956691] {
1140
1146
  width: 1rem;
1141
1147
  height: 1rem;
1142
1148
  }
1143
- .rk-modal-body[data-v-c6537cc8] {
1149
+ .rk-modal-body[data-v-61956691] {
1144
1150
  margin-top: 0.75rem;
1145
1151
  color: var(--color-ink-soft);
1146
1152
  font-size: 0.875rem;
1147
1153
  line-height: 1.625;
1148
1154
  }
1149
- .rk-modal-actions[data-v-c6537cc8] {
1155
+ .rk-modal-actions[data-v-61956691] {
1150
1156
  margin-top: 1.5rem;
1151
1157
  display: flex;
1152
1158
  justify-content: flex-end;
1153
1159
  gap: 0.5rem;
1154
1160
  }
1155
- .rk-modal-enter-active[data-v-c6537cc8],
1156
- .rk-modal-leave-active[data-v-c6537cc8] {
1161
+ .rk-modal-enter-active[data-v-61956691],
1162
+ .rk-modal-leave-active[data-v-61956691] {
1157
1163
  transition: opacity var(--duration-base) ease;
1158
1164
  }
1159
- .rk-modal-enter-active .rk-modal-panel[data-v-c6537cc8],
1160
- .rk-modal-leave-active .rk-modal-panel[data-v-c6537cc8] {
1165
+ .rk-modal-enter-active .rk-modal-panel[data-v-61956691],
1166
+ .rk-modal-leave-active .rk-modal-panel[data-v-61956691] {
1161
1167
  transition:
1162
1168
  transform var(--duration-base) var(--ease-sheet),
1163
1169
  opacity var(--duration-base) ease;
1164
1170
  }
1165
- .rk-modal-enter-from[data-v-c6537cc8],
1166
- .rk-modal-leave-to[data-v-c6537cc8] {
1171
+ .rk-modal-enter-from[data-v-61956691],
1172
+ .rk-modal-leave-to[data-v-61956691] {
1167
1173
  opacity: 0;
1168
1174
  }
1169
1175
 
1170
1176
  /* From nowhere, not from an edge: a scale is what separates this from a sheet. */
1171
- .rk-modal-enter-from .rk-modal-panel[data-v-c6537cc8],
1172
- .rk-modal-leave-to .rk-modal-panel[data-v-c6537cc8] {
1177
+ .rk-modal-enter-from .rk-modal-panel[data-v-61956691],
1178
+ .rk-modal-leave-to .rk-modal-panel[data-v-61956691] {
1173
1179
  transform: scale(0.96);
1174
1180
  opacity: 0;
1175
1181
  }
1176
1182
  @media (prefers-reduced-motion: reduce) {
1177
- .rk-modal-enter-active .rk-modal-panel[data-v-c6537cc8],
1178
- .rk-modal-leave-active .rk-modal-panel[data-v-c6537cc8] {
1183
+ .rk-modal-enter-active .rk-modal-panel[data-v-61956691],
1184
+ .rk-modal-leave-active .rk-modal-panel[data-v-61956691] {
1179
1185
  transition: opacity var(--duration-base) ease;
1180
1186
  transform: none;
1181
1187
  }
1182
- .rk-modal-enter-from .rk-modal-panel[data-v-c6537cc8],
1183
- .rk-modal-leave-to .rk-modal-panel[data-v-c6537cc8] {
1188
+ .rk-modal-enter-from .rk-modal-panel[data-v-61956691],
1189
+ .rk-modal-leave-to .rk-modal-panel[data-v-61956691] {
1184
1190
  transform: none;
1185
1191
  }
1186
1192
  }
@@ -1231,32 +1237,32 @@ to {
1231
1237
  color: var(--color-ink-soft);
1232
1238
  }
1233
1239
 
1234
- .rk-tabs[data-v-2a18b30e] {
1240
+ .rk-tabs[data-v-8135ecab] {
1235
1241
  display: flex;
1236
1242
  align-items: center;
1237
1243
  gap: 0.25rem;
1238
1244
  border-bottom: 1px solid color-mix(in srgb, var(--color-hair) 70%, transparent);
1239
1245
  }
1240
- .rk-tab[data-v-2a18b30e] {
1246
+ .rk-tab[data-v-8135ecab] {
1241
1247
  position: relative;
1242
1248
  padding: 0.625rem 0.875rem;
1243
1249
  font-size: 0.875rem;
1244
1250
  color: var(--color-ink-soft);
1245
1251
  transition: color var(--duration-fast);
1246
1252
  }
1247
- .rk-tab[data-v-2a18b30e]:hover {
1253
+ .rk-tab[data-v-8135ecab]:hover {
1248
1254
  color: var(--color-ink);
1249
1255
  }
1250
- .rk-tab[data-v-2a18b30e]:focus-visible {
1256
+ .rk-tab[data-v-8135ecab]:focus-visible {
1251
1257
  outline: 2px solid var(--color-primary);
1252
1258
  outline-offset: -2px;
1253
1259
  border-radius: var(--radius-cell);
1254
1260
  }
1255
- .rk-tab.is-active[data-v-2a18b30e] {
1261
+ .rk-tab.is-active[data-v-8135ecab] {
1256
1262
  color: var(--color-ink);
1257
1263
  font-weight: 500;
1258
1264
  }
1259
- .rk-tab.is-active[data-v-2a18b30e]::after {
1265
+ .rk-tab.is-active[data-v-8135ecab]::after {
1260
1266
  content: '';
1261
1267
  position: absolute;
1262
1268
  inset-inline: 0.5rem;
@@ -1265,10 +1271,10 @@ to {
1265
1271
  border-radius: 9999px;
1266
1272
  background: var(--color-primary);
1267
1273
  }
1268
- .rk-tabpanel[data-v-2a18b30e] {
1274
+ .rk-tabpanel[data-v-8135ecab] {
1269
1275
  padding-top: 1rem;
1270
1276
  }
1271
- .rk-tabpanel[data-v-2a18b30e]:focus-visible {
1277
+ .rk-tabpanel[data-v-8135ecab]:focus-visible {
1272
1278
  outline: 2px solid var(--color-primary);
1273
1279
  outline-offset: 2px;
1274
1280
  }
package/dist/tokens.css CHANGED
@@ -298,6 +298,20 @@
298
298
  background-attachment: fixed;
299
299
  }
300
300
 
301
+ /* The keyboard focus ring, in one place.
302
+
303
+ Every raw control the kit renders carries this or states its own ring. A
304
+ control without one is invisible to anyone moving through the page with
305
+ Tab — `SegmentedControl` shipped that way, its real input hidden and its
306
+ visible pill never told it had focus. Only `:focus-visible`, so a mouse
307
+ click draws nothing. */
308
+ @utility focus-ring {
309
+ &:focus-visible {
310
+ outline: 2px solid var(--color-primary);
311
+ outline-offset: 2px;
312
+ }
313
+ }
314
+
301
315
  /* Scrolling stays, the bar goes. On a narrow column a visible track reads as a
302
316
  stray line rather than as a control. */
303
317
  @utility no-scrollbar {
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Takes everything on the page except the branch holding `keep` out of tab
3
+ * order and pointer events, and returns the function that gives it back.
4
+ *
5
+ * `inert` is a real focus trap without keydown bookkeeping, and the only one
6
+ * that also stops a screen reader's virtual cursor. It used to be applied to
7
+ * `document.getElementById('app')` — the id Vite's template happens to use —
8
+ * so an app mounted on `#root` got a dialog whose background was still
9
+ * reachable with Tab, and nothing said so. Working from `<body>`'s children
10
+ * instead holds whatever the app is mounted on, and anything else teleported
11
+ * there too.
12
+ *
13
+ * Counted per element, so a sheet opened over a sheet, or a tour over either,
14
+ * does not hand the page back when the inner one closes.
15
+ */
16
+ export declare function inertOutside(keep: Element): () => void;
package/dist/web.css ADDED
@@ -0,0 +1,27 @@
1
+ /* rei-kit, everything, for a wide site: a column with gutters and a page fade.
2
+ *
3
+ * @import 'tailwindcss';
4
+ * @import 'rei-kit/web.css';
5
+ *
6
+ * Two lines instead of seven, and the seven had a trap in them: Tailwind only
7
+ * builds classes it has seen, and it never looks in node_modules on its own,
8
+ * so every app had to write an `@source` with the right number of `../` for
9
+ * wherever its stylesheet happened to sit. Get it wrong and nothing fails —
10
+ * the components mount and render unstyled.
11
+ *
12
+ * Here the `@source` sits next to the files it points at, and Tailwind
13
+ * resolves it from this file, so it is right wherever the app is.
14
+ *
15
+ * Only the compiled JavaScript is scanned. The source maps and the type
16
+ * declarations mention classes too — in examples, in comments — and scanning
17
+ * them built rules no component uses.
18
+ *
19
+ * Want less? The parts are still importable one by one, and `mobile.css` is
20
+ * the same for a mobile app. Import one preset, never both. */
21
+ @import './tokens.css';
22
+ @import './shell/web.css';
23
+ @import './materials.css';
24
+ @import './palettes.css';
25
+ @import './styles.css';
26
+
27
+ @source './**/*.js';
package/dist/web.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BOaGB7Aw.js";
2
+ import { t as inertOutside } from "./inert-B441LoCD.js";
2
3
  import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeModels, nextTick, normalizeClass, onBeforeUnmount, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, unref, useId, useModel, vShow, watch, withCtx, withDirectives, withModifiers } from "vue";
3
4
  import { RouterLink } from "vue-router";
4
5
  //#region src/web/BaseAccordion.vue?vue&type=script&setup=true&lang.ts
@@ -214,6 +215,8 @@ var BaseModal_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
214
215
  const panel = ref(null);
215
216
  /** Who had focus before this opened, so it can be given back. */
216
217
  let restoreTo = null;
218
+ /** Gives the page behind back; set while open. */
219
+ let releaseInert = null;
217
220
  function focusable() {
218
221
  if (!panel.value) return [];
219
222
  return Array.from(panel.value.querySelectorAll(FOCUSABLE));
@@ -243,15 +246,19 @@ var BaseModal_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
243
246
  restoreTo = document.activeElement;
244
247
  document.body.style.overflow = "hidden";
245
248
  await nextTick();
249
+ if (panel.value) releaseInert = inertOutside(panel.value);
246
250
  (focusable()[0] ?? panel.value)?.focus();
247
251
  } else {
248
252
  document.body.style.overflow = "";
253
+ releaseInert?.();
254
+ releaseInert = null;
249
255
  restoreTo?.focus();
250
256
  restoreTo = null;
251
257
  }
252
258
  });
253
259
  onBeforeUnmount(() => {
254
260
  if (open.value) document.body.style.overflow = "";
261
+ releaseInert?.();
255
262
  });
256
263
  return (_ctx, _cache) => {
257
264
  return openBlock(), createBlock(Teleport, { to: "body" }, [createVNode(Transition, { name: "rk-modal" }, {
@@ -291,7 +298,7 @@ var BaseModal_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
291
298
  })]);
292
299
  };
293
300
  }
294
- }), [["__scopeId", "data-v-c6537cc8"]]);
301
+ }), [["__scopeId", "data-v-61956691"]]);
295
302
  //#endregion
296
303
  //#region src/web/BasePagination.vue?vue&type=script&setup=true&lang.ts
297
304
  var _hoisted_1$3 = ["aria-label"];
@@ -443,6 +450,7 @@ var BaseTabs_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
443
450
  onKeydown
444
451
  }, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item) => {
445
452
  return openBlock(), createElementBlock("button", {
453
+ id: tabId(item.key),
446
454
  key: item.key,
447
455
  ref_for: true,
448
456
  ref_key: "tabs",
@@ -450,7 +458,6 @@ var BaseTabs_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
450
458
  type: "button",
451
459
  role: "tab",
452
460
  class: normalizeClass(["rk-tab", { "is-active": item.key === active.value }]),
453
- id: tabId(item.key),
454
461
  "aria-selected": item.key === active.value,
455
462
  "aria-controls": panelId(item.key),
456
463
  tabindex: item.key === active.value ? 0 : -1,
@@ -458,10 +465,10 @@ var BaseTabs_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
458
465
  }, toDisplayString(item.label), 11, _hoisted_2$2);
459
466
  }), 128))], 40, _hoisted_1$2), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item) => {
460
467
  return withDirectives((openBlock(), createElementBlock("div", {
468
+ id: panelId(item.key),
461
469
  key: item.key,
462
470
  role: "tabpanel",
463
471
  class: "rk-tabpanel",
464
- id: panelId(item.key),
465
472
  "aria-labelledby": tabId(item.key),
466
473
  tabindex: "0"
467
474
  }, [renderSlot(_ctx.$slots, "default", {
@@ -471,7 +478,7 @@ var BaseTabs_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
471
478
  }), 128))]);
472
479
  };
473
480
  }
474
- }), [["__scopeId", "data-v-2a18b30e"]]);
481
+ }), [["__scopeId", "data-v-8135ecab"]]);
475
482
  //#endregion
476
483
  //#region src/web/BaseTooltip.vue?vue&type=script&setup=true&lang.ts
477
484
  var _hoisted_1$1 = { class: "rk-tip" };