@sableui/react 0.1.1 → 0.3.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/AGENTS.md +3 -1
- package/CHANGELOG.md +120 -0
- package/CONTRIBUTING.md +8 -0
- package/README.md +1 -0
- package/bin/sable-lint.mjs +0 -0
- package/bin/sable.mjs +68 -26
- package/dist/{_contract-CYScOdf5.d.ts → _contract-o3tUc8Ig.d.ts} +1 -1
- package/dist/blocks/index.d.ts +396 -0
- package/dist/blocks/index.js +1997 -0
- package/dist/chunk-6LCIBMMG.js +4908 -0
- package/dist/{chunk-J23ELQQZ.js → chunk-CKNM7KSB.js} +1664 -4270
- package/dist/chunk-K6LII3OE.js +5093 -0
- package/dist/{chunk-RWP4XBSK.js → chunk-KFZ43RKU.js} +1 -1
- package/dist/{chunk-PAOZBZME.js → chunk-NGBDP3BM.js} +1 -1
- package/dist/{chunk-5Z5KLOAU.js → chunk-TH563WLW.js} +14 -1
- package/dist/{chunk-JI7WJP2L.js → chunk-X276MF2W.js} +5 -0
- package/dist/foundations/index.js +1 -1
- package/dist/icon/index.js +2 -2
- package/dist/icon-sets/reicon.js +1 -1
- package/dist/index.d.ts +624 -133
- package/dist/index.js +767 -4964
- package/dist/ios/index.d.ts +14 -2
- package/dist/ios/index.js +10 -9
- package/dist/ios/preview.d.ts +11 -1
- package/dist/ios/preview.js +14 -9
- package/dist/ios/styles.css +26 -6
- package/dist/{meta-6dUzgC6M.d.ts → meta-CcE_SeFu.d.ts} +37 -1
- package/dist/patterns/index.d.ts +1 -1
- package/dist/patterns/index.js +1684 -471
- package/dist/presets/index.d.ts +1 -1
- package/dist/presets/index.js +1 -1
- package/dist/styles.css +238 -40
- package/dist/{theme-provider-BWcizhAt.d.ts → theme-provider-BE-KqUG-.d.ts} +1 -1
- package/dist/themes/atelier/atelier.css +3 -0
- package/dist/themes/atelier/index.d.ts +1 -1
- package/dist/themes/base/base.css +34 -4
- package/dist/themes/base/index.d.ts +1 -1
- package/dist/themes/ember/ember.css +3 -0
- package/dist/themes/ember/index.d.ts +1 -1
- package/dist/themes/index.d.ts +2 -2
- package/dist/themes/index.js +2 -2
- package/dist/themes/meridian/index.d.ts +1 -1
- package/dist/themes/meridian/meridian.css +10 -5
- package/dist/themes/poppy/index.d.ts +1 -1
- package/dist/themes/poppy/poppy.css +16 -0
- package/dist/themes/prism/index.d.ts +1 -1
- package/dist/themes/prism/prism.css +4 -1
- package/dist/themes/verdant/index.d.ts +1 -1
- package/dist/themes/verdant/verdant.css +7 -2
- package/llms/blocks/api-keys-block.md +79 -0
- package/llms/blocks/chat-thread-block.md +51 -0
- package/llms/blocks/command-palette-block.md +48 -0
- package/llms/blocks/cta-band-block.md +62 -0
- package/llms/blocks/danger-zone-block.md +69 -0
- package/llms/blocks/device-comparison-block.md +91 -0
- package/llms/blocks/event-card-block.md +84 -0
- package/llms/blocks/faq-block.md +72 -0
- package/llms/blocks/feature-grid-block.md +75 -0
- package/llms/blocks/feedback-form-block.md +66 -0
- package/llms/blocks/goal-progress-block.md +54 -0
- package/llms/blocks/hero-block.md +65 -0
- package/llms/blocks/invite-team-block.md +61 -0
- package/llms/blocks/invoice-history-block.md +84 -0
- package/llms/blocks/kpi-sparkline-block.md +57 -0
- package/llms/blocks/media-player-block.md +100 -0
- package/llms/blocks/newsletter-block.md +64 -0
- package/llms/blocks/not-found-block.md +56 -0
- package/llms/blocks/notification-list-block.md +63 -0
- package/llms/blocks/notification-settings-block.md +54 -0
- package/llms/blocks/order-tracking-block.md +62 -0
- package/llms/blocks/pricing-card-block.md +82 -0
- package/llms/blocks/pricing-table-block.md +129 -0
- package/llms/blocks/product-card-block.md +69 -0
- package/llms/blocks/profile-card-block.md +103 -0
- package/llms/blocks/profile-form-block.md +114 -0
- package/llms/blocks/revenue-breakdown-block.md +70 -0
- package/llms/blocks/sign-in-block.md +64 -0
- package/llms/blocks/sign-up-block.md +78 -0
- package/llms/blocks/site-footer-block.md +96 -0
- package/llms/blocks/stat-row-block.md +59 -0
- package/llms/blocks/steps-block.md +73 -0
- package/llms/blocks/task-list-block.md +81 -0
- package/llms/blocks/team-members-block.md +91 -0
- package/llms/blocks/testimonial-block.md +78 -0
- package/llms/blocks/traffic-sources-block.md +63 -0
- package/llms/blocks/traffic-trend-block.md +95 -0
- package/llms/blocks/upload-list-block.md +66 -0
- package/llms/blocks/verify-code-block.md +59 -0
- package/llms/blocks/wallet-block.md +84 -0
- package/llms/components/area-chart.md +112 -0
- package/llms/components/bar-chart.md +131 -0
- package/llms/components/bubble.md +5 -5
- package/llms/components/button.md +1 -1
- package/llms/components/card.md +2 -2
- package/llms/components/checkbox-card.md +1 -1
- package/llms/components/context-card.md +2 -2
- package/llms/components/context-menu.md +1 -1
- package/llms/components/date-tile.md +79 -0
- package/llms/components/dialog.md +1 -1
- package/llms/components/empty-state.md +4 -4
- package/llms/components/entity.md +5 -3
- package/llms/components/fieldset.md +1 -1
- package/llms/components/kbd.md +18 -6
- package/llms/components/line-chart.md +101 -0
- package/llms/components/menu.md +1 -1
- package/llms/components/{dots-menu.md → overflow-menu.md} +9 -9
- package/llms/components/pie-chart.md +103 -0
- package/llms/components/pill.md +1 -1
- package/llms/components/radar-chart.md +106 -0
- package/llms/components/radial-chart.md +102 -0
- package/llms/components/segmented-bar.md +102 -0
- package/llms/components/settings-menu.md +2 -2
- package/llms/components/side-nav.md +1 -1
- package/llms/components/skeleton.md +1 -1
- package/llms/components/sparkline.md +80 -0
- package/llms/components/table.md +1 -1
- package/llms/components/theme-selector.md +1 -1
- package/llms/foundations/shape.md +1 -1
- package/llms/patterns/auth-page.md +132 -42
- package/llms/patterns/brand-landing-page.md +271 -175
- package/llms/patterns/chat-panel.md +120 -39
- package/llms/patterns/dashboard-page.md +276 -65
- package/llms/patterns/feed-page.md +245 -64
- package/llms/patterns/landing-page.md +473 -75
- package/llms/patterns/list-detail-page.md +377 -68
- package/llms/patterns/settings-page.md +268 -67
- package/llms/reference/token-intent.md +4 -2
- package/llms/reference/utilities.md +20 -5
- package/llms/tasks/building-an-ios-prototype.md +4 -1
- package/llms/tasks/choosing-a-component.md +2 -2
- package/llms-full.txt +6428 -892
- package/llms.txt +67 -16
- package/package.json +5 -1
- package/registry.json +3217 -552
- package/targets/ios.json +88 -18
- package/llms/components/description.md +0 -96
- package/dist/{chunk-L6Y46C62.js → chunk-MXJX3NZI.js} +1 -1
package/dist/ios/index.d.ts
CHANGED
|
@@ -21,8 +21,13 @@ declare function iosThemeStyle(tokens: IosBrandTokens): CSSProperties;
|
|
|
21
21
|
* the chrome and any Sable content then follow the preset together. `tokens`
|
|
22
22
|
* overrides individual semantic values. `mode` also sets `dark` on <html>, so
|
|
23
23
|
* Sable popups portaled to <body> follow the prototype's appearance.
|
|
24
|
+
*
|
|
25
|
+
* `systemChrome={false}` is for a prototype shown on a real phone, without
|
|
26
|
+
* PhoneFrame: the device already draws its own status bar and home indicator,
|
|
27
|
+
* so the fake ones go, and the safe areas come from the device
|
|
28
|
+
* (`env(safe-area-inset-*)`) instead of the standard phone's fixed geometry.
|
|
24
29
|
*/
|
|
25
|
-
declare function NativeApp({ children, mode, glassTint, reducedMotion, className, tokens, style, }: {
|
|
30
|
+
declare function NativeApp({ children, mode, glassTint, reducedMotion, className, tokens, style, systemChrome, }: {
|
|
26
31
|
children: ReactNode;
|
|
27
32
|
mode?: "light" | "dark";
|
|
28
33
|
glassTint?: number;
|
|
@@ -30,6 +35,8 @@ declare function NativeApp({ children, mode, glassTint, reducedMotion, className
|
|
|
30
35
|
className?: string;
|
|
31
36
|
tokens?: IosBrandTokens;
|
|
32
37
|
style?: CSSProperties;
|
|
38
|
+
/** Draw the status bar, island and home indicator. Turn off on a real phone. @default true */
|
|
39
|
+
systemChrome?: boolean;
|
|
33
40
|
}): react.JSX.Element;
|
|
34
41
|
|
|
35
42
|
type Navigation = {
|
|
@@ -45,7 +52,12 @@ declare function NavigationStack({ children, active, label }: {
|
|
|
45
52
|
label: string;
|
|
46
53
|
}): react.JSX.Element;
|
|
47
54
|
|
|
48
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* An iOS 26 sheet. At the medium detent it floats inset from the screen edges in
|
|
57
|
+
* Liquid Glass; at the large detent it is opaque and meets the bottom edge. The
|
|
58
|
+
* header is a glass close button and a centered inline title.
|
|
59
|
+
* Browser dialog owns focus trapping, Escape, inert background, and restoration.
|
|
60
|
+
*/
|
|
49
61
|
declare function IosSheet({ open, onOpenChange, title, children, detent }: {
|
|
50
62
|
open: boolean;
|
|
51
63
|
onOpenChange: (open: boolean) => void;
|
package/dist/ios/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StatusIcons } from '../chunk-NEQNXI2G.js';
|
|
2
|
-
import { App, Sheet, Button, Page, NavbarBackLink, TabbarLink, Navbar, Tabbar
|
|
2
|
+
import { App, Sheet, Button, Glass, Page, NavbarBackLink, TabbarLink, Navbar, Tabbar } from 'konsta/react';
|
|
3
3
|
import { createContext, useEffect, useContext, useState, useRef, useId } from 'react';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -124,7 +124,8 @@ function NativeApp({
|
|
|
124
124
|
reducedMotion = false,
|
|
125
125
|
className = "",
|
|
126
126
|
tokens = {},
|
|
127
|
-
style
|
|
127
|
+
style,
|
|
128
|
+
systemChrome = true
|
|
128
129
|
}) {
|
|
129
130
|
const dark = mode === "dark";
|
|
130
131
|
useEffect(() => {
|
|
@@ -136,18 +137,18 @@ function NativeApp({
|
|
|
136
137
|
{
|
|
137
138
|
theme: "ios",
|
|
138
139
|
dark,
|
|
139
|
-
className: `ios-prototype ${dark ? "dark" : ""} ${className}`,
|
|
140
|
+
className: `ios-prototype ${dark ? "dark" : ""} ${systemChrome ? "" : "ios-bare"} ${className}`,
|
|
140
141
|
"data-reduced-motion": reducedMotion || void 0,
|
|
141
142
|
style: { ...iosThemeStyle(tokens), "--ios-glass-tint": tint, ...style },
|
|
142
143
|
children: [
|
|
143
144
|
/* @__PURE__ */ jsx(LiquidGlassMaterial, {}),
|
|
144
|
-
/* @__PURE__ */ jsxs("div", { className: "ios-status-bar", "aria-hidden": "true", children: [
|
|
145
|
+
systemChrome ? /* @__PURE__ */ jsxs("div", { className: "ios-status-bar", "aria-hidden": "true", children: [
|
|
145
146
|
/* @__PURE__ */ jsx("span", { children: "9:41" }),
|
|
146
147
|
/* @__PURE__ */ jsx("span", { className: "ios-island" }),
|
|
147
148
|
/* @__PURE__ */ jsx(StatusIcons, { className: "ios-status-icons" })
|
|
148
|
-
] }),
|
|
149
|
+
] }) : null,
|
|
149
150
|
children,
|
|
150
|
-
/* @__PURE__ */ jsx("div", { className: "ios-home-indicator", "aria-hidden": "true" })
|
|
151
|
+
systemChrome ? /* @__PURE__ */ jsx("div", { className: "ios-home-indicator", "aria-hidden": "true" }) : null
|
|
151
152
|
]
|
|
152
153
|
}
|
|
153
154
|
);
|
|
@@ -245,7 +246,7 @@ function IosSheet({ open, onOpenChange, title, children, detent = "medium" }) {
|
|
|
245
246
|
onClick: (event) => {
|
|
246
247
|
if (event.target === event.currentTarget) onOpenChange(false);
|
|
247
248
|
},
|
|
248
|
-
children: /* @__PURE__ */ jsxs(Sheet, { opened: shown, backdrop: false, className: "ios-sheet", style: { height: expanded ? "90%" : "56%" }, children: [
|
|
249
|
+
children: /* @__PURE__ */ jsxs(Sheet, { opened: shown, backdrop: false, className: "ios-sheet", "data-detent": expanded ? "large" : "medium", style: { height: expanded ? "90%" : "56%" }, children: [
|
|
249
250
|
/* @__PURE__ */ jsx(
|
|
250
251
|
Button,
|
|
251
252
|
{
|
|
@@ -276,8 +277,8 @@ function IosSheet({ open, onOpenChange, title, children, detent = "medium" }) {
|
|
|
276
277
|
}
|
|
277
278
|
),
|
|
278
279
|
/* @__PURE__ */ jsxs("div", { className: "ios-sheet-heading", children: [
|
|
279
|
-
/* @__PURE__ */ jsx("
|
|
280
|
-
/* @__PURE__ */ jsx(
|
|
280
|
+
/* @__PURE__ */ jsx(Glass, { className: "ios-sheet-close", children: /* @__PURE__ */ jsx(Button, { inline: true, rounded: true, clear: true, className: "ios-icon-action", "aria-label": "Close", onClick: () => onOpenChange(false), children: /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", viewBox: "0 0 16 16", width: "16", height: "16", children: /* @__PURE__ */ jsx("path", { d: "M3.5 3.5l9 9m0-9l-9 9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", fill: "none" }) }) }) }),
|
|
281
|
+
/* @__PURE__ */ jsx("h2", { id: titleId, tabIndex: -1, children: title })
|
|
281
282
|
] }),
|
|
282
283
|
/* @__PURE__ */ jsx("div", { className: "ios-sheet-content", children })
|
|
283
284
|
] })
|
package/dist/ios/preview.d.ts
CHANGED
|
@@ -26,11 +26,21 @@ declare const phoneSizes: {
|
|
|
26
26
|
* scaled, never the viewport, so the prototype lays out as it would on a phone.
|
|
27
27
|
* The document draws its own status bar, island and home indicator, so the
|
|
28
28
|
* frame draws neither.
|
|
29
|
+
*
|
|
30
|
+
* `fit="width"` (the default) scales the device to its host's width and sizes
|
|
31
|
+
* the host to match. `fit="contain"` scales it to fit BOTH of the host's
|
|
32
|
+
* dimensions and centres it, so the whole device stays in view: give the host
|
|
33
|
+
* a height through `className` (a viewport-relative one keeps the phone on
|
|
34
|
+
* screen beside other controls).
|
|
29
35
|
*/
|
|
30
|
-
declare function PhoneFrame({ src, title, size, frameRef, onLoad, }: {
|
|
36
|
+
declare function PhoneFrame({ src, title, size, fit, className, frameRef, onLoad, }: {
|
|
31
37
|
src: string;
|
|
32
38
|
title?: string;
|
|
33
39
|
size?: keyof typeof phoneSizes;
|
|
40
|
+
/** "width" fills the host's width; "contain" fits the host's width and height. @default "width" */
|
|
41
|
+
fit?: "width" | "contain";
|
|
42
|
+
/** Classes for the host box. With fit="contain", this is where its height comes from. */
|
|
43
|
+
className?: string;
|
|
34
44
|
frameRef?: Ref<HTMLIFrameElement>;
|
|
35
45
|
onLoad?: ReactEventHandler<HTMLIFrameElement>;
|
|
36
46
|
}): react.JSX.Element;
|
package/dist/ios/preview.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Phone } from '../chunk-
|
|
1
|
+
import { Phone } from '../chunk-KFZ43RKU.js';
|
|
2
2
|
import '../chunk-NEQNXI2G.js';
|
|
3
|
-
import '../chunk-SRQWQUTW.js';
|
|
3
|
+
import { cn } from '../chunk-SRQWQUTW.js';
|
|
4
4
|
import { useRef, useState, useEffect, useCallback } from 'react';
|
|
5
5
|
import { jsx } from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -15,12 +15,14 @@ function PhoneFrame({
|
|
|
15
15
|
src,
|
|
16
16
|
title = "iPhone prototype",
|
|
17
17
|
size = "standard",
|
|
18
|
+
fit = "width",
|
|
19
|
+
className,
|
|
18
20
|
frameRef,
|
|
19
21
|
onLoad
|
|
20
22
|
}) {
|
|
21
23
|
const host = useRef(null);
|
|
22
24
|
const device = useRef(null);
|
|
23
|
-
const [
|
|
25
|
+
const [box, setBox] = useState({ scale: 1, width: 0, height: 0, offset: 0 });
|
|
24
26
|
const { width, height } = phoneSizes[size];
|
|
25
27
|
useEffect(() => {
|
|
26
28
|
const hostEl = host.current;
|
|
@@ -28,26 +30,29 @@ function PhoneFrame({
|
|
|
28
30
|
if (!hostEl || !deviceEl) return;
|
|
29
31
|
const measure = () => {
|
|
30
32
|
const natural = { width: deviceEl.offsetWidth, height: deviceEl.offsetHeight };
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
if (!natural.width) return setBox({ scale: 1, ...natural, offset: 0 });
|
|
34
|
+
const byHeight = fit === "contain" && hostEl.clientHeight ? hostEl.clientHeight / natural.height : 1;
|
|
35
|
+
const scale = Math.min(1, hostEl.clientWidth / natural.width, byHeight);
|
|
36
|
+
const offset = fit === "contain" ? Math.max(0, (hostEl.clientWidth - natural.width * scale) / 2) : 0;
|
|
37
|
+
setBox({ scale, ...natural, offset });
|
|
33
38
|
};
|
|
34
39
|
const observer = new ResizeObserver(measure);
|
|
35
40
|
observer.observe(hostEl);
|
|
36
41
|
observer.observe(deviceEl);
|
|
37
42
|
return () => observer.disconnect();
|
|
38
|
-
}, []);
|
|
43
|
+
}, [fit]);
|
|
39
44
|
return /* @__PURE__ */ jsx(
|
|
40
45
|
"div",
|
|
41
46
|
{
|
|
42
47
|
ref: host,
|
|
43
|
-
className: "ios-preview-host",
|
|
44
|
-
style: { maxWidth:
|
|
48
|
+
className: cn("ios-preview-host", className),
|
|
49
|
+
style: fit === "contain" ? void 0 : { maxWidth: box.width || void 0, height: box.height ? box.height * box.scale : height },
|
|
45
50
|
children: /* @__PURE__ */ jsx(
|
|
46
51
|
"div",
|
|
47
52
|
{
|
|
48
53
|
ref: device,
|
|
49
54
|
className: "ios-phone-frame",
|
|
50
|
-
style: { width: width / 0.926, transform: `scale(${
|
|
55
|
+
style: { width: width / 0.926, insetInlineStart: box.offset, transform: `scale(${box.scale})` },
|
|
51
56
|
children: /* @__PURE__ */ jsx(Phone, { statusBar: false, systemChrome: false, className: "w-full", children: /* @__PURE__ */ jsx("iframe", { ref: frameRef, onLoad, src, title, className: "ios-phone-screen" }) })
|
|
52
57
|
}
|
|
53
58
|
)
|
package/dist/ios/styles.css
CHANGED
|
@@ -24,6 +24,12 @@
|
|
|
24
24
|
--ios-motion: 300ms; --ios-safe-top: 62px; --ios-header-height: 154px; --ios-tabbar-bottom: 28px; --ios-content-bottom: 110px;
|
|
25
25
|
font-family: var(--font-sans, system-ui, sans-serif); color: var(--ios-ink); background: var(--ios-canvas); height: 100dvh; overflow: hidden;
|
|
26
26
|
}
|
|
27
|
+
/* On a real phone (NativeApp systemChrome={false}): the device's own insets, the
|
|
28
|
+
same chrome heights above and below them. */
|
|
29
|
+
.ios-prototype.ios-bare {
|
|
30
|
+
--ios-safe-top: env(safe-area-inset-top, 0px); --ios-header-height: calc(92px + var(--ios-safe-top));
|
|
31
|
+
--ios-tabbar-bottom: max(12px, env(safe-area-inset-bottom, 0px)); --ios-content-bottom: calc(82px + var(--ios-tabbar-bottom));
|
|
32
|
+
}
|
|
27
33
|
.ios-prototype.dark {
|
|
28
34
|
--ios-canvas: var(--background, #000); --ios-ink: var(--foreground, #f2f2f7); --ios-secondary: var(--muted-foreground, #aeaeb2);
|
|
29
35
|
--ios-panel: var(--card, #1c1c1e); --ios-primary-ink: var(--primary-foreground, #fff);
|
|
@@ -61,17 +67,31 @@
|
|
|
61
67
|
.ios-prototype .native-tabbar > .k-glass { width: 100%; }
|
|
62
68
|
.ios-sheet-dialog { position: fixed; inset: 0; padding: 0; border: 0; width: 100%; max-width: none; height: 100%; max-height: none; background: transparent; color: var(--ios-ink); overflow: hidden; }
|
|
63
69
|
.ios-sheet-dialog::backdrop { background: #0005; }
|
|
64
|
-
.
|
|
70
|
+
/* iOS 26 sheets. Large: opaque, attached to the bottom edge. Medium: floats 8px in from
|
|
71
|
+
the edges, concentric with the screen corners, in the same glass as the bars. */
|
|
72
|
+
.ios-sheet { border-radius: 38px 38px 0 0; background: var(--ios-canvas); transition-duration: var(--ios-motion); padding-bottom: 34px; }
|
|
73
|
+
.ios-sheet[data-detent='medium'] {
|
|
74
|
+
/* Concentric: the top with the close button (its 22px radius + 16px inset), the
|
|
75
|
+
bottom with the 62px screen corner, less the 8px float. */
|
|
76
|
+
left: 8px; right: 8px; top: calc(100% - 8px); border-radius: 38px 38px 54px 54px; padding-bottom: 26px;
|
|
77
|
+
background: color-mix(in srgb, var(--ios-canvas) calc(max(var(--ios-glass-tint, .7), .7) * 100%), transparent);
|
|
78
|
+
-webkit-backdrop-filter: blur(24px) saturate(1.6); backdrop-filter: blur(24px) saturate(1.6);
|
|
79
|
+
box-shadow: inset 0 .75px .5px rgb(255 255 255 / .6), 0 8px 40px color-mix(in srgb, var(--ios-ink) 14%, transparent);
|
|
80
|
+
}
|
|
81
|
+
.ios-prototype.dark .ios-sheet[data-detent='medium'], .dark .ios-sheet[data-detent='medium'] { box-shadow: inset 0 .75px .5px rgb(255 255 255 / .25), 0 8px 40px rgb(0 0 0 / .4); }
|
|
65
82
|
.ios-sheet-grabber { display: flex; margin-inline: auto; width: 80px; touch-action: none; }
|
|
66
83
|
.ios-grabber-mark { width: 36px; height: 5px; border-radius: 4px; background: var(--ios-secondary); }
|
|
67
|
-
|
|
68
|
-
.ios-sheet-heading
|
|
69
|
-
.ios-sheet-heading
|
|
70
|
-
.ios-sheet
|
|
84
|
+
/* A glass close button, a centered inline title, and an empty column that keeps it centered. */
|
|
85
|
+
.ios-sheet-heading { display: grid; grid-template-columns: 44px 1fr 44px; align-items: center; gap: 8px; padding-inline: 16px; }
|
|
86
|
+
.ios-sheet-heading h2 { grid-column: 2; text-align: center; font-size: 17px; line-height: 22px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
87
|
+
.ios-sheet-close { grid-column: 1; grid-row: 1; border-radius: 9999px; color: var(--ios-ink); }
|
|
88
|
+
/* Glass on glass: the sheet already blurs what's behind, and refracting the sheet's own
|
|
89
|
+
flat surface only smears pale patches into the rim. Keep the fill and highlights. */
|
|
90
|
+
.ios-prototype .ios-sheet .k-glass { -webkit-backdrop-filter: none; backdrop-filter: none; }
|
|
71
91
|
.ios-sheet-content { height: calc(100% - 88px); overflow-y: auto; scrollbar-width: none; padding: 16px 20px; }
|
|
72
92
|
.ios-visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
|
|
73
93
|
@keyframes ios-route-enter { from { opacity: .7; transform: translateX(28px); } to { opacity: 1; transform: translateX(0); } }
|
|
74
94
|
@keyframes ios-route-back { from { opacity: .7; transform: translateX(-16px); } to { opacity: 1; transform: translateX(0); } }
|
|
75
95
|
.ios-prototype[data-reduced-motion] *, .ios-prototype[data-reduced-motion] *::before, .ios-prototype[data-reduced-motion] *::after { animation-duration: 0s !important; transition-duration: 0s !important; }
|
|
76
96
|
@media (prefers-reduced-motion: reduce) { .ios-prototype *, .ios-prototype *::before, .ios-prototype *::after { animation-duration: 0s !important; transition-duration: 0s !important; } }
|
|
77
|
-
@media (prefers-reduced-transparency: reduce) { .ios-prototype { --ios-glass-tint: 1 !important; } }
|
|
97
|
+
@media (prefers-reduced-transparency: reduce) { .ios-prototype { --ios-glass-tint: 1 !important; } .ios-sheet[data-detent='medium'] { background: var(--ios-canvas); } }
|
|
@@ -140,6 +140,42 @@ interface PatternMeta {
|
|
|
140
140
|
/** Accessibility notes. */
|
|
141
141
|
a11y?: string[];
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* A block: a section-sized composition of components with sample content —
|
|
145
|
+
* smaller than a page shell, with no behaviour of its own to upgrade. Ships
|
|
146
|
+
* the way patterns do (copy-in source + importable preview). Its props are
|
|
147
|
+
* the block contract only — `className`, `framed` on Card-built blocks, and
|
|
148
|
+
* the primary action's callback — never content; content is the constant at
|
|
149
|
+
* the top of the source, edited after copying.
|
|
150
|
+
*/
|
|
151
|
+
interface BlockMeta {
|
|
152
|
+
/** Block name, e.g. "SignInBlock". Always ends in "Block". */
|
|
153
|
+
name: string;
|
|
154
|
+
/** One-line summary. */
|
|
155
|
+
summary: string;
|
|
156
|
+
/** When to reach for this block — and when a component or page shell fits better. */
|
|
157
|
+
intent: string;
|
|
158
|
+
/**
|
|
159
|
+
* "card" — one self-contained object that fills its container up to a
|
|
160
|
+
* designed width. "section" — a full-width band of a page.
|
|
161
|
+
*/
|
|
162
|
+
kind: "card" | "section";
|
|
163
|
+
/**
|
|
164
|
+
* The width range it is designed for, as CSS lengths. The block renders
|
|
165
|
+
* `w-full` capped at `max`; `min` is the narrowest it still holds together
|
|
166
|
+
* (a grid's `minItemWidth`). Section blocks omit it.
|
|
167
|
+
*/
|
|
168
|
+
width?: {
|
|
169
|
+
min: string;
|
|
170
|
+
max: string;
|
|
171
|
+
};
|
|
172
|
+
/** Groups related blocks in the catalog ("Auth", "Commerce", …). */
|
|
173
|
+
family: string;
|
|
174
|
+
/** Canonical decisions the block encodes. */
|
|
175
|
+
notes?: string[];
|
|
176
|
+
/** Accessibility notes. */
|
|
177
|
+
a11y?: string[];
|
|
178
|
+
}
|
|
143
179
|
interface ComponentMeta {
|
|
144
180
|
/** Public component name, e.g. "Button". Must be an actual export. */
|
|
145
181
|
name: string;
|
|
@@ -202,4 +238,4 @@ interface ComponentMeta {
|
|
|
202
238
|
examples: ExampleMeta[];
|
|
203
239
|
}
|
|
204
240
|
|
|
205
|
-
export type { AnatomyMeta as A,
|
|
241
|
+
export type { AnatomyMeta as A, BlockMeta as B, ComponentMeta as C, ExampleMeta as E, MotionMeta as M, PatternMeta as P, RelatedMeta as R, SubcomponentMeta as S, UsageMeta as U, BestPracticeMeta as a, MotionSlot as b, PropMeta as c };
|
package/dist/patterns/index.d.ts
CHANGED