@akonwi/mica 0.9.0 → 0.10.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.
package/mica.css CHANGED
@@ -847,6 +847,85 @@
847
847
  );
848
848
  }
849
849
 
850
+ /* --- skeleton: quiet CSS-only loading placeholder ---------------- */
851
+ :where(m-skeleton) {
852
+ display: block;
853
+ flex: none;
854
+ inline-size: var(--skeleton-width, 100%);
855
+ block-size: var(--skeleton-height, 0.75rem);
856
+ overflow: hidden;
857
+ border-radius: var(--skeleton-radius, var(--radius-md));
858
+ background-color: var(--color-surface-raised);
859
+ animation: mica-skeleton-pulse 1.6s ease-in-out infinite alternate;
860
+ }
861
+
862
+ @keyframes mica-skeleton-pulse {
863
+ to {
864
+ background-color: var(--color-border);
865
+ }
866
+ }
867
+
868
+ @media (prefers-reduced-motion: reduce) {
869
+ :where(m-skeleton) {
870
+ animation: none;
871
+ background-color: var(--color-border);
872
+ }
873
+ }
874
+
875
+ /* --- stat grid: semantic summaries in a fused frame -------------- */
876
+ :where(dl.stat-grid) {
877
+ display: flex;
878
+ flex-wrap: wrap;
879
+ gap: 1px;
880
+ margin-block: 0;
881
+ padding: 1px;
882
+ overflow: hidden;
883
+ border-radius: var(--radius-md);
884
+ background: var(--color-border);
885
+ }
886
+
887
+ :where(dl.stat-grid) > :where(div.stat) {
888
+ display: flex;
889
+ flex-direction: column;
890
+ flex: 1 1 min(100%, 8rem);
891
+ gap: var(--space-sm);
892
+ min-inline-size: 0;
893
+ padding: var(--space-md);
894
+ background: var(--color-surface);
895
+ }
896
+
897
+ :where(dl.stat-grid) > :where(div.stat) > :where(dt) {
898
+ color: var(--color-text-muted);
899
+ font-size: 0.75rem;
900
+ font-weight: 500;
901
+ line-height: 1.4;
902
+ }
903
+
904
+ :where(dl.stat-grid) > :where(div.stat) > :where(dd) {
905
+ display: flex;
906
+ flex-direction: column;
907
+ flex: 1 1 auto;
908
+ gap: var(--space-2xs);
909
+ min-inline-size: 0;
910
+ margin-block: 0;
911
+ }
912
+
913
+ :where(dl.stat-grid) > :where(div.stat) > :where(dd) > :first-child {
914
+ color: var(--color-text);
915
+ font-size: 1.5rem;
916
+ font-weight: 600;
917
+ font-variant-numeric: tabular-nums;
918
+ line-height: 1.2;
919
+ overflow-wrap: anywhere;
920
+ }
921
+
922
+ :where(dl.stat-grid) > :where(div.stat) > :where(dd) > :where(small) {
923
+ margin-block-start: auto;
924
+ color: var(--color-text-muted);
925
+ font-size: 0.75rem;
926
+ line-height: 1.4;
927
+ }
928
+
850
929
  /* --- content: tables, lists, code, quotes ------------------------ */
851
930
  :where(table) {
852
931
  inline-size: 100%;
@@ -983,6 +1062,71 @@
983
1062
  background: var(--color-danger);
984
1063
  }
985
1064
 
