rei-kit 0.17.2 → 0.18.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/README.md CHANGED
@@ -44,14 +44,14 @@ the app, and not a matter of taste.
44
44
 
45
45
  ## Status
46
46
 
47
- **v0.17.2 — three consumers.**
48
-
49
- | | |
50
- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
51
- | Components | 37 (`AuthForm`, `TabShell`, `BaseModal`, `BaseAccordion`, `NavLinks`, `OfflineBanner`, `FabButton`, `BaseButton`, `BaseCard`, `BaseInput`, `BaseSelect`, `BaseTextarea`, `BaseCheckbox`, `BaseRadioGroup`, `BaseAlert`, `BaseBadge`, `BaseSheet`, `ProgressBar`, `PriceCard`, `ToastHost`, `TabBar`, `GoogleButton`, `LocaleLinks`, `LocaleSheet`, `AuthShell`, `TourShell`, `InstallPrompt`, `UpdatePrompt`, `InstallSettings`, `SkeletonList`, `PageContainer`, `ErrorBoundary`, etc.) |
52
- | Composables | 14 (`useToast`, `useTheme`, `useToday`, `useMediaQuery`, `useInstall`, `watchInstallability`, `createTabTransition`, `useThemeSync`, `useVisualViewport`, etc.) |
53
- | Utilities | 27 (`applyTheme`, `formatDate`, `fieldErrors`, `toAuthMessageKey`, `createAuthGuard`, `createQueryDefaults`, `createWriteReport`, `toRedirectPath`, `Supabase error mapper`, i18n runtime, etc.) |
54
- | Entry Points | `rei-kit`, `rei-kit/app`, `rei-kit/web`, `rei-kit/pwa`, `rei-kit/shell/mobile.css`, `rei-kit/shell/web.css` |
47
+ **v0.18.1 — three consumers.**
48
+
49
+ | | |
50
+ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
51
+ | Components | 42 (`AuthForm`, `TabShell`, `BaseModal`, `BaseTabs`, `BaseTooltip`, `BasePagination`, `BaseBreadcrumb`, `BaseDisclosure`, `BaseAccordion`, `NavLinks`, `OfflineBanner`, `FabButton`, `BaseButton`, `BaseCard`, `BaseInput`, `BaseSelect`, `BaseTextarea`, `BaseCheckbox`, `BaseRadioGroup`, `BaseAlert`, `BaseBadge`, `BaseSheet`, `ProgressBar`, `PriceCard`, `ToastHost`, `TabBar`, `GoogleButton`, `LocaleLinks`, `LocaleSheet`, `AuthShell`, `TourShell`, `InstallPrompt`, `UpdatePrompt`, `InstallSettings`, `SkeletonList`, `PageContainer`, `ErrorBoundary`, etc.) |
52
+ | Composables | 14 (`useToast`, `useTheme`, `useToday`, `useMediaQuery`, `useInstall`, `watchInstallability`, `createTabTransition`, `useThemeSync`, `useVisualViewport`, etc.) |
53
+ | Utilities | 27 (`applyTheme`, `formatDate`, `fieldErrors`, `toAuthMessageKey`, `createAuthGuard`, `createQueryDefaults`, `createWriteReport`, `toRedirectPath`, `Supabase error mapper`, i18n runtime, etc.) |
54
+ | Entry Points | `rei-kit`, `rei-kit/app`, `rei-kit/web`, `rei-kit/pwa`, `rei-kit/shell/mobile.css`, `rei-kit/shell/web.css` |
55
55
 
56
56
  | | |
57
57
  | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
package/dist/index.js CHANGED
@@ -1342,7 +1342,7 @@ function createI18nRuntime(options) {
1342
1342
  *
1343
1343
  * The fallback keeps `vitest` and `vite dev` honest, where no define runs.
1344
1344
  */
1345
- var VERSION = "0.17.2";
1345
+ var VERSION = "0.18.1";
1346
1346
  //#endregion
1347
1347
  export { AppError, BaseAlert_default as BaseAlert, BaseBadge_default as BaseBadge, BaseButton_default as BaseButton, BaseCard_default as BaseCard, BaseCheckbox_default as BaseCheckbox, BaseInput_default as BaseInput, BaseRadioGroup_default as BaseRadioGroup, BaseSelect_default as BaseSelect, BaseSheet_default as BaseSheet, BaseTextarea_default as BaseTextarea, EmptyState_default as EmptyState, ErrorBoundary_default as ErrorBoundary, FormField_default as FormField, GoogleButton_default as GoogleButton, LocaleLinks_default as LocaleLinks, PageContainer_default as PageContainer, PageHeader_default as PageHeader, PriceCard_default as PriceCard, ProgressBar_default as ProgressBar, SectionHeading_default as SectionHeading, SegmentedControl_default as SegmentedControl, SettingsGroup_default as SettingsGroup, SettingsRow_default as SettingsRow, SkeletonList_default as SkeletonList, StatCard_default as StatCard, TabBar_default as TabBar, ToastHost_default as ToastHost, ToneDot_default as ToneDot, VERSION, addDays, applyTheme, createI18nRuntime, downloadJson, eachDayOfYear, formatDate, fromDateKey, isApplePortable, isInstalled, isThemePreference, lastNDays, leadingBlanks, needsIosInstall, readStoredTheme, registerErrorMapper, relativeDayLabel, safeRedirect, setFormatLocale, setThemeStorageKey, startOfWeek, tapFeedback, toAppError, toDateKey, toRedirectPath, todayKey, useDebouncedCallback, useDragScroll, useMediaQuery, useOnline, useTheme, useToast, useToday, useVisualViewport };
1348
1348
 
package/dist/styles.css CHANGED
@@ -617,13 +617,13 @@
617
617
  }
618
618
  }
619
619
 