1065
+ /* --- stepper: framed sequence controls --------------------------- *
1066
+ * Mica owns only the fused layout. Consumers own labels, disabled
1067
+ * state, events, routing, and value changes. The frame deliberately does
1068
+ * not clip overflow: native focus rings must remain fully visible.
1069
+ * ------------------------------------------------------------------ */
1070
+ :where(m-stepper) {
1071
+ display: grid;
1072
+ grid-template-columns: auto minmax(0, 1fr) auto;
1073
+ align-items: stretch;
1074
+ min-inline-size: 0;
1075
+ border: 1px solid var(--color-border-strong);
1076
+ border-radius: var(--radius-md);
1077
+ background: var(--color-surface);
1078
+ }
1079
+
1080
+ :where(m-stepper:has(> [data-reset])) {
1081
+ grid-template-columns: auto minmax(0, 1fr) auto auto;
1082
+ }
1083
+
1084
+ :where(m-stepper) > :where(button) {
1085
+ border: 0;
1086
+ border-radius: 0;
1087
+ background: transparent;
1088
+
1089
+ &:focus-visible {
1090
+ z-index: 1;
1091
+ }
1092
+ }
1093
+
1094
+ :where(m-stepper) > :where(button:first-child) {
1095
+ border-start-start-radius: inherit;
1096
+ border-end-start-radius: inherit;
1097
+ }
1098
+
1099
+ :where(m-stepper) > :where(button:last-child) {
1100
+ border-start-end-radius: inherit;
1101
+ border-end-end-radius: inherit;
1102
+ }
1103
+
1104
+ :where(m-stepper) > :where([data-step]) {
1105
+ inline-size: var(--control-height);
1106
+ padding-inline: 0;
1107
+ }
1108
+
1109
+ :where(m-stepper) > :where(:nth-child(2)) {
1110
+ display: grid;
1111
+ place-items: center;
1112
+ min-inline-size: 0;
1113
+ block-size: var(--control-height);
1114
+ padding-inline: var(--space-sm);
1115
+ overflow: hidden;
1116
+ border-inline: 1px solid var(--color-border);
1117
+ background: var(--color-surface-raised);
1118
+ color: var(--color-text);
1119
+ font-size: 0.875rem;
1120
+ font-weight: 600;
1121
+ text-align: center;
1122
+ text-overflow: ellipsis;
1123
+ white-space: nowrap;
1124
+ }
1125
+
1126
+ :where(m-stepper) > :where([data-reset]) {
1127
+ border-inline-start: 1px solid var(--color-border);
1128
+ }
1129
+
986
1130
  /* --- dialog: modal + drawer --------------------------------------- *
987
1131
  * The browser brings focus trapping, Esc, top layer, ::backdrop, and
988
1132
  * form[method=dialog] closing. Invoker commands (commandfor/command)
@@ -1535,38 +1679,136 @@
1535
1679
  /* --- tabs: m-tabs + tabs.js (JS-enhanced) ------------------------------ *
1536
1680
  * without the module: inert nav, all panels visible in order —
1537
1681
  * complete content. with it: tablist semantics + roving focus.
1538
- * shadcn segmented look: muted track, surface active tab.
1682
+ * default: muted track + surface active tab. variant="underline":
1683
+ * quiet rail + accent selection line; behavior stays identical.
1539
1684
  * ------------------------------------------------------------------ */
1540
1685
  :where(m-tabs) {
1686
+ --m-tabs-rail-gap: var(--space-2xs);
1687
+ --m-tabs-rail-padding: var(--space-2xs);
1688
+ --m-tabs-rail-border: none;
1689
+ --m-tabs-rail-radius: var(--radius-md);
1690
+ --m-tabs-rail-background: var(--neutral-3);
1691
+ --m-tabs-overflow-cover: var(--neutral-3);
1692
+ --m-tabs-overflow-duration: 0.15s;
1693
+ --m-tabs-overflow-marker: color-mix(in oklch, var(--color-text-muted) 70%, transparent);
1694
+ --m-tabs-overflow-start-gutter: 0px;
1695
+ --m-tabs-overflow-end-gutter: 0px;
1696
+ --m-tabs-overflow-start: 0;
1697
+ --m-tabs-overflow-end: 0;
1698
+ --m-tabs-tab-radius: var(--radius-sm);
1699
+ --m-tabs-tab-edge-padding: var(--space-sm);
1700
+ --m-tabs-tab-focus-offset: var(--focus-ring-offset);
1701
+ --m-tabs-tab-selected-background: var(--color-surface);
1702
+ --m-tabs-tab-selected-shadow: 0 1px 2px oklch(0 0 0 / 0.08);
1541
1703
  display: block;
1542
1704
  }
1543
1705
 
1706
+ :where(m-tabs[variant="underline"]) {
1707
+ --m-tabs-rail-gap: 0;
1708
+ --m-tabs-rail-padding: 0;
1709
+ --m-tabs-rail-border: 1px solid var(--color-border);
1710
+ --m-tabs-rail-radius: 0;
1711
+ --m-tabs-rail-background: transparent;
1712
+ --m-tabs-overflow-cover: var(--color-surface);
1713
+ --m-tabs-tab-radius: 0;
1714
+ --m-tabs-tab-edge-padding: 0;
1715
+ --m-tabs-tab-focus-offset: -2px;
1716
+ --m-tabs-tab-selected-background: transparent;
1717
+ --m-tabs-tab-selected-shadow: inset 0 -2px var(--color-accent);
1718
+ }
1719
+
1544
1720
  :where(m-tabs) > :where(nav) {
1545
1721
  display: inline-flex;
1546
- gap: var(--space-2xs);
1547
- padding: var(--space-2xs);
1548
- background: var(--neutral-3);
1549
- border-radius: var(--radius-md);
1722
+ gap: var(--m-tabs-rail-gap);
1723
+ padding: var(--m-tabs-rail-padding);
1724
+ border-block-end: var(--m-tabs-rail-border);
1725
+ border-radius: var(--m-tabs-rail-radius);
1726
+ background: var(--m-tabs-rail-background);
1550
1727
 
1551
1728
  /* Graceful collapse: labels never wrap inside a tab — when the rail
1552
- is narrower than its tabs it scrolls horizontally instead. The
1553
- thin scrollbar is the overflow affordance on platforms that show
1554
- one; scroll chaining stays contained. */
1729
+ is narrower than its tabs it scrolls horizontally instead. Before
1730
+ enhancement, the native scrollbar remains the overflow affordance.
1731
+ tabs.js hides it, activates sticky direction markers in clear
1732
+ gutters, and reveals a selected tab within those gutters. Scroll
1733
+ chaining stays contained. */
1555
1734
  max-inline-size: 100%;
1556
1735
  overflow-x: auto;
1557
1736
  overscroll-behavior-x: contain;
1558
1737
  scrollbar-width: thin;
1559
1738
 
1739
+ &[role="tablist"] {
1740
+ scrollbar-width: none;
1741
+ }
1742
+
1743
+ &::before,
1744
+ &::after {
1745
+ content: "";
1746
+ position: sticky;
1747
+ z-index: 1;
1748
+ align-self: stretch;
1749
+ background-color: var(--m-tabs-overflow-cover);
1750
+ background-position: center;
1751
+ background-size: 6px 10px;
1752
+ background-repeat: no-repeat;
1753
+ pointer-events: none;
1754
+ }
1755
+
1756
+ &::before {
1757
+ inset-inline-start: 0;
1758
+ flex: 0 0 var(--space-md);
1759
+ margin-inline-end: calc(var(--m-tabs-overflow-start-gutter) - var(--space-md));
1760
+ opacity: var(--m-tabs-overflow-start);
1761
+ background-image: conic-gradient(from 45deg at left center,
1762
+ var(--m-tabs-overflow-marker) 0 25%, transparent 0);
1763
+ transition:
1764
+ opacity var(--m-tabs-overflow-duration),
1765
+ margin-inline-end var(--m-tabs-overflow-duration);
1766
+ }
1767
+
1768
+ &::after {
1769
+ inset-inline-end: 0;
1770
+ flex: 0 0 var(--space-md);
1771
+ margin-inline-start: calc(var(--m-tabs-overflow-end-gutter) - var(--space-md));
1772
+ opacity: var(--m-tabs-overflow-end);
1773
+ background-image: conic-gradient(from 225deg at right center,
1774
+ var(--m-tabs-overflow-marker) 0 25%, transparent 0);
1775
+ transition:
1776
+ opacity var(--m-tabs-overflow-duration),
1777
+ margin-inline-start var(--m-tabs-overflow-duration);
1778
+ }
1779
+
1780
+ &:dir(rtl)::before {
1781
+ background-image: conic-gradient(from 225deg at right center,
1782
+ var(--m-tabs-overflow-marker) 0 25%, transparent 0);
1783
+ }
1784
+
1785
+ &:dir(rtl)::after {
1786
+ background-image: conic-gradient(from 45deg at left center,
1787
+ var(--m-tabs-overflow-marker) 0 25%, transparent 0);
1788
+ }
1789
+
1560
1790
  & > :where(button) {
1561
1791
  flex-shrink: 0;
1562
1792
  white-space: nowrap;
1563
1793
  block-size: var(--control-height-sm);
1564
1794
  padding-inline: var(--space-sm);
1565
1795
  border: 0;
1566
- border-radius: var(--radius-sm);
1796
+ border-radius: var(--m-tabs-tab-radius);
1567
1797
  background: transparent;
1568
1798
  color: var(--color-text-muted);
1569
1799
 
1800
+ &:first-of-type {
1801
+ padding-inline-start: var(--m-tabs-tab-edge-padding);
1802
+ }
1803
+
1804
+ &:last-of-type {
1805
+ padding-inline-end: var(--m-tabs-tab-edge-padding);
1806
+ }
1807
+
1808
+ &:focus-visible {
1809
+ outline-offset: var(--m-tabs-tab-focus-offset);
1810
+ }
1811
+
1570
1812
  /* :not() guards mirror the base button states (house rule) */
1571
1813
  &:hover:not(:disabled, [aria-disabled="true"]),
1572
1814
  &:active:not(:disabled, [aria-disabled="true"]) {
@@ -1575,19 +1817,25 @@
1575
1817
  }
1576
1818
 
1577
1819
  &[aria-selected="true"] {
1578
- background: var(--color-surface);
1820
+ background: var(--m-tabs-tab-selected-background);
1579
1821
  color: var(--color-text);
1580
- box-shadow: 0 1px 2px oklch(0 0 0 / 0.08);
1822
+ box-shadow: var(--m-tabs-tab-selected-shadow);
1581
1823
 
1582
1824
  &:hover:not(:disabled, [aria-disabled="true"]),
1583
1825
  &:active:not(:disabled, [aria-disabled="true"]) {
1584
- background: var(--color-surface);
1826
+ background: var(--m-tabs-tab-selected-background);
1585
1827
  color: var(--color-text);
1586
1828
  }
1587
1829
  }
1588
1830
  }
1589
1831
  }