620
- .rk-accordion[data-v-00091812] {
620
+ .rk-accordion[data-v-d7bddb65] {
621
621
  border-top: 1px solid color-mix(in srgb, var(--color-hair) 70%, transparent);
622
622
  }
623
- .rk-accordion-item[data-v-00091812] {
623
+ .rk-accordion-item[data-v-d7bddb65] {
624
624
  border-bottom: 1px solid color-mix(in srgb, var(--color-hair) 70%, transparent);
625
625
  }
626
- .rk-accordion-control[data-v-00091812] {
626
+ .rk-accordion-control[data-v-d7bddb65] {
627
627
  display: flex;
628
628
  width: 100%;
629
629
  cursor: pointer;
@@ -634,19 +634,19 @@
634
634
  text-align: left;
635
635
  transition: color 150ms;
636
636
  }
637
- .rk-accordion-control[data-v-00091812]:hover {
637
+ .rk-accordion-control[data-v-d7bddb65]:hover {
638
638
  color: var(--color-primary);
639
639
  }
640
- .rk-accordion-control[data-v-00091812]:focus-visible {
640
+ .rk-accordion-control[data-v-d7bddb65]:focus-visible {
641
641
  outline: 2px solid var(--color-primary);
642
642
  outline-offset: 2px;
643
643
  }
644
- .rk-accordion-title[data-v-00091812] {
644
+ .rk-accordion-title[data-v-d7bddb65] {
645
645
  color: var(--color-ink);
646
646
  font-size: 1rem;
647
647
  font-weight: 500;
648
648
  }
649
- .rk-accordion-mark[data-v-00091812] {
649
+ .rk-accordion-mark[data-v-d7bddb65] {
650
650
  position: relative;
651
651
  display: grid;
652
652
  place-items: center;
@@ -654,34 +654,34 @@
654
654
  width: 1.5rem;
655
655
  height: 1.5rem;
656
656
  }
657
- .rk-accordion-bar[data-v-00091812] {
657
+ .rk-accordion-bar[data-v-d7bddb65] {
658
658
  position: absolute;
659
659
  height: 1px;
660
660
  width: 0.875rem;
661
661
  background: var(--color-ink-soft);
662
662
  }
663
- .rk-accordion-bar-turn[data-v-00091812] {
663
+ .rk-accordion-bar-turn[data-v-d7bddb65] {
664
664
  transform: rotate(90deg);
665
665
  transition: transform 420ms ease-out;
666
666
  }
667
- .rk-accordion-bar-turn.is-open[data-v-00091812] {
667
+ .rk-accordion-bar-turn.is-open[data-v-d7bddb65] {
668
668
  transform: rotate(0deg);
669
669
  }
670
670
 
671
671
  /* 0fr to 1fr is the whole trick: a grid row can be animated to a height that
672
672
  was never measured, which is what `height: auto` cannot do. */
673
- .rk-accordion-panel[data-v-00091812] {
673
+ .rk-accordion-panel[data-v-d7bddb65] {
674
674
  display: grid;
675
675
  grid-template-rows: 0fr;
676
676
  transition: grid-template-rows 420ms ease-out;
677
677
  }
678
- .rk-accordion-panel.is-open[data-v-00091812] {
678
+ .rk-accordion-panel.is-open[data-v-d7bddb65] {
679
679
  grid-template-rows: 1fr;
680
680
  }
681
- .rk-accordion-clip[data-v-00091812] {
681
+ .rk-accordion-clip[data-v-d7bddb65] {
682
682
  overflow: hidden;
683
683
  }
684
- .rk-accordion-body[data-v-00091812] {
684
+ .rk-accordion-body[data-v-d7bddb65] {
685
685
  max-width: 68ch;
686
686
  padding-bottom: 1.5rem;
687
687
  color: var(--color-ink-soft);
@@ -689,13 +689,122 @@
689
689
  opacity: 0;
690
690
  transition: opacity 300ms;
691
691
  }
692
- .rk-accordion-body.is-open[data-v-00091812] {
692
+ .rk-accordion-body.is-open[data-v-d7bddb65] {
693
693
  opacity: 1;
694
694
  }
695
695
  @media (prefers-reduced-motion: reduce) {
696
- .rk-accordion-panel[data-v-00091812],
697
- .rk-accordion-bar-turn[data-v-00091812],
698
- .rk-accordion-body[data-v-00091812] {
696
+ .rk-accordion-panel[data-v-d7bddb65],
697
+ .rk-accordion-bar-turn[data-v-d7bddb65],
698
+ .rk-accordion-body[data-v-d7bddb65] {
699
+ transition: none;
700
+ }
701
+ }
702
+
703
+ .rk-crumbs[data-v-85ee4b4e] {
704
+ display: flex;
705
+ flex-wrap: wrap;
706
+ align-items: center;
707
+ gap: 0.5rem;
708
+ font-size: 0.8125rem;
709
+ }
710
+ .rk-crumb[data-v-85ee4b4e] {
711
+ display: flex;
712
+ align-items: center;
713
+ gap: 0.5rem;
714
+ }
715
+ .rk-crumb-link[data-v-85ee4b4e] {
716
+ color: var(--color-ink-soft);
717
+ transition: color 150ms;
718
+ }
719
+ .rk-crumb-link[data-v-85ee4b4e]:hover {
720
+ color: var(--color-ink);
721
+ }
722
+ .rk-crumb-link[data-v-85ee4b4e]:focus-visible {
723
+ outline: 2px solid var(--color-primary);
724
+ outline-offset: 2px;
725
+ border-radius: 2px;
726
+ }
727
+ .rk-crumb-current[data-v-85ee4b4e] {
728
+ color: var(--color-ink);
729
+ font-weight: 500;
730
+ }
731
+ .rk-crumb-sep[data-v-85ee4b4e] {
732
+ color: var(--color-hair);
733
+ }
734
+
735
+ .rk-disclosure-control[data-v-d32ee03c] {
736
+ display: flex;
737
+ width: 100%;
738
+ cursor: pointer;
739
+ align-items: center;
740
+ justify-content: space-between;
741
+ gap: 1.5rem;
742
+ padding: 1.25rem 0;
743
+ text-align: left;
744
+ transition: color 150ms;
745
+ }
746
+ .rk-disclosure-control[data-v-d32ee03c]:hover {
747
+ color: var(--color-primary);
748
+ }
749
+ .rk-disclosure-control[data-v-d32ee03c]:focus-visible {
750
+ outline: 2px solid var(--color-primary);
751
+ outline-offset: 2px;
752
+ }
753
+ .rk-disclosure-title[data-v-d32ee03c] {
754
+ color: var(--color-ink);
755
+ font-size: 1rem;
756
+ font-weight: 500;
757
+ }
758
+ .rk-disclosure-mark[data-v-d32ee03c] {
759
+ position: relative;
760
+ display: grid;
761
+ place-items: center;
762
+ flex-shrink: 0;
763
+ width: 1.5rem;
764
+ height: 1.5rem;
765
+ }
766
+ .rk-disclosure-bar[data-v-d32ee03c] {
767
+ position: absolute;
768
+ height: 1px;
769
+ width: 0.875rem;
770
+ background: var(--color-ink-soft);
771
+ }
772
+ .rk-disclosure-turn[data-v-d32ee03c] {
773
+ transform: rotate(90deg);
774
+ transition: transform 420ms ease-out;
775
+ }
776
+ .rk-disclosure-turn.is-open[data-v-d32ee03c] {
777
+ transform: rotate(0deg);
778
+ }
779
+
780
+ /* 0fr to 1fr is the whole trick: a grid row can be animated to a height that
781
+ was never measured, which `height: auto` cannot do. */
782
+ .rk-disclosure-panel[data-v-d32ee03c] {
783
+ display: grid;
784
+ grid-template-rows: 0fr;
785
+ transition: grid-template-rows 420ms ease-out;
786
+ }
787
+ .rk-disclosure-panel.is-open[data-v-d32ee03c] {
788
+ grid-template-rows: 1fr;
789
+ }
790
+ .rk-disclosure-clip[data-v-d32ee03c] {
791
+ overflow: hidden;
792
+ }
793
+ .rk-disclosure-body[data-v-d32ee03c] {
794
+ max-width: 68ch;
795
+ padding-bottom: 1.5rem;
796
+ color: var(--color-ink-soft);
797
+ line-height: 1.625;
798
+ opacity: 0;
799
+ transition: opacity 300ms;
800
+ }
801
+ .rk-disclosure-body.is-open[data-v-d32ee03c] {
802
+ opacity: 1;
803
+ }
804
+ @media (prefers-reduced-motion: reduce) {
805
+ .rk-disclosure-panel[data-v-d32ee03c],
806
+ .rk-disclosure-turn[data-v-d32ee03c],
807
+ .rk-disclosure-body[data-v-d32ee03c] {
699
808
  transition: none;
700
809
  }
701
810
  }
@@ -800,6 +909,133 @@
800
909
  }
801
910
  }
802
911
 
912
+ .rk-pager[data-v-cc4bbb58] {
913
+ display: flex;
914
+ align-items: center;
915
+ gap: 0.25rem;
916
+ }
917
+ .rk-pager-step[data-v-cc4bbb58],
918
+ .rk-pager-page[data-v-cc4bbb58] {
919
+ display: grid;
920
+ place-items: center;
921
+ min-width: 2rem;
922
+ height: 2rem;
923
+ padding: 0 0.5rem;
924
+ border-radius: var(--radius-cell);
925
+ font-size: 0.875rem;
926
+ color: var(--color-ink-soft);
927
+ transition:
928
+ background-color 150ms,
929
+ color 150ms;
930
+ }
931
+ .rk-pager-step[data-v-cc4bbb58]:hover:not(:disabled),
932
+ .rk-pager-page[data-v-cc4bbb58]:hover {
933
+ background: var(--color-muted);
934
+ color: var(--color-ink);
935
+ }
936
+ .rk-pager-step[data-v-cc4bbb58]:focus-visible,
937
+ .rk-pager-page[data-v-cc4bbb58]:focus-visible {
938
+ outline: 2px solid var(--color-primary);
939
+ outline-offset: 2px;
940
+ }
941
+ .rk-pager-step[data-v-cc4bbb58]:disabled {
942
+ opacity: 0.4;
943
+ pointer-events: none;
944
+ }
945
+ .rk-pager-page.is-active[data-v-cc4bbb58] {
946
+ background: var(--color-primary);
947
+ color: #fff;
948
+ font-weight: 500;
949
+ }
950
+ .rk-pager-gap[data-v-cc4bbb58] {
951
+ display: grid;
952
+ place-items: center;
953
+ min-width: 2rem;
954
+ height: 2rem;
955
+ color: var(--color-ink-soft);
956
+ }
957
+
958
+ .rk-tabs[data-v-b854e7f5] {
959
+ display: flex;
960
+ align-items: center;
961
+ gap: 0.25rem;
962
+ border-bottom: 1px solid color-mix(in srgb, var(--color-hair) 70%, transparent);
963
+ }
964
+ .rk-tab[data-v-b854e7f5] {
965
+ position: relative;
966
+ padding: 0.625rem 0.875rem;
967
+ font-size: 0.875rem;
968
+ color: var(--color-ink-soft);
969
+ transition: color 150ms;
970
+ }
971
+ .rk-tab[data-v-b854e7f5]:hover {
972
+ color: var(--color-ink);
973
+ }
974
+ .rk-tab[data-v-b854e7f5]:focus-visible {
975
+ outline: 2px solid var(--color-primary);
976
+ outline-offset: -2px;
977
+ border-radius: var(--radius-cell);
978
+ }
979
+ .rk-tab.is-active[data-v-b854e7f5] {
980
+ color: var(--color-ink);
981
+ font-weight: 500;
982
+ }
983
+ .rk-tab.is-active[data-v-b854e7f5]::after {
984
+ content: '';
985
+ position: absolute;
986
+ inset-inline: 0.5rem;
987
+ bottom: -1px;
988
+ height: 2px;
989
+ border-radius: 9999px;
990
+ background: var(--color-primary);
991
+ }
992
+ .rk-tabpanel[data-v-b854e7f5] {
993
+ padding-top: 1rem;
994
+ }
995
+ .rk-tabpanel[data-v-b854e7f5]:focus-visible {
996
+ outline: 2px solid var(--color-primary);
997
+ outline-offset: 2px;
998
+ }
999
+
1000
+ .rk-tip[data-v-3ed61bd4] {
1001
+ position: relative;
1002
+ display: inline-flex;
1003
+ }
1004
+ .rk-tip-bubble[data-v-3ed61bd4] {
1005
+ position: absolute;
1006
+ left: 50%;
1007
+ z-index: 60;
1008
+ width: max-content;
1009
+ max-width: 16rem;
1010
+ transform: translateX(-50%);
1011
+ border-radius: var(--radius-cell);
1012
+ background: var(--color-ink);
1013
+ padding: 0.375rem 0.5rem;
1014
+ font-size: 0.75rem;
1015
+ line-height: 1.4;
1016
+ color: var(--color-canvas);
1017
+ opacity: 0;
1018
+ /* Out of the hit area while hidden, or it would swallow the pointer on its
1019
+ way to the control it describes. */
1020
+ pointer-events: none;
1021
+ transition: opacity 150ms ease;
1022
+ }
1023
+ .rk-tip-bubble.is-top[data-v-3ed61bd4] {
1024
+ bottom: calc(100% + 0.375rem);
1025
+ }
1026
+ .rk-tip-bubble.is-bottom[data-v-3ed61bd4] {
1027
+ top: calc(100% + 0.375rem);
1028
+ }
1029
+ .rk-tip:hover .rk-tip-bubble[data-v-3ed61bd4],
1030
+ .rk-tip:focus-within .rk-tip-bubble[data-v-3ed61bd4] {
1031
+ opacity: 1;
1032
+ }
1033
+ @media (prefers-reduced-motion: reduce) {
1034
+ .rk-tip-bubble[data-v-3ed61bd4] {
1035
+ transition: none;
1036
+ }
1037
+ }
1038
+
803
1039
  /* The root carries no layout of its own, and that is the fix for a real bug
804
1040
  rather than a style preference.
805
1041
 
@@ -27,6 +27,11 @@ declare const __VLS_export: <K extends string>(__VLS_props: NonNullable<Awaited<
27
27
  item: AccordionItem<K>;
28
28
  open: boolean;
29
29
  }) => unknown;
30
+ /** The question, when the item's `title` is not enough. */
31
+ title?: (props: {
32
+ item: AccordionItem<K>;
33
+ open: boolean;
34
+ }) => unknown;
30
35
  };
31
36
  emit: {};
32
37
  }>) => import('vue').VNode & {
@@ -0,0 +1,26 @@
1
+ export interface Crumb {
2
+ /** Already translated. */
3
+ label: string;
4
+ /** Omitted for the current page, which is not a link to itself. */
5
+ to?: string | undefined;
6
+ }
7
+ /**
8
+ * Where this page sits, and the way back up.
9
+ *
10
+ * An ordered list inside a `nav`, because the order is the meaning. The last
11
+ * crumb is the current page and is deliberately not a link: a link to the page
12
+ * you are on is a control that does nothing, and `aria-current="page"` is what
13
+ * says so to everyone else.
14
+ *
15
+ * The separators are `aria-hidden`. A screen reader announces a list and its
16
+ * position in it; reading "slash" between every item is noise on top of
17
+ * information the reader already has.
18
+ */
19
+ type __VLS_Props = {
20
+ items: readonly Crumb[];
21
+ /** Accessible name for the landmark. */
22
+ label?: string | undefined;
23
+ };
24
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
25
+ declare const _default: typeof __VLS_export;
26
+ export default _default;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * One section that opens and closes.
3
+ *
4
+ * `BaseAccordion` is a list of these with the rule that only one stays open.
5
+ * This is the same row on its own, for the common case where the list belongs
6
+ * to the app — because it is staggered as it scrolls in, or interleaved with
7
+ * something else, or rendered from a source the accordion cannot know about.
8
+ *
9
+ * That case is not hypothetical: the first list this kit met decorated every
10
+ * row with a reveal directive, which has to sit on the element the accordion
11
+ * would have owned. Shipping only the list would have meant choosing between
12
+ * the component and the design.
13
+ *
14
+ * ## Why not `<details>`
15
+ *
16
+ * A browser removes `<details>` content from layout entirely when closed, so
17
+ * there is nothing to animate between — the panel can only appear. Faking it by
18
+ * leaving `open` set and hiding with CSS tells a screen reader the section is
19
+ * expanded while a sighted reader sees it shut, which is worse than no
20
+ * animation.
21
+ *
22
+ * So: a button carrying `aria-expanded`, the content always in the markup —
23
+ * which is what a crawler and a reader without JavaScript get — and a grid row
24
+ * travelling from `0fr` to `1fr`, the one way to animate to a height nobody has
25
+ * measured.
26
+ */
27
+ type __VLS_Props = {
28
+ /** The question. Already translated. */
29
+ title: string;
30
+ /**
31
+ * Which heading the control sits inside.
32
+ *
33
+ * A heading, always — it is how a screen reader user moves between sections
34
+ * without opening any of them. The level depends on what is above it on the
35
+ * page, and getting it wrong breaks the outline.
36
+ */
37
+ headingLevel?: 2 | 3 | 4 | undefined;
38
+ };
39
+ type __VLS_Slots = {
40
+ /** The answer. */
41
+ default: () => unknown;
42
+ /**
43
+ * The question, when the prop is not enough.
44
+ *
45
+ * A slot as well as a prop because the size of a heading is a decision about
46
+ * the page it is on, not about disclosure: the first list to use this wanted
47
+ * the question a step larger on a wide screen, and a component that hard-codes
48
+ * one size makes that an override against its own stylesheet.
49
+ */
50
+ title?: () => unknown;
51
+ };
52
+ type __VLS_ModelProps = {
53
+ modelValue?: boolean;
54
+ };
55
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
56
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
57
+ "update:modelValue": (value: boolean) => any;
58
+ }, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
59
+ "onUpdate:modelValue"?: (value: boolean) => any;
60
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
61
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
62
+ declare const _default: typeof __VLS_export;
63
+ export default _default;
64
+ type __VLS_WithSlots<T, S> = T & {
65
+ new (): {
66
+ $slots: S;
67
+ };
68
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Moving between pages of a list.
3
+ *
4
+ * A `nav` of buttons rather than links, because this component does not know
5
+ * whether the app pages by route, by query or in memory. It emits a number and
6
+ * the app decides what that means.
7
+ *
8
+ * ## The ellipsis
9
+ *
10
+ * Every page number is unusable past about a dozen, and cutting to
11
+ * "1 … 7 8 9 … 40" is what every list does. The window is a fixed size around
12
+ * the current page and the first and last are always present, so the control
13
+ * never changes width as you move through it — a row of numbers that reflows
14
+ * under the pointer is a row you have to re-aim at.
15
+ *
16
+ * The gap is a `<span>`, not a disabled button: it is not a control, and
17
+ * announcing it as one gives a screen reader something to try to press.
18
+ */
19
+ type __VLS_Props = {
20
+ /** Current page, 1-based. */
21
+ page: number;
22
+ /** How many there are. */
23
+ pages: number;
24
+ /** How many numbers to show either side of the current one. */
25
+ siblings?: number | undefined;
26
+ /** Accessible name for the landmark. */
27
+ label?: string | undefined;
28
+ /**
29
+ * Names for the arrows, already translated.
30
+ *
31
+ * Required, because `‹` is a glyph and not a word: a screen reader reading
32
+ * the arrow announces nothing a person can act on.
33
+ */
34
+ previousLabel: string;
35
+ nextLabel: string;
36
+ };
37
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
38
+ change: (page: number) => any;
39
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
40
+ onChange?: (page: number) => any;
41
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
42
+ declare const _default: typeof __VLS_export;
43
+ export default _default;
@@ -0,0 +1,37 @@
1
+ export interface TabPanel<K extends string> {
2
+ key: K;
3
+ /** Already translated. */
4
+ label: string;
5
+ }
6
+ declare const __VLS_export: <K extends string>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
7
+ props: import('vue').PublicProps & __VLS_PrettifyLocal<({
8
+ items: readonly TabPanel<K>[];
9
+ /** Accessible name for the tablist. */
10
+ label?: string | undefined;
11
+ } & {
12
+ modelValue: K;
13
+ }) & {
14
+ "onUpdate:modelValue"?: (value: K) => any;
15
+ }> & (typeof globalThis extends {
16
+ __VLS_PROPS_FALLBACK: infer P;
17
+ } ? P : {});
18
+ expose: (exposed: {}) => void;
19
+ attrs: any;
20
+ slots: {
21
+ /** The panel for the selected tab. */
22
+ default: (props: {
23
+ item: TabPanel<K>;
24
+ active: K;
25
+ }) => unknown;
26
+ };
27
+ emit: (event: "update:modelValue", value: K) => void;
28
+ }>) => import('vue').VNode & {
29
+ __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
30
+ };
31
+ declare const _default: typeof __VLS_export;
32
+ export default _default;
33
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
34
+ [K in keyof T]: T[K];
35
+ } : {
36
+ [K in keyof T as K]: T[K];
37
+ }) & {};
@@ -0,0 +1,45 @@
1
+ /**
2
+ * A short label that appears beside a control.
3
+ *
4
+ * ## CSS, not JavaScript, and that is a decision
5
+ *
6
+ * The bubble is shown by `:hover` and `:focus-within` in the stylesheet. No
7
+ * listener, no state, no positioning library. That costs collision detection —
8
+ * a tooltip near the right edge is clipped rather than flipped — and buys the
9
+ * only thing that matters more: it works in a prerendered page, before the
10
+ * bundle has arrived, and with JavaScript switched off entirely.
11
+ *
12
+ * `:focus-within` rather than `:hover` alone is the part people leave out. A
13
+ * tooltip that only answers a mouse is a tooltip that does not exist for anyone
14
+ * using a keyboard, and the content is usually the only explanation of what the
15
+ * control does.
16
+ *
17
+ * The bubble is wired with `aria-describedby`, so a screen reader reads it as a
18
+ * description of the control rather than as loose text nearby. That is why the
19
+ * trigger goes in a slot: the component has to own the id on both ends.
20
+ *
21
+ * ## When not to use it
22
+ *
23
+ * For anything the reader must have. A tooltip is unreachable on a touch screen
24
+ * without a hover state, so text that changes a decision belongs on the page.
25
+ */
26
+ type __VLS_Props = {
27
+ /** The description. Already translated. */
28
+ label: string;
29
+ placement?: 'top' | 'bottom' | undefined;
30
+ };
31
+ type __VLS_Slots = {
32
+ /** The control being described. */
33
+ default: (props: {
34
+ describedBy: string;
35
+ }) => unknown;
36
+ };
37
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
38
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
39
+ declare const _default: typeof __VLS_export;
40
+ export default _default;
41
+ type __VLS_WithSlots<T, S> = T & {
42
+ new (): {
43
+ $slots: S;
44
+ };
45
+ };
@@ -5,19 +5,26 @@
5
5
  * assume a page with a header, a mouse and room to spare. A phone app importing
6
6
  * the kit should not download them.
7
7
  *
8
- * Smaller than it was meant to be, and deliberately. The plan for this release
9
- * listed eight components; four of them had no user anywhere `Pagination` was
10
- * not written once in any consumer, and `Tabs` and `Breadcrumb` appear only in
11
- * prose. A kit that ships a component nobody reached for is a kit guessing at
12
- * a shape, and `BaseRadioGroup` is already one standing reminder of that.
13
- *
14
- * `Tooltip` is missing for a better reason: the one consumer's tooltip is
15
- * CSS-only on purpose, because a tooltip that needs JavaScript to appear does
16
- * not appear in a prerendered page. Shipping a JavaScript one would have been
17
- * shipping the wrong answer in a nicer package.
8
+ * Everything a wide site is normally built from is here whether or not a
9
+ * consumer has reached for it yet. That is the rule in `AGENTS.md` — no waiting
10
+ * for a second consumer and no counting of call sites — and 0.17.0 broke it by
11
+ * shipping three of eight planned components on the grounds that the other five
12
+ * had no users. A kit is a separate project: somebody installing it should not
13
+ * have to hand-write a pagination control because the apps that happen to exist
14
+ * today do not paginate.
18
15
  */
19
16
  export { default as BaseAccordion } from './BaseAccordion.vue';
20
17
  export type { AccordionItem } from './BaseAccordion.vue';
18
+ export { default as BaseBreadcrumb } from './BaseBreadcrumb.vue';
19
+ export type { Crumb } from './BaseBreadcrumb.vue';
20
+ /**
21
+ * One accordion row on its own.
22
+ *
23
+ * For the common case where the list belongs to the app — staggered as it
24
+ * scrolls in, interleaved with something else, or built from a source the
25
+ * accordion cannot know about.
26
+ */
27
+ export { default as BaseDisclosure } from './BaseDisclosure.vue';
21
28
  /**
22
29
  * `BaseModal`, beside `BaseSheet` rather than named `Modal` on its own.
23
30
  *
@@ -26,5 +33,9 @@ export type { AccordionItem } from './BaseAccordion.vue';
26
33
  * to make somebody reaching for one notice the other exists.
27
34
  */
28
35
  export { default as BaseModal } from './BaseModal.vue';
36
+ export { default as BasePagination } from './BasePagination.vue';
37
+ export { default as BaseTabs } from './BaseTabs.vue';
38
+ export type { TabPanel } from './BaseTabs.vue';
39
+ export { default as BaseTooltip } from './BaseTooltip.vue';
29
40
  export { default as NavLinks } from './NavLinks.vue';
30
41
  export type { NavLinkItem } from './NavLinks.vue';