1590
1832
 
1833
+ /* Vendor pseudo gets its own rule: one unknown selector in a list
1834
+ invalidates the whole list. */
1835
+ :where(m-tabs) > :where(nav[role="tablist"])::-webkit-scrollbar {
1836
+ display: none;
1837
+ }
1838
+
1591
1839
  :where(m-tabs) > :where(section) {
1592
1840
  padding-block: var(--space-md);
1593
1841
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akonwi/mica",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Custom elements. Native behavior. Nearly no JavaScript.",
5
5
  "keywords": [
6
6
  "css",
package/tabs.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /* Type declarations for mica/tabs.js — side-effect module.
2
- * Registers <m-tabs>: roving tabindex, arrow keys, aria-selected wiring.
2
+ * Registers <m-tabs>: roving tabindex, arrow keys, aria-selected wiring,
3
+ * selected-tab reveal, and directional overflow markers.
3
4
  */
4
5
  declare global {
5
6
  interface HTMLElementTagNameMap {
package/tabs.js CHANGED
@@ -3,7 +3,8 @@
3
3
  * Enhances working light-DOM markup; never renders it. Without this
4
4
  * module, the nav buttons are inert and every panel is visible in
5
5
  * order — complete, readable content. With it: real tablist semantics,
6
- * roving tabindex, arrow-key navigation, automatic activation.
6
+ * roving tabindex, arrow-key navigation, automatic activation, and
7
+ * selected-tab reveal with position-aware overflow markers.
7
8
  *
8
9
  * <m-tabs>
9
10
  * <nav>
@@ -23,10 +24,43 @@ let uid = 0;
23
24
  class MTabs extends HTMLElement {
24
25
  #tabs = [];
25
26
  #panels = [];
27
+ #nav = null;
28
+ #overflowing = false;
29
+ #resizeObserver = null;
30
+ #revealFrame = null;
31
+ #onScroll = () => this.#syncOverflow();
32
+ #cancelReveal = () => {
33
+ if (this.#revealFrame !== null) cancelAnimationFrame(this.#revealFrame);
34
+ this.#revealFrame = null;
35
+ };
36
+ #onClick = (event) => {
37
+ const tab = event.target instanceof Element ? event.target.closest("button") : null;
38
+ const index = this.#tabs.indexOf(tab);
39
+ if (index === -1) return;
40
+ this.select(index);
41
+ this.#reveal(index);
42
+ };
43
+ #onKeyDown = (event) => {
44
+ const n = this.#tabs.length;
45
+ const current = this.#tabs.findIndex(
46
+ (tab) => tab.getAttribute("aria-selected") === "true",
47
+ );
48
+ let next = null;
49
+ if (event.key === "ArrowRight") next = (current + 1) % n;
50
+ else if (event.key === "ArrowLeft") next = (current - 1 + n) % n;
51
+ else if (event.key === "Home") next = 0;
52
+ else if (event.key === "End") next = n - 1;
53
+ if (next === null) return;
54
+ event.preventDefault();
55
+ this.select(next); // automatic activation, radix-style
56
+ this.#tabs[next].focus({ preventScroll: true });
57
+ this.#reveal(next);
58
+ };
26
59
 
27
60
  connectedCallback() {
28
61
  const nav = this.querySelector(":scope > nav");
29
62
  if (!nav) return;
63
+ this.#nav = nav;
30
64
  this.#tabs = [...nav.querySelectorAll("button")];
31
65
  const sections = [...this.querySelectorAll(":scope > section")];
32
66
  this.#panels = this.#tabs.map((b, i) => {
@@ -44,29 +78,117 @@ class MTabs extends HTMLElement {
44
78
  panel.setAttribute("aria-labelledby", tab.id);
45
79
  panel.tabIndex = 0;
46
80
  }
47
- tab.addEventListener("click", () => this.select(i));
48
81
  });
49
82
 
50
- nav.addEventListener("keydown", (e) => {
51
- const n = this.#tabs.length;
52
- const current = this.#tabs.findIndex(
53
- (t) => t.getAttribute("aria-selected") === "true",
54
- );
55
- let next = null;
56
- if (e.key === "ArrowRight") next = (current + 1) % n;
57
- else if (e.key === "ArrowLeft") next = (current - 1 + n) % n;
58
- else if (e.key === "Home") next = 0;
59
- else if (e.key === "End") next = n - 1;
60
- if (next === null) return;
61
- e.preventDefault();
62
- this.select(next); // automatic activation, radix-style
63
- this.#tabs[next].focus();
64
- });
83
+ nav.addEventListener("click", this.#onClick);
84
+ nav.addEventListener("keydown", this.#onKeyDown);
85
+ nav.addEventListener("pointerdown", this.#cancelReveal, { passive: true });
86
+ nav.addEventListener("wheel", this.#cancelReveal, { passive: true });
65
87
 
66
88
  const initial = this.#tabs.findIndex(
67
89
  (t) => t.hasAttribute("selected") || t.getAttribute("aria-selected") === "true",
68
90
  );
69
91
  this.select(initial === -1 ? 0 : initial);
92
+
93
+ nav.addEventListener("scroll", this.#onScroll, { passive: true });
94
+ this.#resizeObserver = new ResizeObserver(() => this.#measureOverflow());
95
+ this.#resizeObserver.observe(nav);
96
+ this.#tabs.forEach((tab) => this.#resizeObserver.observe(tab));
97
+ this.#measureOverflow();
98
+ }
99
+
100
+ disconnectedCallback() {
101
+ this.#nav?.removeEventListener("click", this.#onClick);
102
+ this.#nav?.removeEventListener("keydown", this.#onKeyDown);
103
+ this.#nav?.removeEventListener("pointerdown", this.#cancelReveal);
104
+ this.#nav?.removeEventListener("wheel", this.#cancelReveal);
105
+ this.#nav?.removeEventListener("scroll", this.#onScroll);
106
+ this.#resizeObserver?.disconnect();
107
+ this.#cancelReveal();
108
+ for (const property of [
109
+ "--m-tabs-overflow-start-gutter",
110
+ "--m-tabs-overflow-end-gutter",
111
+ "--m-tabs-overflow-start",
112
+ "--m-tabs-overflow-end",
113
+ ]) this.#nav?.style.removeProperty(property);
114
+ this.#nav = null;
115
+ this.#resizeObserver = null;
116
+ }
117
+
118
+ #measureOverflow() {
119
+ const nav = this.#nav;
120
+ if (!nav) return;
121
+ const style = getComputedStyle(nav);
122
+ const gap = Number.parseFloat(style.columnGap) || 0;
123
+ const padding = (Number.parseFloat(style.paddingInlineStart) || 0) +
124
+ (Number.parseFloat(style.paddingInlineEnd) || 0);
125
+ const tabsWidth = this.#tabs.reduce(
126
+ (width, tab) => width + tab.getBoundingClientRect().width,
127
+ padding + gap * Math.max(0, this.#tabs.length - 1),
128
+ );
129
+ this.#overflowing = tabsWidth > nav.clientWidth + 1;
130
+ this.#syncOverflow();
131
+ }
132
+
133
+ #syncOverflow() {
134
+ const nav = this.#nav;
135
+ if (!nav) return;
136
+ const offset = Math.abs(nav.scrollLeft);
137
+ const max = nav.scrollWidth - nav.clientWidth;
138
+ const start = this.#overflowing && offset > 1;
139
+ const end = this.#overflowing && offset < max - 1;
140
+ nav.style.setProperty("--m-tabs-overflow-start", String(start ? 1 : 0));
141
+ nav.style.setProperty("--m-tabs-overflow-end", String(end ? 1 : 0));
142
+ nav.style.setProperty(
143
+ "--m-tabs-overflow-start-gutter",
144
+ start ? "var(--space-md)" : "0px",
145
+ );
146
+ nav.style.setProperty(
147
+ "--m-tabs-overflow-end-gutter",
148
+ end ? "var(--space-md)" : "0px",
149
+ );
150
+ }
151
+
152
+ #reveal(index) {
153
+ const nav = this.#nav;
154
+ if (!nav || !this.#tabs[index]) return;
155
+ this.#cancelReveal();
156
+ const durations = getComputedStyle(nav, "::before").transitionDuration.split(",");
157
+ const duration = durations.reduce((longest, value) => {
158
+ const time = Number.parseFloat(value) * (value.trim().endsWith("ms") ? 1 : 1000);
159
+ return Math.max(longest, time);
160
+ }, 0);
161
+ // Follow the moving gutters through their transition, plus two frames
162
+ // for the scroll event that activates the newly exposed marker.
163
+ const settleAt = performance.now() + duration + 34;
164
+ let firstFrame = true;
165
+ const reveal = (now) => {
166
+ const nav = this.#nav;
167
+ const tab = this.#tabs[index];
168
+ if (!nav || !tab) return;
169
+ const navRect = nav.getBoundingClientRect();
170
+ const tabRect = tab.getBoundingClientRect();
171
+ const beforeStyle = getComputedStyle(nav, "::before");
172
+ const afterStyle = getComputedStyle(nav, "::after");
173
+ const before = Math.max(0,
174
+ (Number.parseFloat(beforeStyle.inlineSize) || 0) +
175
+ (Number.parseFloat(beforeStyle.marginInlineEnd) || 0));
176
+ const after = Math.max(0,
177
+ (Number.parseFloat(afterStyle.inlineSize) || 0) +
178
+ (Number.parseFloat(afterStyle.marginInlineStart) || 0));
179
+ const rtl = getComputedStyle(nav).direction === "rtl";
180
+ const left = navRect.left + (rtl ? after : before);
181
+ const right = navRect.right - (rtl ? before : after);
182
+ if (tabRect.left < left) nav.scrollBy({ left: tabRect.left - left });
183
+ else if (tabRect.right > right) nav.scrollBy({ left: tabRect.right - right });
184
+ if (firstFrame) {
185
+ this.#syncOverflow();
186
+ firstFrame = false;
187
+ }
188
+ if (now < settleAt) this.#revealFrame = requestAnimationFrame(reveal);
189
+ else this.#revealFrame = null;
190
+ };
191
+ this.#revealFrame = requestAnimationFrame(reveal);
70
192
  }
71
193
 
72
194
  select(index) {
package/types/react.d.ts CHANGED
@@ -51,7 +51,8 @@ declare module 'react' {
51
51
 
52
52
  // components
53
53
  'm-segmented': MicaElement
54
- 'm-tabs': MicaElement
54
+ 'm-stepper': MicaElement
55
+ 'm-tabs': MicaElement<{ variant?: 'underline' }>
55
56
  'm-badge': MicaElement<{
56
57
  variant?: 'primary' | 'success' | 'warning' | 'danger'
57
58
  count?: boolean
@@ -60,6 +61,7 @@ declare module 'react' {
60
61
  blobatar?: string
61
62
  contained?: boolean
62
63
  }>
64
+ 'm-skeleton': MicaElement
63
65
  'm-toast': MicaElement<{
64
66
  popover?: 'manual'
65
67
  variant?: 'success' | 'warning' | 'danger'