@krizaka/ui 3.5.0 → 3.7.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/README.md +1 -0
- package/dist/app-shell.d.ts +24 -22
- package/dist/app-shell.js +9 -3
- package/dist/app-shell.js.map +1 -1
- package/dist/chat.js +2 -1
- package/dist/chat.js.map +1 -1
- package/dist/chunk-3GODX3D6.js +25 -0
- package/dist/chunk-3GODX3D6.js.map +1 -0
- package/dist/{chunk-F2GKFIYK.js → chunk-CURW36FI.js} +1 -1
- package/dist/chunk-JXLDUDTD.js +2 -0
- package/dist/chunk-JXLDUDTD.js.map +1 -0
- package/dist/{chunk-R6SDS7JM.js → chunk-ND3L5VHT.js} +25 -2
- package/dist/chunk-ND3L5VHT.js.map +1 -0
- package/dist/chunk-NPF3OHE2.js +2 -0
- package/dist/chunk-NPF3OHE2.js.map +1 -0
- package/dist/{chunk-ECSCA3CN.js → chunk-UOMP6VOZ.js} +1 -1
- package/dist/command.js +1 -1
- package/dist/data-table.js +2 -1
- package/dist/data-table.js.map +1 -1
- package/dist/dialog.js +7 -3
- package/dist/dialog.js.map +1 -1
- package/dist/loader.d.ts +21 -1
- package/dist/loader.js +7 -3
- package/dist/loader.js.map +1 -1
- package/dist/map.js +7 -1
- package/dist/map.js.map +1 -1
- package/dist/marketing-layout.d.ts +3 -9
- package/dist/marketing-layout.js +24 -7
- package/dist/marketing-layout.js.map +1 -1
- package/dist/match-dialog.d.ts +3 -1
- package/dist/match-dialog.js +29 -5
- package/dist/match-dialog.js.map +1 -1
- package/dist/native/vertical-video.d.ts +102 -0
- package/dist/native/vertical-video.js +163 -0
- package/dist/native/vertical-video.js.map +1 -0
- package/dist/native.d.ts +65 -2
- package/dist/native.js +960 -878
- package/dist/native.js.map +1 -1
- package/dist/skip-link.d.ts +15 -0
- package/dist/skip-link.js +10 -0
- package/dist/skip-link.js.map +1 -0
- package/dist/tree-view.d.ts +2 -0
- package/dist/tree-view.js.map +1 -1
- package/dist/vertical-video.d.ts +112 -0
- package/dist/vertical-video.js +307 -0
- package/dist/vertical-video.js.map +1 -0
- package/package.json +56 -8
- package/registry/achievement.json +2 -1
- package/registry/action-bar.json +2 -1
- package/registry/action-sheet.json +1 -0
- package/registry/activity-feed.json +2 -1
- package/registry/alert.json +2 -1
- package/registry/app-shell.json +27 -5
- package/registry/argument-card.json +2 -1
- package/registry/audio-player.json +2 -1
- package/registry/auth-layout.json +7 -2
- package/registry/avatar.json +7 -6
- package/registry/badge.json +2 -1
- package/registry/button.json +2 -1
- package/registry/card-grid.json +2 -1
- package/registry/card.json +2 -1
- package/registry/catalogue-page.json +5 -2
- package/registry/changelog-page.json +5 -2
- package/registry/chat.json +2 -1
- package/registry/checkbox.json +2 -1
- package/registry/chip-link.json +2 -1
- package/registry/chip.json +2 -1
- package/registry/choice-grid.json +2 -1
- package/registry/cn.json +1 -0
- package/registry/code-block.json +2 -1
- package/registry/combobox.json +2 -1
- package/registry/command.json +2 -1
- package/registry/component-page.json +5 -2
- package/registry/confirm-button.json +2 -1
- package/registry/contact-page.json +5 -2
- package/registry/continue-prompt.json +2 -1
- package/registry/countdown.json +2 -1
- package/registry/cta-panel.json +2 -1
- package/registry/dashboard-layout.json +5 -2
- package/registry/data-table.json +2 -1
- package/registry/date-picker.json +3 -2
- package/registry/decision-list.json +2 -1
- package/registry/description-list.json +2 -1
- package/registry/detail-layout.json +16 -2
- package/registry/dialog.json +10 -4
- package/registry/docs-article-page.json +16 -2
- package/registry/docs-hub-page.json +5 -2
- package/registry/docs-layout.json +2 -1
- package/registry/dropdown-menu.json +2 -1
- package/registry/empty-state.json +14 -2
- package/registry/error-page.json +5 -2
- package/registry/examples/avatar/group.js +4 -7
- package/registry/examples/avatar/group.tsx +4 -11
- package/registry/examples/avatar/native/group.dark.png +0 -0
- package/registry/examples/avatar/native/group.js +4 -4
- package/registry/examples/avatar/native/group.light.png +0 -0
- package/registry/examples/avatar/native/group.tsx +4 -4
- package/registry/examples/avatar/native/presence.dark.png +0 -0
- package/registry/examples/avatar/native/presence.js +8 -5
- package/registry/examples/avatar/native/presence.light.png +0 -0
- package/registry/examples/avatar/native/presence.tsx +9 -5
- package/registry/examples/avatar/with-image.js +1 -4
- package/registry/examples/avatar/with-image.tsx +2 -9
- package/registry/examples/detail-layout/checkout.d.ts +4 -0
- package/registry/examples/detail-layout/checkout.js +37 -0
- package/registry/examples/detail-layout/checkout.tsx +44 -0
- package/registry/examples/docs-article-page/faq.d.ts +4 -0
- package/registry/examples/docs-article-page/faq.js +31 -0
- package/registry/examples/docs-article-page/faq.tsx +40 -0
- package/registry/examples/empty-state/library.d.ts +4 -0
- package/registry/examples/empty-state/library.js +25 -0
- package/registry/examples/empty-state/library.tsx +20 -0
- package/registry/examples/loader/branded.d.ts +4 -0
- package/registry/examples/loader/branded.js +12 -0
- package/registry/examples/loader/branded.tsx +7 -0
- package/registry/examples/loader/native/branded.d.ts +4 -0
- package/registry/examples/loader/native/branded.dark.png +0 -0
- package/registry/examples/loader/native/branded.js +12 -0
- package/registry/examples/loader/native/branded.light.png +0 -0
- package/registry/examples/loader/native/branded.tsx +11 -0
- package/registry/examples/longform-page/case-study.d.ts +4 -0
- package/registry/examples/longform-page/case-study.js +41 -0
- package/registry/examples/longform-page/case-study.tsx +40 -0
- package/registry/examples/profile-card/creator.js +2 -2
- package/registry/examples/profile-card/creator.tsx +2 -2
- package/registry/examples/profile-card/match.js +2 -2
- package/registry/examples/profile-card/match.tsx +2 -2
- package/registry/examples/profile-card/native/default.dark.png +0 -0
- package/registry/examples/profile-card/native/default.js +2 -2
- package/registry/examples/profile-card/native/default.light.png +0 -0
- package/registry/examples/profile-card/native/default.tsx +2 -2
- package/registry/examples/pull-to-refresh/native/branded.d.ts +4 -0
- package/registry/examples/pull-to-refresh/native/branded.dark.png +0 -0
- package/registry/examples/pull-to-refresh/native/branded.js +14 -0
- package/registry/examples/pull-to-refresh/native/branded.light.png +0 -0
- package/registry/examples/pull-to-refresh/native/branded.tsx +23 -0
- package/registry/examples/screen/native/app-shell.dark.png +0 -0
- package/registry/examples/screen/native/app-shell.js +1 -1
- package/registry/examples/screen/native/app-shell.light.png +0 -0
- package/registry/examples/screen/native/app-shell.tsx +1 -1
- package/registry/examples/screen/native/feed.dark.png +0 -0
- package/registry/examples/screen/native/feed.js +31 -14
- package/registry/examples/screen/native/feed.light.png +0 -0
- package/registry/examples/screen/native/feed.tsx +28 -24
- package/registry/examples/screen/native/map.d.ts +4 -0
- package/registry/examples/screen/native/map.dark.png +0 -0
- package/registry/examples/screen/native/map.js +26 -0
- package/registry/examples/screen/native/map.light.png +0 -0
- package/registry/examples/screen/native/map.tsx +31 -0
- package/registry/examples/screen/native/notifications.d.ts +4 -0
- package/registry/examples/screen/native/notifications.dark.png +0 -0
- package/registry/examples/screen/native/notifications.js +21 -0
- package/registry/examples/screen/native/notifications.light.png +0 -0
- package/registry/examples/screen/native/notifications.tsx +21 -0
- package/registry/examples/screen/native/profile.dark.png +0 -0
- package/registry/examples/screen/native/profile.js +2 -2
- package/registry/examples/screen/native/profile.light.png +0 -0
- package/registry/examples/screen/native/profile.tsx +2 -2
- package/registry/examples/skip-link/default.d.ts +4 -0
- package/registry/examples/skip-link/default.js +19 -0
- package/registry/examples/skip-link/default.tsx +12 -0
- package/registry/examples/splash-handoff/native/default.d.ts +4 -0
- package/registry/examples/splash-handoff/native/default.dark.png +0 -0
- package/registry/examples/splash-handoff/native/default.js +12 -0
- package/registry/examples/splash-handoff/native/default.light.png +0 -0
- package/registry/examples/splash-handoff/native/default.tsx +11 -0
- package/registry/examples/split-view/nearby.d.ts +4 -0
- package/registry/examples/split-view/nearby.js +33 -0
- package/registry/examples/split-view/nearby.tsx +45 -0
- package/registry/examples/split-view/notifications.d.ts +4 -0
- package/registry/examples/split-view/notifications.js +33 -0
- package/registry/examples/split-view/notifications.tsx +31 -0
- package/registry/examples/status-page/maintenance.d.ts +4 -0
- package/registry/examples/status-page/maintenance.js +29 -0
- package/registry/examples/status-page/maintenance.tsx +24 -0
- package/registry/examples/swipe-deck/discover.js +2 -3
- package/registry/examples/swipe-deck/discover.tsx +2 -3
- package/registry/examples/swipe-deck/native/discover.dark.png +0 -0
- package/registry/examples/swipe-deck/native/discover.js +2 -3
- package/registry/examples/swipe-deck/native/discover.light.png +0 -0
- package/registry/examples/swipe-deck/native/discover.tsx +2 -3
- package/registry/examples/vertical-video/feed.d.ts +4 -0
- package/registry/examples/vertical-video/feed.js +40 -0
- package/registry/examples/vertical-video/feed.tsx +36 -0
- package/registry/examples/vertical-video/native/rail.d.ts +4 -0
- package/registry/examples/vertical-video/native/rail.dark.png +0 -0
- package/registry/examples/vertical-video/native/rail.js +39 -0
- package/registry/examples/vertical-video/native/rail.light.png +0 -0
- package/registry/examples/vertical-video/native/rail.tsx +37 -0
- package/registry/examples/vertical-video/rail.d.ts +4 -0
- package/registry/examples/vertical-video/rail.js +39 -0
- package/registry/examples/vertical-video/rail.tsx +39 -0
- package/registry/fab.json +1 -0
- package/registry/field.json +2 -1
- package/registry/file-upload.json +3 -2
- package/registry/filter-bar.json +2 -1
- package/registry/form.json +3 -2
- package/registry/gallery-page.json +5 -2
- package/registry/glow-card.json +2 -1
- package/registry/goal-gauge.json +2 -1
- package/registry/header.json +1 -0
- package/registry/how-it-works-page.json +5 -2
- package/registry/image-cropper.json +2 -1
- package/registry/image-viewer.json +1 -0
- package/registry/index.json +492 -22
- package/registry/iso.json +2 -1
- package/registry/kanban.json +2 -1
- package/registry/kbd.json +2 -1
- package/registry/landing-page.json +5 -2
- package/registry/landscape.json +2 -1
- package/registry/legal-page.json +5 -2
- package/registry/link-card.json +2 -1
- package/registry/list.json +2 -1
- package/registry/loader.json +47 -3
- package/registry/longform-page.json +16 -2
- package/registry/map.json +4 -3
- package/registry/marketing-layout.json +13 -4
- package/registry/marquee.json +2 -1
- package/registry/mascot-quote.json +2 -1
- package/registry/mascot-state.json +2 -1
- package/registry/mascots.json +2 -1
- package/registry/match-dialog.json +17 -2
- package/registry/media-capture.json +2 -1
- package/registry/media-picker.json +1 -0
- package/registry/meter.json +2 -1
- package/registry/nav-bar.json +2 -1
- package/registry/number-ticker.json +2 -1
- package/registry/onboarding.json +1 -0
- package/registry/otp-input.json +1 -0
- package/registry/page-header.json +2 -1
- package/registry/page-hero.json +2 -1
- package/registry/page.json +2 -1
- package/registry/pagination.json +2 -1
- package/registry/permission-prompt.json +1 -0
- package/registry/photo-grid.json +2 -1
- package/registry/pointer-light.json +2 -1
- package/registry/popover.json +2 -1
- package/registry/pricing-page.json +5 -2
- package/registry/product-page.json +5 -2
- package/registry/profile-card.json +6 -5
- package/registry/progress.json +2 -1
- package/registry/promise-card.json +2 -1
- package/registry/pull-to-refresh.json +68 -4
- package/registry/radio-group.json +2 -1
- package/registry/screen.json +55 -6
- package/registry/scroll-stage.json +2 -1
- package/registry/search-field.json +2 -1
- package/registry/section-backdrop.json +2 -1
- package/registry/segmented.json +1 -0
- package/registry/separator.json +2 -1
- package/registry/settings-layout.json +5 -2
- package/registry/skeleton.json +2 -1
- package/registry/skip-link.json +122 -0
- package/registry/slider.json +2 -1
- package/registry/slot.json +2 -1
- package/registry/spinner.json +2 -1
- package/registry/splash-handoff.json +138 -0
- package/registry/split-view.json +27 -2
- package/registry/stage-banner.json +2 -1
- package/registry/stat.json +2 -1
- package/registry/status-page.json +18 -2
- package/registry/step-progress.json +2 -1
- package/registry/stepper.json +2 -1
- package/registry/swipe-deck.json +5 -4
- package/registry/swipeable-row.json +1 -0
- package/registry/switch.json +2 -1
- package/registry/tab-bar.json +1 -0
- package/registry/tabs.json +2 -1
- package/registry/tag-input.json +2 -1
- package/registry/tag-selector.json +2 -1
- package/registry/terminal-replay.json +2 -1
- package/registry/theme.json +2 -1
- package/registry/toast.json +2 -1
- package/registry/toc.json +2 -1
- package/registry/tooltip.json +2 -1
- package/registry/tree-view.json +10 -4
- package/registry/txt.json +1 -0
- package/registry/verified-badge.json +2 -1
- package/registry/vertical-video.json +871 -0
- package/registry/video-player.json +2 -1
- package/registry/video-trimmer.json +2 -1
- package/registry/virtual.json +2 -1
- package/dist/chunk-R6SDS7JM.js.map +0 -1
- /package/dist/{chunk-F2GKFIYK.js.map → chunk-CURW36FI.js.map} +0 -0
- /package/dist/{chunk-ECSCA3CN.js.map → chunk-UOMP6VOZ.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/marketing-layout/marketing-layout.tsx"],"sourcesContent":["// Server-safe. The page of a site (krizaka.com, a product's public pages): a link to skip to the content, the site's\n// bar, the page — its PageHero and Sections (@krizaka/ui/page) — and the footer. The bar floats over the hero\n// (`--kz-hero-top` clears it); everything shares the page frame (`--kz-page-max`, `--kz-page-gutter`).\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const marketingLayout = tv({\n slots: {\n root: \"flex min-h-dvh w-full flex-col bg-surface-0 text-fg\",\n
|
|
1
|
+
{"version":3,"sources":["../src/skip-link/skip-link.tsx","../src/marketing-layout/marketing-layout.tsx"],"sourcesContent":["// Client (it moves focus). WCAG 2.4.1 Bypass Blocks: the first tab stop of a page, a link that skips the navigation and\n// lands on the content. Visually hidden until focused, then a pill above everything in the brand ring. The label is\n// passed translated; the target needs an `id` (and is made focusable, so focus really moves, router or not).\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const skipLink = tv({\n base:\n \"sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-[100] focus:rounded-full focus:bg-surface-1 focus:px-4 focus:py-2 \" +\n \"focus:text-sm focus:font-semibold focus:text-fg focus:no-underline focus:shadow-lg focus:outline-hidden focus:ring-2 focus:ring-ring\",\n});\n\nexport type SkipLinkProps = Omit<React.ComponentProps<\"a\">, \"href\"> & {\n /**\n * The content to land on: `#` and its `id`. The element becomes focusable (`tabindex=\"-1\"`) when it is not.\n * @default \"#content\"\n */\n href?: `#${string}`;\n};\n\n/** A \"skip to content\" link: the first tab stop, hidden until focused; Enter moves focus to the target. */\nexport function SkipLink({ href = \"#content\", className, onClick, children, ...props }: SkipLinkProps) {\n const handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n const target = document.getElementById(decodeURIComponent(href.slice(1)));\n if (!target) return;\n if (!target.hasAttribute(\"tabindex\") && !target.matches(\"a[href], button, input, select, textarea, [contenteditable]\")) target.setAttribute(\"tabindex\", \"-1\");\n target.focus();\n };\n return (\n <a href={href} className={skipLink({ className })} onClick={handleClick} {...props}>\n {children}\n </a>\n );\n}\n","// Server-safe. The page of a site (krizaka.com, a product's public pages): a link to skip to the content, the site's\n// bar, the page — its PageHero and Sections (@krizaka/ui/page) — and the footer. The bar floats over the hero\n// (`--kz-hero-top` clears it); everything shares the page frame (`--kz-page-max`, `--kz-page-gutter`).\nimport { SkipLink } from \"@krizaka/ui/skip-link\";\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const marketingLayout = tv({\n slots: {\n root: \"flex min-h-dvh w-full flex-col bg-surface-0 text-fg\",\n header: \"fixed inset-x-0 top-3 z-50 px-(--kz-page-gutter,16px) pointer-events-none *:pointer-events-auto\",\n main: \"flex-1 outline-hidden\",\n },\n});\nconst s = marketingLayout();\n\nexport type MarketingLayoutProps = React.ComponentProps<\"div\"> & {\n /** The site's bar (a floating NavBar of @krizaka/ui/nav-bar). */\n header: React.ReactNode;\n /** The site's footer. */\n footer?: React.ReactNode;\n /** The words of the link that skips to the content (`Skip to content`). */\n skipLabel: string;\n /** The page: a PageHero, then Sections. */\n children: React.ReactNode;\n};\n\n/** A site's page: skip link, floating bar, the page, the footer. */\nexport function MarketingLayout({ header, footer, skipLabel, className, children, ...props }: MarketingLayoutProps) {\n return (\n <div className={s.root({ className })} {...props}>\n <SkipLink>{skipLabel}</SkipLink>\n <div className={s.header()}>{header}</div>\n <main id=\"content\" tabIndex={-1} className={s.main()}>\n {children}\n </main>\n {footer}\n </div>\n );\n}\n"],"mappings":";AAIA,SAAS,UAAU;AA2Bf;AAzBG,IAAM,WAAW,GAAG;AAAA,EACzB,MACE;AAEJ,CAAC;AAWM,SAAS,SAAS,EAAE,OAAO,YAAY,WAAW,SAAS,UAAU,GAAG,MAAM,GAAkB;AACrG,QAAM,cAAc,CAAC,UAA+C;AAClE,cAAU,KAAK;AACf,QAAI,MAAM,iBAAkB;AAC5B,UAAM,SAAS,SAAS,eAAe,mBAAmB,KAAK,MAAM,CAAC,CAAC,CAAC;AACxE,QAAI,CAAC,OAAQ;AACb,QAAI,CAAC,OAAO,aAAa,UAAU,KAAK,CAAC,OAAO,QAAQ,6DAA6D,EAAG,QAAO,aAAa,YAAY,IAAI;AAC5J,WAAO,MAAM;AAAA,EACf;AACA,SACE,oBAAC,OAAE,MAAY,WAAW,SAAS,EAAE,UAAU,CAAC,GAAG,SAAS,aAAc,GAAG,OAC1E,UACH;AAEJ;;;AC9BA,SAAS,MAAAA,WAAU;AAyBf,SACE,OAAAC,MADF;AAvBG,IAAM,kBAAkBD,IAAG;AAAA,EAChC,OAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,EACR;AACF,CAAC;AACD,IAAM,IAAI,gBAAgB;AAcnB,SAAS,gBAAgB,EAAE,QAAQ,QAAQ,WAAW,WAAW,UAAU,GAAG,MAAM,GAAyB;AAClH,SACE,qBAAC,SAAI,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OACzC;AAAA,oBAAAC,KAAC,YAAU,qBAAU;AAAA,IACrB,gBAAAA,KAAC,SAAI,WAAW,EAAE,OAAO,GAAI,kBAAO;AAAA,IACpC,gBAAAA,KAAC,UAAK,IAAG,WAAU,UAAU,IAAI,WAAW,EAAE,KAAK,GAChD,UACH;AAAA,IACC;AAAA,KACH;AAEJ;","names":["tv","jsx"]}
|
package/dist/match-dialog.d.ts
CHANGED
|
@@ -23,8 +23,10 @@ type MatchDialogProps = {
|
|
|
23
23
|
onPrimary: () => void;
|
|
24
24
|
/** The way back (“Keep swiping”). */
|
|
25
25
|
secondaryLabel: string;
|
|
26
|
+
/** Where it is drawn (the page's body by default): give an element inside a brand scope (`.brand-…`) so the dialog wears the brand too. */
|
|
27
|
+
container?: HTMLElement | null;
|
|
26
28
|
};
|
|
27
29
|
/** Two people choose each other: the avatars meet at a heart in the brand gradient, the next step under them. */
|
|
28
|
-
declare function MatchDialog({ open, onOpenChange, title, description, people, primaryLabel, onPrimary, secondaryLabel }: MatchDialogProps): React.JSX.Element;
|
|
30
|
+
declare function MatchDialog({ open, onOpenChange, title, description, people, primaryLabel, onPrimary, secondaryLabel, container }: MatchDialogProps): React.JSX.Element;
|
|
29
31
|
|
|
30
32
|
export { MatchDialog, type MatchDialogProps };
|
package/dist/match-dialog.js
CHANGED
|
@@ -1,15 +1,36 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import "./chunk-NPF3OHE2.js";
|
|
2
3
|
import {
|
|
3
4
|
Avatar
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-CURW36FI.js";
|
|
6
|
+
import "./chunk-JXLDUDTD.js";
|
|
5
7
|
import {
|
|
6
8
|
Button,
|
|
7
9
|
IconButton
|
|
8
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-UOMP6VOZ.js";
|
|
9
11
|
|
|
10
12
|
// src/dialog/dialog.tsx
|
|
11
13
|
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
12
14
|
import { tv } from "tailwind-variants";
|
|
15
|
+
|
|
16
|
+
// src/dialog/return-focus.ts
|
|
17
|
+
import * as React from "react";
|
|
18
|
+
function useReturnFocus(onCloseAutoFocus) {
|
|
19
|
+
const [opener] = React.useState(() => typeof document === "undefined" ? null : document.activeElement);
|
|
20
|
+
return React.useCallback(
|
|
21
|
+
(event) => {
|
|
22
|
+
onCloseAutoFocus?.(event);
|
|
23
|
+
if (event.defaultPrevented) return;
|
|
24
|
+
if (opener instanceof HTMLElement && opener !== document.body && opener.isConnected) {
|
|
25
|
+
event.preventDefault();
|
|
26
|
+
opener.focus();
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
[opener, onCloseAutoFocus]
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/dialog/dialog.tsx
|
|
13
34
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
35
|
var dialog = tv({
|
|
15
36
|
slots: {
|
|
@@ -42,6 +63,9 @@ function CloseIcon() {
|
|
|
42
63
|
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) });
|
|
43
64
|
}
|
|
44
65
|
var prevent = (event) => event.preventDefault();
|
|
66
|
+
function ReturnFocusContent({ onCloseAutoFocus, ...props }) {
|
|
67
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Content, { onCloseAutoFocus: useReturnFocus(onCloseAutoFocus), ...props });
|
|
68
|
+
}
|
|
45
69
|
function DialogContent({
|
|
46
70
|
placement,
|
|
47
71
|
size,
|
|
@@ -60,7 +84,7 @@ function DialogContent({
|
|
|
60
84
|
return /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { container, children: [
|
|
61
85
|
/* @__PURE__ */ jsx(DialogPrimitive.Overlay, { className: v.overlay() }),
|
|
62
86
|
/* @__PURE__ */ jsxs(
|
|
63
|
-
|
|
87
|
+
ReturnFocusContent,
|
|
64
88
|
{
|
|
65
89
|
"data-placement": placement ?? "center",
|
|
66
90
|
"data-dismissible": dismissible ? void 0 : "false",
|
|
@@ -112,8 +136,8 @@ var Dialog = {
|
|
|
112
136
|
|
|
113
137
|
// src/match-dialog/match-dialog.tsx
|
|
114
138
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
115
|
-
function MatchDialog({ open, onOpenChange, title, description, people, primaryLabel, onPrimary, secondaryLabel }) {
|
|
116
|
-
return /* @__PURE__ */ jsx2(Dialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs2(Dialog.Content, { hideClose: true, size: "sm", className: "overflow-hidden border-0 bg-gradient-to-br from-accent to-accent-2 text-center text-on-accent", children: [
|
|
139
|
+
function MatchDialog({ open, onOpenChange, title, description, people, primaryLabel, onPrimary, secondaryLabel, container }) {
|
|
140
|
+
return /* @__PURE__ */ jsx2(Dialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs2(Dialog.Content, { hideClose: true, size: "sm", container, className: "overflow-hidden border-0 bg-gradient-to-br from-accent to-accent-2 text-center text-on-accent", children: [
|
|
117
141
|
/* @__PURE__ */ jsx2("style", { href: "krizaka-match", precedence: "default", children: "@media (prefers-reduced-motion:no-preference){[data-kz-match] [data-side=a]{animation:kz-match-a .55s cubic-bezier(.3,1.6,.5,1) both}[data-kz-match] [data-side=b]{animation:kz-match-b .55s cubic-bezier(.3,1.6,.5,1) both}[data-kz-match] [data-heart]{animation:kz-match-heart .45s .25s cubic-bezier(.3,1.6,.5,1) both}}@keyframes kz-match-a{from{transform:translateX(-60px) rotate(-8deg);opacity:0}}@keyframes kz-match-b{from{transform:translateX(60px) rotate(8deg);opacity:0}}@keyframes kz-match-heart{from{transform:scale(0)}}" }),
|
|
118
142
|
/* @__PURE__ */ jsxs2("div", { "data-kz-match": "", className: "flex flex-col items-center gap-3 px-2 pb-2 pt-6", children: [
|
|
119
143
|
/* @__PURE__ */ jsx2(Dialog.Title, { className: "font-display text-4xl font-black text-on-accent", children: title }),
|
package/dist/match-dialog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dialog/dialog.tsx","../src/match-dialog/match-dialog.tsx"],"sourcesContent":["// Client (a portal). Radix does the focus trap, the scroll lock, Escape, the outside click, aria-modal, the\n// aria-labelledby / aria-describedby wiring and the focus return: this file only holds the shape.\nimport { Dialog as DialogPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { IconButton } from \"../button/button\";\n\nexport const dialog = tv({\n slots: {\n overlay: \"kz-overlay fixed inset-0 z-50 bg-overlay backdrop-blur-xs\",\n content:\n \"kz-dialog fixed z-50 flex flex-col overflow-hidden border border-border-default bg-surface-1 text-fg shadow-lg focus:outline-hidden\",\n close: \"absolute right-3 top-3 h-9 w-9\",\n header: \"flex flex-col gap-1 px-5 pb-2 pr-14 pt-5\",\n title: \"text-base font-bold text-fg\",\n description: \"text-sm text-fg-secondary\",\n body: \"min-h-0 flex-1 overflow-y-auto px-5 pb-5\",\n footer:\n \"flex flex-wrap items-center justify-end gap-2 border-t border-border-subtle px-5 py-4 pb-[max(1rem,env(safe-area-inset-bottom))]\",\n },\n variants: {\n placement: {\n center: { content: \"left-1/2 top-1/2 max-h-[85dvh] w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 rounded-xl\" },\n /* A sheet: anchored at the bottom on a phone, centred from `sm` up. */\n bottom: {\n content:\n \"inset-x-0 bottom-0 max-h-[92dvh] rounded-t-[1.75rem] sm:bottom-auto sm:left-1/2 sm:top-1/2 sm:w-full \" +\n \"sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-[1.75rem]\",\n },\n right: { content: \"inset-y-0 right-0 h-full w-full max-w-md rounded-none border-y-0 border-r-0\" },\n /* A navigation drawer: full height, from the left, clear of the notch. */\n left: { content: \"inset-y-0 left-0 h-full w-full max-w-md rounded-none border-y-0 border-l-0 pl-[env(safe-area-inset-left)]\" },\n },\n size: { sm: { content: \"sm:max-w-sm\" }, md: { content: \"sm:max-w-md\" }, lg: { content: \"sm:max-w-2xl\" } },\n },\n defaultVariants: { placement: \"center\", size: \"md\" },\n});\nconst s = dialog();\n\nexport type DialogVariants = VariantProps<typeof dialog>;\n\nfunction CloseIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\ntype CloseButtonProps =\n | {\n /** The accessible name of the close button — passed translated. */\n closeLabel: string;\n /** Leaves the close button out (the content brings its own way out, or none: see `dismissible`). */\n hideClose?: false;\n }\n | { closeLabel?: string; hideClose: true };\n\nexport type DialogContentProps = React.ComponentProps<typeof DialogPrimitive.Content> &\n DialogVariants &\n CloseButtonProps & {\n /**\n * center · bottom (a sheet on a phone, centred from `sm` up) · right (a side panel, full height) · left (a\n * navigation drawer, full height).\n * @default \"center\"\n */\n placement?: DialogVariants[\"placement\"];\n /**\n * sm · md · lg: the width of the dialog.\n * @default \"md\"\n */\n size?: DialogVariants[\"size\"];\n /**\n * `false`: Escape and a click outside do not close it (a gate the user must answer: age, terms). It still closes\n * through `open` / `onOpenChange` and any `Dialog.Close` inside. Default `true`.\n */\n dismissible?: boolean;\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n };\n\nconst prevent = (event: Event) => event.preventDefault();\n\n/** The dialog itself, portalled over a dimmed overlay, with a close button. Give it a `Dialog.Title`. */\nexport function DialogContent({\n placement,\n size,\n closeLabel,\n hideClose,\n dismissible = true,\n container,\n className,\n children,\n onEscapeKeyDown,\n onPointerDownOutside,\n onInteractOutside,\n ...props\n}: DialogContentProps) {\n const v = dialog({ placement, size });\n return (\n <DialogPrimitive.Portal container={container}>\n <DialogPrimitive.Overlay className={v.overlay()} />\n <DialogPrimitive.Content\n data-placement={placement ?? \"center\"}\n data-dismissible={dismissible ? undefined : \"false\"}\n className={v.content({ className })}\n onEscapeKeyDown={dismissible ? onEscapeKeyDown : chain(onEscapeKeyDown, prevent)}\n onPointerDownOutside={dismissible ? onPointerDownOutside : chain(onPointerDownOutside, prevent)}\n onInteractOutside={dismissible ? onInteractOutside : chain(onInteractOutside, prevent)}\n {...props}\n >\n {children}\n {!hideClose && (\n <DialogPrimitive.Close asChild>\n <IconButton label={closeLabel as string} variant=\"ghost\" shape=\"pill\" className={v.close()}>\n <CloseIcon />\n </IconButton>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n );\n}\n\nfunction chain<E extends Event>(handler: ((event: E) => void) | undefined, then: (event: E) => void) {\n return (event: E) => {\n handler?.(event);\n then(event);\n };\n}\n\nexport function DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.header({ className })} {...props} />;\n}\n\nexport function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return <DialogPrimitive.Title className={s.title({ className })} {...props} />;\n}\n\nexport function DialogDescription({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return <DialogPrimitive.Description className={s.description({ className })} {...props} />;\n}\n\nexport function DialogBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport function DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.footer({ className })} {...props} />;\n}\n\n/** `Dialog.Root/Trigger/Content/Header/Title/Description/Body/Footer/Close`. `open`/`defaultOpen` + `onOpenChange`. */\nexport const Dialog = {\n Root: DialogPrimitive.Root,\n Trigger: DialogPrimitive.Trigger,\n Close: DialogPrimitive.Close,\n Content: DialogContent,\n Header: DialogHeader,\n Title: DialogTitle,\n Description: DialogDescription,\n Body: DialogBody,\n Footer: DialogFooter,\n};\n\n/** `Omit` that keeps the close-button union (`closeLabel` required unless `hideClose`). */\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\nexport type SheetProps = DistributiveOmit<DialogContentProps, \"placement\">;\n\n/** A sheet is a dialog anchored at the bottom (centred from `sm` up): `Dialog.Content placement=\"bottom\"`. */\nexport function Sheet(props: SheetProps) {\n return <DialogContent placement=\"bottom\" {...props} />;\n}\n","// Client (a portal). The moment two people choose each other — a match, a pair, a deal: a dialog in the brand\n// gradient, the two avatars meeting at a heart, the next step. The entrance plays once; still under reduced motion.\nimport * as React from \"react\";\n\nimport { Avatar } from \"../avatar\";\nimport { Button } from \"../button\";\nimport { Dialog } from \"../dialog\";\n\nexport type MatchDialogProps = {\n /** Shown (controlled). */\n open: boolean;\n /** Called when it closes. */\n onOpenChange: (open: boolean) => void;\n /** The headline (“It's a match!”) — passed translated; the dialog's name. */\n title: string;\n /** A line under it. */\n description?: string;\n /** The two people: avatar URLs and names. */\n people: readonly [{ src?: string | null; name: string }, { src?: string | null; name: string }];\n /** The main action (“Send a message”). */\n primaryLabel: string;\n /** What it does. */\n onPrimary: () => void;\n /** The way back (“Keep swiping”). */\n secondaryLabel: string;\n};\n\n/** Two people choose each other: the avatars meet at a heart in the brand gradient, the next step under them. */\nexport function MatchDialog({ open, onOpenChange, title, description, people, primaryLabel, onPrimary, secondaryLabel }: MatchDialogProps) {\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Content hideClose size=\"sm\" className=\"overflow-hidden border-0 bg-gradient-to-br from-accent to-accent-2 text-center text-on-accent\">\n <style href=\"krizaka-match\" precedence=\"default\">\n {\"@media (prefers-reduced-motion:no-preference){[data-kz-match] [data-side=a]{animation:kz-match-a .55s cubic-bezier(.3,1.6,.5,1) both}[data-kz-match] [data-side=b]{animation:kz-match-b .55s cubic-bezier(.3,1.6,.5,1) both}[data-kz-match] [data-heart]{animation:kz-match-heart .45s .25s cubic-bezier(.3,1.6,.5,1) both}}@keyframes kz-match-a{from{transform:translateX(-60px) rotate(-8deg);opacity:0}}@keyframes kz-match-b{from{transform:translateX(60px) rotate(8deg);opacity:0}}@keyframes kz-match-heart{from{transform:scale(0)}}\"}\n </style>\n <div data-kz-match=\"\" className=\"flex flex-col items-center gap-3 px-2 pb-2 pt-6\">\n <Dialog.Title className=\"font-display text-4xl font-black text-on-accent\">{title}</Dialog.Title>\n {description ? <Dialog.Description className=\"max-w-xs text-sm text-on-accent\">{description}</Dialog.Description> : null}\n <div className=\"relative my-6 flex h-36 w-64 items-center justify-center\" aria-hidden>\n <span data-side=\"a\" className=\"absolute left-6 -rotate-6 rounded-full ring-4 ring-on-accent\">\n <Avatar src={people[0].src ?? null} alt=\"\" fallback={people[0].name.charAt(0)} className=\"h-28 w-28 text-3xl\" />\n </span>\n <span data-side=\"b\" className=\"absolute right-6 rotate-6 rounded-full ring-4 ring-on-accent\">\n <Avatar src={people[1].src ?? null} alt=\"\" fallback={people[1].name.charAt(0)} className=\"h-28 w-28 text-3xl\" />\n </span>\n <span data-heart=\"\" className=\"absolute -bottom-1 flex h-12 w-12 items-center justify-center rounded-full bg-on-accent text-accent shadow-lg\">\n <svg viewBox=\"0 0 24 24\" className=\"h-6 w-6\" fill=\"currentColor\">\n <path d=\"M12 20s-7-4.4-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.6-7 10-7 10z\" />\n </svg>\n </span>\n </div>\n <div className=\"flex w-full flex-col gap-2\">\n <Button\n size=\"lg\"\n onClick={() => {\n onOpenChange(false);\n onPrimary();\n }}\n >\n {primaryLabel}\n </Button>\n <Dialog.Close asChild>\n <Button size=\"lg\" variant=\"ghost\" className=\"text-on-accent hover:bg-on-accent/15\">\n {secondaryLabel}\n </Button>\n </Dialog.Close>\n </div>\n </div>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/dialog/dialog.tsx","../src/dialog/return-focus.ts","../src/match-dialog/match-dialog.tsx"],"sourcesContent":["// Client (a portal). Radix does the focus trap, the scroll lock, Escape, the outside click, aria-modal, the\n// aria-labelledby / aria-describedby wiring and the focus return: this file only holds the shape.\nimport { Dialog as DialogPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { IconButton } from \"../button/button\";\nimport { useReturnFocus } from \"./return-focus\";\n\nexport const dialog = tv({\n slots: {\n overlay: \"kz-overlay fixed inset-0 z-50 bg-overlay backdrop-blur-xs\",\n content:\n \"kz-dialog fixed z-50 flex flex-col overflow-hidden border border-border-default bg-surface-1 text-fg shadow-lg focus:outline-hidden\",\n close: \"absolute right-3 top-3 h-9 w-9\",\n header: \"flex flex-col gap-1 px-5 pb-2 pr-14 pt-5\",\n title: \"text-base font-bold text-fg\",\n description: \"text-sm text-fg-secondary\",\n body: \"min-h-0 flex-1 overflow-y-auto px-5 pb-5\",\n footer:\n \"flex flex-wrap items-center justify-end gap-2 border-t border-border-subtle px-5 py-4 pb-[max(1rem,env(safe-area-inset-bottom))]\",\n },\n variants: {\n placement: {\n center: { content: \"left-1/2 top-1/2 max-h-[85dvh] w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 rounded-xl\" },\n /* A sheet: anchored at the bottom on a phone, centred from `sm` up. */\n bottom: {\n content:\n \"inset-x-0 bottom-0 max-h-[92dvh] rounded-t-[1.75rem] sm:bottom-auto sm:left-1/2 sm:top-1/2 sm:w-full \" +\n \"sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-[1.75rem]\",\n },\n right: { content: \"inset-y-0 right-0 h-full w-full max-w-md rounded-none border-y-0 border-r-0\" },\n /* A navigation drawer: full height, from the left, clear of the notch. */\n left: { content: \"inset-y-0 left-0 h-full w-full max-w-md rounded-none border-y-0 border-l-0 pl-[env(safe-area-inset-left)]\" },\n },\n size: { sm: { content: \"sm:max-w-sm\" }, md: { content: \"sm:max-w-md\" }, lg: { content: \"sm:max-w-2xl\" } },\n },\n defaultVariants: { placement: \"center\", size: \"md\" },\n});\nconst s = dialog();\n\nexport type DialogVariants = VariantProps<typeof dialog>;\n\nfunction CloseIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\ntype CloseButtonProps =\n | {\n /** The accessible name of the close button — passed translated. */\n closeLabel: string;\n /** Leaves the close button out (the content brings its own way out, or none: see `dismissible`). */\n hideClose?: false;\n }\n | { closeLabel?: string; hideClose: true };\n\nexport type DialogContentProps = React.ComponentProps<typeof DialogPrimitive.Content> &\n DialogVariants &\n CloseButtonProps & {\n /**\n * center · bottom (a sheet on a phone, centred from `sm` up) · right (a side panel, full height) · left (a\n * navigation drawer, full height).\n * @default \"center\"\n */\n placement?: DialogVariants[\"placement\"];\n /**\n * sm · md · lg: the width of the dialog.\n * @default \"md\"\n */\n size?: DialogVariants[\"size\"];\n /**\n * `false`: Escape and a click outside do not close it (a gate the user must answer: age, terms). It still closes\n * through `open` / `onOpenChange` and any `Dialog.Close` inside. Default `true`.\n */\n dismissible?: boolean;\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n };\n\nconst prevent = (event: Event) => event.preventDefault();\n\n/** Radix's content, mounted only while open: it remembers the opener then and gives focus back on close (WCAG 2.4.3). */\nfunction ReturnFocusContent({ onCloseAutoFocus, ...props }: React.ComponentProps<typeof DialogPrimitive.Content>) {\n return <DialogPrimitive.Content onCloseAutoFocus={useReturnFocus(onCloseAutoFocus)} {...props} />;\n}\n\n/** The dialog itself, portalled over a dimmed overlay, with a close button. Give it a `Dialog.Title`. */\nexport function DialogContent({\n placement,\n size,\n closeLabel,\n hideClose,\n dismissible = true,\n container,\n className,\n children,\n onEscapeKeyDown,\n onPointerDownOutside,\n onInteractOutside,\n ...props\n}: DialogContentProps) {\n const v = dialog({ placement, size });\n return (\n <DialogPrimitive.Portal container={container}>\n <DialogPrimitive.Overlay className={v.overlay()} />\n <ReturnFocusContent\n data-placement={placement ?? \"center\"}\n data-dismissible={dismissible ? undefined : \"false\"}\n className={v.content({ className })}\n onEscapeKeyDown={dismissible ? onEscapeKeyDown : chain(onEscapeKeyDown, prevent)}\n onPointerDownOutside={dismissible ? onPointerDownOutside : chain(onPointerDownOutside, prevent)}\n onInteractOutside={dismissible ? onInteractOutside : chain(onInteractOutside, prevent)}\n {...props}\n >\n {children}\n {!hideClose && (\n <DialogPrimitive.Close asChild>\n <IconButton label={closeLabel as string} variant=\"ghost\" shape=\"pill\" className={v.close()}>\n <CloseIcon />\n </IconButton>\n </DialogPrimitive.Close>\n )}\n </ReturnFocusContent>\n </DialogPrimitive.Portal>\n );\n}\n\nfunction chain<E extends Event>(handler: ((event: E) => void) | undefined, then: (event: E) => void) {\n return (event: E) => {\n handler?.(event);\n then(event);\n };\n}\n\nexport function DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.header({ className })} {...props} />;\n}\n\nexport function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return <DialogPrimitive.Title className={s.title({ className })} {...props} />;\n}\n\nexport function DialogDescription({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return <DialogPrimitive.Description className={s.description({ className })} {...props} />;\n}\n\nexport function DialogBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport function DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.footer({ className })} {...props} />;\n}\n\n/** `Dialog.Root/Trigger/Content/Header/Title/Description/Body/Footer/Close`. `open`/`defaultOpen` + `onOpenChange`. */\nexport const Dialog = {\n Root: DialogPrimitive.Root,\n Trigger: DialogPrimitive.Trigger,\n Close: DialogPrimitive.Close,\n Content: DialogContent,\n Header: DialogHeader,\n Title: DialogTitle,\n Description: DialogDescription,\n Body: DialogBody,\n Footer: DialogFooter,\n};\n\n/** `Omit` that keeps the close-button union (`closeLabel` required unless `hideClose`). */\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\nexport type SheetProps = DistributiveOmit<DialogContentProps, \"placement\">;\n\n/** A sheet is a dialog anchored at the bottom (centred from `sm` up): `Dialog.Content placement=\"bottom\"`. */\nexport function Sheet(props: SheetProps) {\n return <DialogContent placement=\"bottom\" {...props} />;\n}\n","// Client. WCAG 2.4.3: when a dialog closes, focus goes back to what opened it. Radix only does it for `Dialog.Trigger`;\n// most app dialogs are controlled (`open` / `onOpenChange`) and opened by a plain button, so on Escape focus fell to\n// <body>. The content remembers the focused element when it mounts (it is still the opener: Radix moves focus in an\n// effect) and gives it back on close, unless the consumer's `onCloseAutoFocus` prevented the default.\nimport * as React from \"react\";\n\n/** The handler for `onCloseAutoFocus`: yours first, then focus back on the opener if it is still on the page. */\nexport function useReturnFocus(onCloseAutoFocus?: (event: Event) => void) {\n const [opener] = React.useState<Element | null>(() => (typeof document === \"undefined\" ? null : document.activeElement));\n return React.useCallback(\n (event: Event) => {\n onCloseAutoFocus?.(event);\n if (event.defaultPrevented) return;\n if (opener instanceof HTMLElement && opener !== document.body && opener.isConnected) {\n event.preventDefault();\n opener.focus();\n }\n },\n [opener, onCloseAutoFocus],\n );\n}\n","// Client (a portal). The moment two people choose each other — a match, a pair, a deal: a dialog in the brand\n// gradient, the two avatars meeting at a heart, the next step. The entrance plays once; still under reduced motion.\nimport * as React from \"react\";\n\nimport { Avatar } from \"../avatar\";\nimport { Button } from \"../button\";\nimport { Dialog } from \"../dialog\";\n\nexport type MatchDialogProps = {\n /** Shown (controlled). */\n open: boolean;\n /** Called when it closes. */\n onOpenChange: (open: boolean) => void;\n /** The headline (“It's a match!”) — passed translated; the dialog's name. */\n title: string;\n /** A line under it. */\n description?: string;\n /** The two people: avatar URLs and names. */\n people: readonly [{ src?: string | null; name: string }, { src?: string | null; name: string }];\n /** The main action (“Send a message”). */\n primaryLabel: string;\n /** What it does. */\n onPrimary: () => void;\n /** The way back (“Keep swiping”). */\n secondaryLabel: string;\n /** Where it is drawn (the page's body by default): give an element inside a brand scope (`.brand-…`) so the dialog wears the brand too. */\n container?: HTMLElement | null;\n};\n\n/** Two people choose each other: the avatars meet at a heart in the brand gradient, the next step under them. */\nexport function MatchDialog({ open, onOpenChange, title, description, people, primaryLabel, onPrimary, secondaryLabel, container }: MatchDialogProps) {\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Content hideClose size=\"sm\" container={container} className=\"overflow-hidden border-0 bg-gradient-to-br from-accent to-accent-2 text-center text-on-accent\">\n <style href=\"krizaka-match\" precedence=\"default\">\n {\"@media (prefers-reduced-motion:no-preference){[data-kz-match] [data-side=a]{animation:kz-match-a .55s cubic-bezier(.3,1.6,.5,1) both}[data-kz-match] [data-side=b]{animation:kz-match-b .55s cubic-bezier(.3,1.6,.5,1) both}[data-kz-match] [data-heart]{animation:kz-match-heart .45s .25s cubic-bezier(.3,1.6,.5,1) both}}@keyframes kz-match-a{from{transform:translateX(-60px) rotate(-8deg);opacity:0}}@keyframes kz-match-b{from{transform:translateX(60px) rotate(8deg);opacity:0}}@keyframes kz-match-heart{from{transform:scale(0)}}\"}\n </style>\n <div data-kz-match=\"\" className=\"flex flex-col items-center gap-3 px-2 pb-2 pt-6\">\n <Dialog.Title className=\"font-display text-4xl font-black text-on-accent\">{title}</Dialog.Title>\n {description ? <Dialog.Description className=\"max-w-xs text-sm text-on-accent\">{description}</Dialog.Description> : null}\n <div className=\"relative my-6 flex h-36 w-64 items-center justify-center\" aria-hidden>\n <span data-side=\"a\" className=\"absolute left-6 -rotate-6 rounded-full ring-4 ring-on-accent\">\n <Avatar src={people[0].src ?? null} alt=\"\" fallback={people[0].name.charAt(0)} className=\"h-28 w-28 text-3xl\" />\n </span>\n <span data-side=\"b\" className=\"absolute right-6 rotate-6 rounded-full ring-4 ring-on-accent\">\n <Avatar src={people[1].src ?? null} alt=\"\" fallback={people[1].name.charAt(0)} className=\"h-28 w-28 text-3xl\" />\n </span>\n <span data-heart=\"\" className=\"absolute -bottom-1 flex h-12 w-12 items-center justify-center rounded-full bg-on-accent text-accent shadow-lg\">\n <svg viewBox=\"0 0 24 24\" className=\"h-6 w-6\" fill=\"currentColor\">\n <path d=\"M12 20s-7-4.4-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.6-7 10-7 10z\" />\n </svg>\n </span>\n </div>\n <div className=\"flex w-full flex-col gap-2\">\n <Button\n size=\"lg\"\n onClick={() => {\n onOpenChange(false);\n onPrimary();\n }}\n >\n {primaryLabel}\n </Button>\n <Dialog.Close asChild>\n <Button size=\"lg\" variant=\"ghost\" className=\"text-on-accent hover:bg-on-accent/15\">\n {secondaryLabel}\n </Button>\n </Dialog.Close>\n </div>\n </div>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs"]}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
interface VerticalVideoLabels {
|
|
5
|
+
play: string;
|
|
6
|
+
pause: string;
|
|
7
|
+
like: string;
|
|
8
|
+
comment: string;
|
|
9
|
+
share: string;
|
|
10
|
+
more: string;
|
|
11
|
+
/** "Follow {name}". */
|
|
12
|
+
follow: string;
|
|
13
|
+
/** "Following {name}". */
|
|
14
|
+
following: string;
|
|
15
|
+
expand: string;
|
|
16
|
+
collapse: string;
|
|
17
|
+
progress: string;
|
|
18
|
+
/** The rail's name ("Actions"). */
|
|
19
|
+
actions: string;
|
|
20
|
+
}
|
|
21
|
+
declare const verticalVideoLabels: VerticalVideoLabels;
|
|
22
|
+
type VerticalVideoProps = {
|
|
23
|
+
/** The video's accessible name ("Video: Night shoot, part 2"), passed translated. */
|
|
24
|
+
title: string;
|
|
25
|
+
/** The clip's address (MP4 or HLS). Absent, the poster alone shows. */
|
|
26
|
+
uri?: string;
|
|
27
|
+
/** The picture until the first frame. */
|
|
28
|
+
posterUri?: string;
|
|
29
|
+
/** Plays while `true` (a `ShortFeed` passes it for the slide in view). Default `true`. */
|
|
30
|
+
active?: boolean;
|
|
31
|
+
/** Who made it: name, portrait, the seal's words. */
|
|
32
|
+
creator: {
|
|
33
|
+
name: string;
|
|
34
|
+
avatarUri?: string;
|
|
35
|
+
verifiedLabel?: string;
|
|
36
|
+
};
|
|
37
|
+
/** A pill beside the name ("AI-GENERATED"). */
|
|
38
|
+
disclosure?: string;
|
|
39
|
+
/** The caption, two lines until expanded. */
|
|
40
|
+
caption?: string;
|
|
41
|
+
/** Tags after the caption (without `#`). */
|
|
42
|
+
tags?: readonly string[];
|
|
43
|
+
/** The sound or credit line. */
|
|
44
|
+
credit?: string;
|
|
45
|
+
/** The like count, compact in `locale`. */
|
|
46
|
+
likes?: number;
|
|
47
|
+
/** The comment count. */
|
|
48
|
+
comments?: number;
|
|
49
|
+
/** The share count. */
|
|
50
|
+
shares?: number;
|
|
51
|
+
/** Whether the viewer likes it. */
|
|
52
|
+
liked?: boolean;
|
|
53
|
+
/** Whether the viewer follows the creator. */
|
|
54
|
+
following?: boolean;
|
|
55
|
+
/** The viewer likes or unlikes. */
|
|
56
|
+
onLike?: (liked: boolean) => void;
|
|
57
|
+
/** Opens the comments. */
|
|
58
|
+
onComment?: () => void;
|
|
59
|
+
/** Opens the share sheet. */
|
|
60
|
+
onShare?: () => void;
|
|
61
|
+
/** Follows or unfollows; without it the avatar has no "+". */
|
|
62
|
+
onFollow?: (following: boolean) => void;
|
|
63
|
+
/** The "more" action; without it the button is not drawn. */
|
|
64
|
+
onMore?: () => void;
|
|
65
|
+
/** The product's own action on the rail (a tip, an unlock): a named, 44 pt button of yours. */
|
|
66
|
+
tipSlot?: React.ReactNode;
|
|
67
|
+
/** Top left over the picture: a chip (an auction's time left). */
|
|
68
|
+
topStart?: React.ReactNode;
|
|
69
|
+
/** Above the caption: a goal gauge. */
|
|
70
|
+
aboveCaption?: React.ReactNode;
|
|
71
|
+
/** The locale of the counts. Default `en`. */
|
|
72
|
+
locale?: string;
|
|
73
|
+
/** Every word, passed translated. */
|
|
74
|
+
labels?: Partial<VerticalVideoLabels>;
|
|
75
|
+
/** Styles merged last, on the frame. */
|
|
76
|
+
style?: StyleProp<ViewStyle>;
|
|
77
|
+
};
|
|
78
|
+
/** One short video: 9:16, the rail of actions on the right, the creator's caption bottom-left. */
|
|
79
|
+
declare function VerticalVideo({ title, uri, posterUri, active, creator, disclosure, caption, tags, credit, likes, comments, shares, liked, following, onLike, onComment, onShare, onFollow, onMore, tipSlot, topStart, aboveCaption, locale, labels: custom, style, }: VerticalVideoProps): React.JSX.Element;
|
|
80
|
+
type ShortFeedProps<T> = {
|
|
81
|
+
/** The feed's accessible name ("Videos"). */
|
|
82
|
+
label: string;
|
|
83
|
+
/** The videos, in order. */
|
|
84
|
+
items: readonly T[];
|
|
85
|
+
/** A stable key for an item. */
|
|
86
|
+
getId: (item: T) => string;
|
|
87
|
+
/** One slide: `active` is true for the one in view. */
|
|
88
|
+
renderItem: (item: T, state: {
|
|
89
|
+
active: boolean;
|
|
90
|
+
index: number;
|
|
91
|
+
}) => React.ReactElement;
|
|
92
|
+
/** The page's height in points (the feed's own height; one slide per page). */
|
|
93
|
+
height: number;
|
|
94
|
+
/** Called when the slide in view changes. */
|
|
95
|
+
onActiveChange?: (index: number, item: T) => void;
|
|
96
|
+
/** Styles merged last. */
|
|
97
|
+
style?: StyleProp<ViewStyle>;
|
|
98
|
+
};
|
|
99
|
+
/** A vertical paging feed: one video per screen, the one in view plays, the others pause. */
|
|
100
|
+
declare function ShortFeed<T>({ label, items, getId, renderItem, height, onActiveChange, style }: ShortFeedProps<T>): React.JSX.Element;
|
|
101
|
+
|
|
102
|
+
export { ShortFeed, type ShortFeedProps, VerticalVideo, type VerticalVideoLabels, type VerticalVideoProps, verticalVideoLabels };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// src/native/vertical-video.tsx
|
|
2
|
+
import { formatCompact } from "@krizaka/intl";
|
|
3
|
+
import { Avatar, Txt, useTheme, VerifiedBadge } from "@krizaka/ui/native";
|
|
4
|
+
import { VideoPlayer } from "@krizaka/ui/native/video-player";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { FlatList, Image, Pressable, StyleSheet, View } from "react-native";
|
|
7
|
+
import Svg, { Path } from "react-native-svg";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
var verticalVideoLabels = {
|
|
10
|
+
play: "Play",
|
|
11
|
+
pause: "Pause",
|
|
12
|
+
like: "Like",
|
|
13
|
+
comment: "Comments",
|
|
14
|
+
share: "Share",
|
|
15
|
+
more: "More",
|
|
16
|
+
follow: "Follow {name}",
|
|
17
|
+
following: "Following {name}",
|
|
18
|
+
expand: "More",
|
|
19
|
+
collapse: "Less",
|
|
20
|
+
progress: "Progress",
|
|
21
|
+
actions: "Actions"
|
|
22
|
+
};
|
|
23
|
+
var HEART = "M12 20s-7-4.4-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.6-7 10-7 10z";
|
|
24
|
+
var COMMENT = "M4 5h16v11H9l-5 4z";
|
|
25
|
+
var SHARE = "M4 12v7h16v-7M12 3v12M7 8l5-5 5 5";
|
|
26
|
+
var MORE = "M5 12h.01M12 12h.01M19 12h.01";
|
|
27
|
+
function Glyph({ d, color, filled }) {
|
|
28
|
+
return /* @__PURE__ */ jsx(Svg, { width: 24, height: 24, viewBox: "0 0 24 24", fill: filled ? color : "none", stroke: color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx(Path, { d }) });
|
|
29
|
+
}
|
|
30
|
+
function RailButton({ label, count, pressed, onPress, children }) {
|
|
31
|
+
const { theme } = useTheme();
|
|
32
|
+
return /* @__PURE__ */ jsxs(View, { style: styles.railItem, children: [
|
|
33
|
+
/* @__PURE__ */ jsx(Pressable, { role: "button", "aria-label": label, "aria-pressed": pressed, onPress, hitSlop: 4, style: [styles.railButton, { backgroundColor: theme.scrim }], children }),
|
|
34
|
+
count !== void 0 ? /* @__PURE__ */ jsx(Txt, { variant: "caption", tone: "onMedia", style: styles.count, children: count }) : null
|
|
35
|
+
] });
|
|
36
|
+
}
|
|
37
|
+
function VerticalVideo({
|
|
38
|
+
title,
|
|
39
|
+
uri,
|
|
40
|
+
posterUri,
|
|
41
|
+
active = true,
|
|
42
|
+
creator,
|
|
43
|
+
disclosure,
|
|
44
|
+
caption,
|
|
45
|
+
tags = [],
|
|
46
|
+
credit,
|
|
47
|
+
likes,
|
|
48
|
+
comments,
|
|
49
|
+
shares,
|
|
50
|
+
liked = false,
|
|
51
|
+
following = false,
|
|
52
|
+
onLike,
|
|
53
|
+
onComment,
|
|
54
|
+
onShare,
|
|
55
|
+
onFollow,
|
|
56
|
+
onMore,
|
|
57
|
+
tipSlot,
|
|
58
|
+
topStart,
|
|
59
|
+
aboveCaption,
|
|
60
|
+
locale = "en",
|
|
61
|
+
labels: custom,
|
|
62
|
+
style
|
|
63
|
+
}) {
|
|
64
|
+
const { theme } = useTheme();
|
|
65
|
+
const labels = { ...verticalVideoLabels, ...custom };
|
|
66
|
+
const [open, setOpen] = React.useState(false);
|
|
67
|
+
const [paused, setPaused] = React.useState(false);
|
|
68
|
+
const count = (n) => n === void 0 ? void 0 : formatCompact(n, { locale });
|
|
69
|
+
const on = theme.textOnMedia;
|
|
70
|
+
return /* @__PURE__ */ jsxs(View, { role: "group", "aria-label": title, style: [styles.frame, { backgroundColor: theme.media }, style], children: [
|
|
71
|
+
uri ? /* @__PURE__ */ jsx(VideoPlayer, { source: { uri }, title, aspectRatio: 9 / 16, contentFit: "cover", nativeControls: false, fullscreen: false, autoPlay: true, loop: true, muted: true, paused: !active || paused, style: StyleSheet.absoluteFill, ...posterUri ? { poster: { uri: posterUri } } : {} }) : posterUri ? /* @__PURE__ */ jsx(Image, { source: { uri: posterUri }, "aria-hidden": true, resizeMode: "cover", style: StyleSheet.absoluteFill }) : null,
|
|
72
|
+
/* @__PURE__ */ jsx(Pressable, { role: "button", "aria-label": paused ? labels.play : labels.pause, onPress: () => setPaused((p) => !p), onLongPress: () => onLike?.(!liked), style: StyleSheet.absoluteFill }),
|
|
73
|
+
/* @__PURE__ */ jsx(View, { pointerEvents: "none", style: [styles.shade, { backgroundColor: theme.scrim }] }),
|
|
74
|
+
topStart ? /* @__PURE__ */ jsx(View, { style: styles.topStart, children: topStart }) : null,
|
|
75
|
+
/* @__PURE__ */ jsxs(View, { role: "group", "aria-label": labels.actions, style: styles.rail, children: [
|
|
76
|
+
/* @__PURE__ */ jsxs(View, { children: [
|
|
77
|
+
/* @__PURE__ */ jsx(Avatar, { alt: creator.name, ...creator.avatarUri ? { src: creator.avatarUri } : {}, size: "md" }),
|
|
78
|
+
onFollow ? /* @__PURE__ */ jsx(
|
|
79
|
+
Pressable,
|
|
80
|
+
{
|
|
81
|
+
role: "button",
|
|
82
|
+
"aria-label": (following ? labels.following : labels.follow).replace("{name}", creator.name),
|
|
83
|
+
"aria-pressed": following,
|
|
84
|
+
onPress: () => onFollow(!following),
|
|
85
|
+
hitSlop: 12,
|
|
86
|
+
style: [styles.follow, { backgroundColor: following ? theme.surface2 : theme.accent }],
|
|
87
|
+
children: /* @__PURE__ */ jsx(Glyph, { d: following ? "M5 12l5 5 9-10" : "M12 5v14M5 12h14", color: following ? theme.textPrimary : theme.onAccent })
|
|
88
|
+
}
|
|
89
|
+
) : null
|
|
90
|
+
] }),
|
|
91
|
+
/* @__PURE__ */ jsx(RailButton, { label: labels.like, count: count(likes), pressed: liked, onPress: () => onLike?.(!liked), children: /* @__PURE__ */ jsx(Glyph, { d: HEART, color: liked ? theme.accent : on, filled: liked }) }),
|
|
92
|
+
/* @__PURE__ */ jsx(RailButton, { label: labels.comment, count: count(comments), onPress: onComment, children: /* @__PURE__ */ jsx(Glyph, { d: COMMENT, color: on }) }),
|
|
93
|
+
/* @__PURE__ */ jsx(RailButton, { label: labels.share, count: count(shares), onPress: onShare, children: /* @__PURE__ */ jsx(Glyph, { d: SHARE, color: on }) }),
|
|
94
|
+
tipSlot,
|
|
95
|
+
onMore ? /* @__PURE__ */ jsx(RailButton, { label: labels.more, onPress: onMore, children: /* @__PURE__ */ jsx(Glyph, { d: MORE, color: on }) }) : null
|
|
96
|
+
] }),
|
|
97
|
+
/* @__PURE__ */ jsxs(View, { style: styles.caption, children: [
|
|
98
|
+
aboveCaption,
|
|
99
|
+
/* @__PURE__ */ jsxs(View, { style: styles.nameRow, children: [
|
|
100
|
+
/* @__PURE__ */ jsx(Txt, { variant: "label", tone: "onMedia", children: creator.name }),
|
|
101
|
+
creator.verifiedLabel ? /* @__PURE__ */ jsx(VerifiedBadge, { label: creator.verifiedLabel, on: "media", size: 14 }) : null,
|
|
102
|
+
disclosure ? /* @__PURE__ */ jsx(View, { style: [styles.pill, { backgroundColor: theme.scrim }], children: /* @__PURE__ */ jsx(Txt, { variant: "caption", tone: "onMedia", style: styles.pillText, children: disclosure.toUpperCase() }) }) : null
|
|
103
|
+
] }),
|
|
104
|
+
caption ? /* @__PURE__ */ jsxs(Txt, { tone: "onMedia", numberOfLines: open ? void 0 : 2, children: [
|
|
105
|
+
caption,
|
|
106
|
+
tags.length > 0 ? ` ${tags.map((tag) => `#${tag}`).join(" ")}` : ""
|
|
107
|
+
] }) : null,
|
|
108
|
+
caption && caption.length > 90 ? /* @__PURE__ */ jsx(Pressable, { role: "button", "aria-label": open ? labels.collapse : labels.expand, "aria-expanded": open, onPress: () => setOpen((v) => !v), hitSlop: 10, children: /* @__PURE__ */ jsx(Txt, { variant: "caption", tone: "onMedia", style: styles.underline, children: open ? labels.collapse : labels.expand }) }) : null,
|
|
109
|
+
credit ? /* @__PURE__ */ jsx(Txt, { variant: "caption", tone: "onMedia", children: credit }) : null
|
|
110
|
+
] })
|
|
111
|
+
] });
|
|
112
|
+
}
|
|
113
|
+
function ShortFeed({ label, items, getId, renderItem, height, onActiveChange, style }) {
|
|
114
|
+
const [active, setActive] = React.useState(0);
|
|
115
|
+
const [onViewable] = React.useState(() => ({ viewableItems }) => {
|
|
116
|
+
const first = viewableItems.find((v) => v.isViewable && typeof v.index === "number");
|
|
117
|
+
if (first && typeof first.index === "number") setActive(first.index);
|
|
118
|
+
});
|
|
119
|
+
React.useEffect(() => {
|
|
120
|
+
const item = items[active];
|
|
121
|
+
if (item !== void 0) onActiveChange?.(active, item);
|
|
122
|
+
}, [active]);
|
|
123
|
+
return /* @__PURE__ */ jsx(View, { role: "list", "aria-label": label, style: [{ height }, style], children: /* @__PURE__ */ jsx(
|
|
124
|
+
FlatList,
|
|
125
|
+
{
|
|
126
|
+
data: items,
|
|
127
|
+
keyExtractor: getId,
|
|
128
|
+
pagingEnabled: true,
|
|
129
|
+
showsVerticalScrollIndicator: false,
|
|
130
|
+
snapToInterval: height,
|
|
131
|
+
decelerationRate: "fast",
|
|
132
|
+
getItemLayout: (_, index) => ({ length: height, offset: height * index, index }),
|
|
133
|
+
windowSize: 3,
|
|
134
|
+
initialNumToRender: 2,
|
|
135
|
+
viewabilityConfig: { itemVisiblePercentThreshold: 60 },
|
|
136
|
+
onViewableItemsChanged: onViewable,
|
|
137
|
+
extraData: active,
|
|
138
|
+
style: { height },
|
|
139
|
+
renderItem: ({ item, index }) => /* @__PURE__ */ jsx(View, { style: { height }, children: renderItem(item, { active: index === active, index }) })
|
|
140
|
+
}
|
|
141
|
+
) });
|
|
142
|
+
}
|
|
143
|
+
var styles = StyleSheet.create({
|
|
144
|
+
frame: { width: "100%", aspectRatio: 9 / 16, overflow: "hidden" },
|
|
145
|
+
shade: { position: "absolute", left: 0, right: 0, bottom: 0, height: "30%", opacity: 0.55 },
|
|
146
|
+
topStart: { position: "absolute", left: 12, top: 12 },
|
|
147
|
+
rail: { position: "absolute", right: 8, bottom: 20, alignItems: "center", gap: 12 },
|
|
148
|
+
railItem: { alignItems: "center", gap: 2 },
|
|
149
|
+
railButton: { width: 44, height: 44, borderRadius: 22, alignItems: "center", justifyContent: "center" },
|
|
150
|
+
count: { fontVariant: ["tabular-nums"], fontWeight: "600" },
|
|
151
|
+
follow: { position: "absolute", bottom: -10, alignSelf: "center", width: 22, height: 22, borderRadius: 11, alignItems: "center", justifyContent: "center", overflow: "hidden" },
|
|
152
|
+
caption: { position: "absolute", left: 12, right: 76, bottom: 16, gap: 6 },
|
|
153
|
+
nameRow: { flexDirection: "row", alignItems: "center", gap: 6 },
|
|
154
|
+
pill: { paddingHorizontal: 8, paddingVertical: 2, borderRadius: 999 },
|
|
155
|
+
pillText: { fontWeight: "700", letterSpacing: 0.4 },
|
|
156
|
+
underline: { textDecorationLine: "underline", fontWeight: "600" }
|
|
157
|
+
});
|
|
158
|
+
export {
|
|
159
|
+
ShortFeed,
|
|
160
|
+
VerticalVideo,
|
|
161
|
+
verticalVideoLabels
|
|
162
|
+
};
|
|
163
|
+
//# sourceMappingURL=vertical-video.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/native/vertical-video.tsx"],"sourcesContent":["// @krizaka/ui/native/vertical-video — its own entry (it plays video on expo-video, an optional peer). A 9:16 clip filling\n// its frame, the action rail on the right (avatar + follow, like, comments, share, a slot for the product's tip), the\n// creator's caption bottom-left, a progress hairline; `ShortFeed` pages them vertically and plays the one in view.\n// Over the picture everything reads on the theme's invariant `scrim` / `textOnMedia`.\nimport { formatCompact } from \"@krizaka/intl\";\nimport { Avatar, Txt, useTheme, VerifiedBadge } from \"@krizaka/ui/native\";\nimport { VideoPlayer } from \"@krizaka/ui/native/video-player\";\nimport * as React from \"react\";\nimport { FlatList, Image,Pressable, type StyleProp, StyleSheet, View, type ViewStyle, type ViewToken } from \"react-native\";\nimport Svg, { Path } from \"react-native-svg\";\n\nexport interface VerticalVideoLabels {\n play: string;\n pause: string;\n like: string;\n comment: string;\n share: string;\n more: string;\n /** \"Follow {name}\". */\n follow: string;\n /** \"Following {name}\". */\n following: string;\n expand: string;\n collapse: string;\n progress: string;\n /** The rail's name (\"Actions\"). */\n actions: string;\n}\n\nexport const verticalVideoLabels: VerticalVideoLabels = {\n play: \"Play\",\n pause: \"Pause\",\n like: \"Like\",\n comment: \"Comments\",\n share: \"Share\",\n more: \"More\",\n follow: \"Follow {name}\",\n following: \"Following {name}\",\n expand: \"More\",\n collapse: \"Less\",\n progress: \"Progress\",\n actions: \"Actions\",\n};\n\nexport type VerticalVideoProps = {\n /** The video's accessible name (\"Video: Night shoot, part 2\"), passed translated. */\n title: string;\n /** The clip's address (MP4 or HLS). Absent, the poster alone shows. */\n uri?: string;\n /** The picture until the first frame. */\n posterUri?: string;\n /** Plays while `true` (a `ShortFeed` passes it for the slide in view). Default `true`. */\n active?: boolean;\n /** Who made it: name, portrait, the seal's words. */\n creator: { name: string; avatarUri?: string; verifiedLabel?: string };\n /** A pill beside the name (\"AI-GENERATED\"). */\n disclosure?: string;\n /** The caption, two lines until expanded. */\n caption?: string;\n /** Tags after the caption (without `#`). */\n tags?: readonly string[];\n /** The sound or credit line. */\n credit?: string;\n /** The like count, compact in `locale`. */\n likes?: number;\n /** The comment count. */\n comments?: number;\n /** The share count. */\n shares?: number;\n /** Whether the viewer likes it. */\n liked?: boolean;\n /** Whether the viewer follows the creator. */\n following?: boolean;\n /** The viewer likes or unlikes. */\n onLike?: (liked: boolean) => void;\n /** Opens the comments. */\n onComment?: () => void;\n /** Opens the share sheet. */\n onShare?: () => void;\n /** Follows or unfollows; without it the avatar has no \"+\". */\n onFollow?: (following: boolean) => void;\n /** The \"more\" action; without it the button is not drawn. */\n onMore?: () => void;\n /** The product's own action on the rail (a tip, an unlock): a named, 44 pt button of yours. */\n tipSlot?: React.ReactNode;\n /** Top left over the picture: a chip (an auction's time left). */\n topStart?: React.ReactNode;\n /** Above the caption: a goal gauge. */\n aboveCaption?: React.ReactNode;\n /** The locale of the counts. Default `en`. */\n locale?: string;\n /** Every word, passed translated. */\n labels?: Partial<VerticalVideoLabels>;\n /** Styles merged last, on the frame. */\n style?: StyleProp<ViewStyle>;\n};\n\nconst HEART = \"M12 20s-7-4.4-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.6-7 10-7 10z\";\nconst COMMENT = \"M4 5h16v11H9l-5 4z\";\nconst SHARE = \"M4 12v7h16v-7M12 3v12M7 8l5-5 5 5\";\nconst MORE = \"M5 12h.01M12 12h.01M19 12h.01\";\n\nfunction Glyph({ d, color, filled }: { d: string; color: string; filled?: boolean }) {\n return (\n <Svg width={24} height={24} viewBox=\"0 0 24 24\" fill={filled ? color : \"none\"} stroke={color} strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <Path d={d} />\n </Svg>\n );\n}\n\nfunction RailButton({ label, count, pressed, onPress, children }: { label: string; count?: string | undefined; pressed?: boolean | undefined; onPress?: (() => void) | undefined; children: React.ReactNode }) {\n const { theme } = useTheme();\n return (\n <View style={styles.railItem}>\n <Pressable role=\"button\" aria-label={label} aria-pressed={pressed} onPress={onPress} hitSlop={4} style={[styles.railButton, { backgroundColor: theme.scrim }]}>\n {children}\n </Pressable>\n {count !== undefined ? (\n <Txt variant=\"caption\" tone=\"onMedia\" style={styles.count}>\n {count}\n </Txt>\n ) : null}\n </View>\n );\n}\n\n/** One short video: 9:16, the rail of actions on the right, the creator's caption bottom-left. */\nexport function VerticalVideo({\n title,\n uri,\n posterUri,\n active = true,\n creator,\n disclosure,\n caption,\n tags = [],\n credit,\n likes,\n comments,\n shares,\n liked = false,\n following = false,\n onLike,\n onComment,\n onShare,\n onFollow,\n onMore,\n tipSlot,\n topStart,\n aboveCaption,\n locale = \"en\",\n labels: custom,\n style,\n}: VerticalVideoProps) {\n const { theme } = useTheme();\n const labels = { ...verticalVideoLabels, ...custom };\n const [open, setOpen] = React.useState(false);\n const [paused, setPaused] = React.useState(false);\n const count = (n?: number) => (n === undefined ? undefined : formatCompact(n, { locale }));\n const on = theme.textOnMedia;\n return (\n <View role=\"group\" aria-label={title} style={[styles.frame, { backgroundColor: theme.media }, style]}>\n {uri ? (\n <VideoPlayer source={{ uri }} title={title} aspectRatio={9 / 16} contentFit=\"cover\" nativeControls={false} fullscreen={false} autoPlay loop muted paused={!active || paused} style={StyleSheet.absoluteFill} {...(posterUri ? { poster: { uri: posterUri } } : {})} />\n ) : posterUri ? (\n <Image source={{ uri: posterUri }} aria-hidden resizeMode=\"cover\" style={StyleSheet.absoluteFill} />\n ) : null}\n <Pressable role=\"button\" aria-label={paused ? labels.play : labels.pause} onPress={() => setPaused((p) => !p)} onLongPress={() => onLike?.(!liked)} style={StyleSheet.absoluteFill} />\n <View pointerEvents=\"none\" style={[styles.shade, { backgroundColor: theme.scrim }]} />\n {topStart ? <View style={styles.topStart}>{topStart}</View> : null}\n\n <View role=\"group\" aria-label={labels.actions} style={styles.rail}>\n <View>\n <Avatar alt={creator.name} {...(creator.avatarUri ? { src: creator.avatarUri } : {})} size=\"md\" />\n {onFollow ? (\n <Pressable\n role=\"button\"\n aria-label={(following ? labels.following : labels.follow).replace(\"{name}\", creator.name)}\n aria-pressed={following}\n onPress={() => onFollow(!following)}\n hitSlop={12}\n style={[styles.follow, { backgroundColor: following ? theme.surface2 : theme.accent }]}\n >\n <Glyph d={following ? \"M5 12l5 5 9-10\" : \"M12 5v14M5 12h14\"} color={following ? theme.textPrimary : theme.onAccent} />\n </Pressable>\n ) : null}\n </View>\n <RailButton label={labels.like} count={count(likes)} pressed={liked} onPress={() => onLike?.(!liked)}>\n <Glyph d={HEART} color={liked ? theme.accent : on} filled={liked} />\n </RailButton>\n <RailButton label={labels.comment} count={count(comments)} onPress={onComment}>\n <Glyph d={COMMENT} color={on} />\n </RailButton>\n <RailButton label={labels.share} count={count(shares)} onPress={onShare}>\n <Glyph d={SHARE} color={on} />\n </RailButton>\n {tipSlot}\n {onMore ? (\n <RailButton label={labels.more} onPress={onMore}>\n <Glyph d={MORE} color={on} />\n </RailButton>\n ) : null}\n </View>\n\n <View style={styles.caption}>\n {aboveCaption}\n <View style={styles.nameRow}>\n <Txt variant=\"label\" tone=\"onMedia\">\n {creator.name}\n </Txt>\n {creator.verifiedLabel ? <VerifiedBadge label={creator.verifiedLabel} on=\"media\" size={14} /> : null}\n {disclosure ? (\n <View style={[styles.pill, { backgroundColor: theme.scrim }]}>\n <Txt variant=\"caption\" tone=\"onMedia\" style={styles.pillText}>\n {disclosure.toUpperCase()}\n </Txt>\n </View>\n ) : null}\n </View>\n {caption ? (\n <Txt tone=\"onMedia\" numberOfLines={open ? undefined : 2}>\n {caption}\n {tags.length > 0 ? ` ${tags.map((tag) => `#${tag}`).join(\" \")}` : \"\"}\n </Txt>\n ) : null}\n {caption && caption.length > 90 ? (\n <Pressable role=\"button\" aria-label={open ? labels.collapse : labels.expand} aria-expanded={open} onPress={() => setOpen((v) => !v)} hitSlop={10}>\n <Txt variant=\"caption\" tone=\"onMedia\" style={styles.underline}>\n {open ? labels.collapse : labels.expand}\n </Txt>\n </Pressable>\n ) : null}\n {credit ? (\n <Txt variant=\"caption\" tone=\"onMedia\">\n {credit}\n </Txt>\n ) : null}\n </View>\n </View>\n );\n}\n\nexport type ShortFeedProps<T> = {\n /** The feed's accessible name (\"Videos\"). */\n label: string;\n /** The videos, in order. */\n items: readonly T[];\n /** A stable key for an item. */\n getId: (item: T) => string;\n /** One slide: `active` is true for the one in view. */\n renderItem: (item: T, state: { active: boolean; index: number }) => React.ReactElement;\n /** The page's height in points (the feed's own height; one slide per page). */\n height: number;\n /** Called when the slide in view changes. */\n onActiveChange?: (index: number, item: T) => void;\n /** Styles merged last. */\n style?: StyleProp<ViewStyle>;\n};\n\n/** A vertical paging feed: one video per screen, the one in view plays, the others pause. */\nexport function ShortFeed<T>({ label, items, getId, renderItem, height, onActiveChange, style }: ShortFeedProps<T>) {\n const [active, setActive] = React.useState(0);\n // FlatList wants one stable callback for its whole life.\n const [onViewable] = React.useState(() => ({ viewableItems }: { viewableItems: ViewToken[] }) => {\n const first = viewableItems.find((v) => v.isViewable && typeof v.index === \"number\");\n if (first && typeof first.index === \"number\") setActive(first.index);\n });\n React.useEffect(() => {\n const item = items[active];\n if (item !== undefined) onActiveChange?.(active, item);\n // Only a change of the slide in view is an event.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [active]);\n return (\n <View role=\"list\" aria-label={label} style={[{ height }, style]}>\n <FlatList\n data={items as T[]}\n keyExtractor={getId}\n pagingEnabled\n showsVerticalScrollIndicator={false}\n snapToInterval={height}\n decelerationRate=\"fast\"\n getItemLayout={(_, index) => ({ length: height, offset: height * index, index })}\n windowSize={3}\n initialNumToRender={2}\n viewabilityConfig={{ itemVisiblePercentThreshold: 60 }}\n onViewableItemsChanged={onViewable}\n extraData={active}\n style={{ height }}\n renderItem={({ item, index }) => <View style={{ height }}>{renderItem(item, { active: index === active, index })}</View>}\n />\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n frame: { width: \"100%\", aspectRatio: 9 / 16, overflow: \"hidden\" },\n shade: { position: \"absolute\", left: 0, right: 0, bottom: 0, height: \"30%\", opacity: 0.55 },\n topStart: { position: \"absolute\", left: 12, top: 12 },\n rail: { position: \"absolute\", right: 8, bottom: 20, alignItems: \"center\", gap: 12 },\n railItem: { alignItems: \"center\", gap: 2 },\n railButton: { width: 44, height: 44, borderRadius: 22, alignItems: \"center\", justifyContent: \"center\" },\n count: { fontVariant: [\"tabular-nums\"], fontWeight: \"600\" },\n follow: { position: \"absolute\", bottom: -10, alignSelf: \"center\", width: 22, height: 22, borderRadius: 11, alignItems: \"center\", justifyContent: \"center\", overflow: \"hidden\" },\n caption: { position: \"absolute\", left: 12, right: 76, bottom: 16, gap: 6 },\n nameRow: { flexDirection: \"row\", alignItems: \"center\", gap: 6 },\n pill: { paddingHorizontal: 8, paddingVertical: 2, borderRadius: 999 },\n pillText: { fontWeight: \"700\", letterSpacing: 0.4 },\n underline: { textDecorationLine: \"underline\", fontWeight: \"600\" },\n});\n"],"mappings":"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","names":[]}
|
package/dist/native.d.ts
CHANGED
|
@@ -1044,11 +1044,16 @@ type LoaderProps = {
|
|
|
1044
1044
|
endDuration?: number;
|
|
1045
1045
|
/** inline (default) · block (a region's centre) · overlay (over its parent, frosted) · page (the whole screen). */
|
|
1046
1046
|
variant?: "inline" | "block" | "overlay" | "page";
|
|
1047
|
+
/**
|
|
1048
|
+
* The product whose animated mark waits in place of the Krizaka glyph (`orochia`, `orazaka`, `yazakia`, `yororis`,
|
|
1049
|
+
* `krizaka`). Still when the system reduces motion; the ending stays the check or the cross.
|
|
1050
|
+
*/
|
|
1051
|
+
product?: BrandId;
|
|
1047
1052
|
/** Styles merged last. */
|
|
1048
1053
|
style?: StyleProp<ViewStyle>;
|
|
1049
1054
|
};
|
|
1050
1055
|
/** A wait from start to end — the web `Loader`: delayed, never blinking, announced when it shows and when it ends. */
|
|
1051
|
-
declare function Loader({ label, status, successLabel, errorLabel, value, eta, delay, minDuration, endDuration, variant, style }: LoaderProps): React$1.JSX.Element | null;
|
|
1056
|
+
declare function Loader({ label, status, successLabel, errorLabel, value, eta, delay, minDuration, endDuration, variant, product, style }: LoaderProps): React$1.JSX.Element | null;
|
|
1052
1057
|
|
|
1053
1058
|
/**
|
|
1054
1059
|
* The Krizaka flock — the geometry of the mascots, drawn by the web `Mascot` (`./mascot.tsx`) and the native one
|
|
@@ -1513,6 +1518,33 @@ type PullToRefreshProps = Omit<RefreshControlProps, "colors" | "tintColor" | "pr
|
|
|
1513
1518
|
* draws it already with `onRefresh`.
|
|
1514
1519
|
*/
|
|
1515
1520
|
declare function PullToRefresh({ label, ...props }: PullToRefreshProps): React$1.JSX.Element;
|
|
1521
|
+
/** What `BrandedRefresh` hands to the scrollable: spread it on a `ScrollView` / `FlatList` (`{...scroll}`). */
|
|
1522
|
+
type BrandedRefreshScrollProps = {
|
|
1523
|
+
refreshControl: React$1.ReactElement<RefreshControlProps>;
|
|
1524
|
+
onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
1525
|
+
scrollEventThrottle: number;
|
|
1526
|
+
};
|
|
1527
|
+
type BrandedRefreshProps = {
|
|
1528
|
+
/** The product whose mark is drawn as the person pulls and turns while it refreshes. */
|
|
1529
|
+
product: BrandId;
|
|
1530
|
+
/** Whether the data is refreshing: keep it true until the new data is there. */
|
|
1531
|
+
refreshing: boolean;
|
|
1532
|
+
/** Called when the person pulls past the threshold. */
|
|
1533
|
+
onRefresh: () => void;
|
|
1534
|
+
/** The words announced when the refresh starts (“Refreshing your videos”) — passed translated. */
|
|
1535
|
+
label: string;
|
|
1536
|
+
/** The scrollable, given the props to spread: `{(scroll) => <ScrollView {...scroll}>…</ScrollView>}`. */
|
|
1537
|
+
children: (scroll: BrandedRefreshScrollProps) => React$1.ReactElement;
|
|
1538
|
+
/** The pull (in points) at which the mark is complete. Default 72. */
|
|
1539
|
+
threshold?: number;
|
|
1540
|
+
};
|
|
1541
|
+
/**
|
|
1542
|
+
* The product's mark as the pull-to-refresh: it grows and turns into place as the person pulls (iOS, where the content
|
|
1543
|
+
* overscrolls) and keeps its own motion while it refreshes (iOS and Android). The platform's control still does the
|
|
1544
|
+
* gesture, so the system announces it too; ours announces `label` when the refresh starts. Under reduced motion the mark
|
|
1545
|
+
* is still and appears without the growing.
|
|
1546
|
+
*/
|
|
1547
|
+
declare function BrandedRefresh({ product, refreshing, onRefresh, label, children, threshold }: BrandedRefreshProps): React$1.JSX.Element;
|
|
1516
1548
|
|
|
1517
1549
|
/** A choice: the value stored and its words (passed translated), a line under them, a second line on a key. */
|
|
1518
1550
|
type RadioOption = {
|
|
@@ -1704,6 +1736,37 @@ type SpinnerProps = Omit<ActivityIndicatorProps, "size" | "color"> & {
|
|
|
1704
1736
|
/** An indeterminate wait: the platform's activity indicator in the accent, named by `label`. */
|
|
1705
1737
|
declare function Spinner({ label, size, ...props }: SpinnerProps): React$1.JSX.Element;
|
|
1706
1738
|
|
|
1739
|
+
type SplashHandoffProps = {
|
|
1740
|
+
/** The product whose animated mark holds the screen. */
|
|
1741
|
+
product: BrandId;
|
|
1742
|
+
/** `true` once the first screen is ready to show: the splash dissolves into it. */
|
|
1743
|
+
ready: boolean;
|
|
1744
|
+
/**
|
|
1745
|
+
* Called once the splash is on screen and painted — hide the native splash here
|
|
1746
|
+
* (`SplashScreen.hideAsync()` of expo-splash-screen), so the static image dissolves into this one with no flash.
|
|
1747
|
+
*/
|
|
1748
|
+
onShown?: () => void;
|
|
1749
|
+
/** Called when the dissolve is over and the splash has left. */
|
|
1750
|
+
onDone?: () => void;
|
|
1751
|
+
/** The mark's side, in points. Default 96 — the size of the native splash icon, so nothing jumps. */
|
|
1752
|
+
size?: number;
|
|
1753
|
+
/** The background. Default: the theme's page colour, the one `app.json` gives the native splash. */
|
|
1754
|
+
background?: string;
|
|
1755
|
+
/** The words a screen reader hears while it waits (“Orochia is opening”) — passed translated. */
|
|
1756
|
+
label: string;
|
|
1757
|
+
/** The dissolve, in milliseconds. Default 320; none under reduced motion. */
|
|
1758
|
+
duration?: number;
|
|
1759
|
+
/** Styles merged last. */
|
|
1760
|
+
style?: StyleProp<ViewStyle>;
|
|
1761
|
+
};
|
|
1762
|
+
/**
|
|
1763
|
+
* The splash hand-off: the app's first frame is the static native splash; this puts the product's animated mark at the
|
|
1764
|
+
* same place and size over the same background, then dissolves it away once `ready`. Render it above the app's root
|
|
1765
|
+
* (absolute, full screen) and unmount nothing yourself: it removes its own content when the dissolve ends. Reduced
|
|
1766
|
+
* motion: the mark stands still and the splash leaves without fading.
|
|
1767
|
+
*/
|
|
1768
|
+
declare function SplashHandoff({ product, ready, onShown, onDone, size, background, label, duration, style }: SplashHandoffProps): React$1.JSX.Element | null;
|
|
1769
|
+
|
|
1707
1770
|
type StepProgressProps = {
|
|
1708
1771
|
/** The current step, from 1. */
|
|
1709
1772
|
step: number;
|
|
@@ -2243,4 +2306,4 @@ declare function YazakiaMark({ size, animated, title, neutral }: NativeMarkProps
|
|
|
2243
2306
|
*/
|
|
2244
2307
|
declare function YororisMark({ size, animated, title, neutral }: NativeMarkProps): React__default.JSX.Element;
|
|
2245
2308
|
|
|
2246
|
-
export { ActionSheet, type ActionSheetAction, type ActionSheetProps, type ActivityEvent, ActivityFeed, type ActivityFeedLabels, type ActivityFeedProps, type ActivityTone, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, AvatarRoot, type AvatarSize, Badge, type BadgeProps, type BadgeTone, type BrandId, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Calendar, type CalendarLabels, type CalendarProps, Card, CardBody, type CardBodyProps, CardDescription, CardFooter, CardImage, type CardImageProps, CardMedia, type CardMediaProps, CardOverlay, type CardOverlayProps, CardRoot, type CardRootProps, CardTitle, Checkbox, type CheckboxProps, Chip, type ChipGroupProps, type ChipProps, type ChipSize, Combobox, type ComboboxLabels, type ComboboxProps, ConversationItem, type ConversationItemProps, Countdown, type CountdownProps, type CountdownUnits, DateField, type DateFieldLabels, type DateFieldProps, type DatePart, DateWheel, type DateWheelProps, DayStrip, type DayStripProps, type DescriptionItem, DescriptionList, type DescriptionListProps, EmptyState, type EmptyStateProps, ErrorState, Fab, type FabProps, GoalGauge, type GoalGaugeProps, type GridPhoto, type HapticKind, Header, type HeaderProps, IconButton, type IconButtonProps, ImageViewer, type ImageViewerProps, type Insets, KrizakaMark, Loader, LoaderGlyph, type LoaderGlyphProps, type LoaderProps, LoadingState, Mascot, type MascotProps, MascotState, type MascotStateProps, MatchDialog, type MatchDialogProps, MessageBubble, type MessageBubbleLabels, type MessageBubbleProps, MessageComposer, type MessageComposerProps, type MessageStatus, Meter, type MeterPart, type MeterProps, type Mode, MonthPicker, type MonthPickerProps, type Motion, type NativeMarkProps, NumberTicker, type NumberTickerProps, Onboarding, type OnboardingProps, type OnboardingSlide, OrazakaMark, OrochiaMark, OtpInput, type OtpInputProps, Pagination, type PaginationLabels, type PaginationProps, PermissionPrompt, type PermissionPromptProps, type PermissionStatus, PersonCard, type PersonCardProps, Phoenix, type PhoenixProps, PhotoGrid, type PhotoGridLabels, type PhotoGridProps, ProductMark, ProfileCard, type ProfileCardProps, type ProfileStat, Progress, type ProgressProps, PullToRefresh, type PullToRefreshProps, RadioGroup, type RadioGroupProps, type RadioOption, type Radius, Screen, type ScreenProps, SearchField, type SearchFieldProps, Segmented, type SegmentedOption, type SegmentedProps, Select, type SelectOption, type SelectProps, Sheet, type SheetProps, Skeleton, type SkeletonProps, Slider, type SliderProps, type SliderValue, Spinner, type SpinnerProps, type Step, StepProgress, type StepProgressProps, type StepStatus, Stepper, type StepperProps, SuccessState, type SwipeAction, SwipeDeck, type SwipeDeckLabels, type SwipeDeckProps, type SwipeDirection, SwipeableRow, type SwipeableRowProps, Switch, type SwitchProps, TabBar, type TabBarItem, type TabBarProps, type TabItem, Tabs, type TabsProps, type TagOption, TagSelector, type TagSelectorProps, TextField, type TextFieldProps, type Theme, type ThemeContextValue, type ThemeFonts, type ThemeName, type ThemeOverrides, ThemeProvider, type ThemeProviderProps, TimePicker, type TimePickerLabels, type TimePickerProps, type TimeValue, type ToastItem, type ToastOptions, type ToastTone, Toaster, type ToasterProps, Txt, type TxtProps, type TxtTone, type TxtVariant, TypingIndicator, type TypingIndicatorProps, VerifiedBadge, type VerifiedBadgeProps, type ViewerImage, WelcomeState, Wheel, WheelDivider, type WheelOption, WheelPicker, type WheelPickerProps, type WheelProps, YazakiaMark, YororisMark, addDays, addMonths, ageOn, alpha, calendarLabels, comboboxLabels, composeDate, dateFieldLabels, datePartsOrder, daysInMonth, formatTime, isRealDate, latestBirthDate, monthNames, prefetchNeighbours, splitDuration, textStyles, timeSlots, timeToMinutes, toast, todayIso, useCollapsingHeader, useCountdown, useDelayedWait, useReducedMotion, useTheme, uses12Hours };
|
|
2309
|
+
export { ActionSheet, type ActionSheetAction, type ActionSheetProps, type ActivityEvent, ActivityFeed, type ActivityFeedLabels, type ActivityFeedProps, type ActivityTone, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, AvatarRoot, type AvatarSize, Badge, type BadgeProps, type BadgeTone, type BrandId, BrandedRefresh, type BrandedRefreshProps, type BrandedRefreshScrollProps, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Calendar, type CalendarLabels, type CalendarProps, Card, CardBody, type CardBodyProps, CardDescription, CardFooter, CardImage, type CardImageProps, CardMedia, type CardMediaProps, CardOverlay, type CardOverlayProps, CardRoot, type CardRootProps, CardTitle, Checkbox, type CheckboxProps, Chip, type ChipGroupProps, type ChipProps, type ChipSize, Combobox, type ComboboxLabels, type ComboboxProps, ConversationItem, type ConversationItemProps, Countdown, type CountdownProps, type CountdownUnits, DateField, type DateFieldLabels, type DateFieldProps, type DatePart, DateWheel, type DateWheelProps, DayStrip, type DayStripProps, type DescriptionItem, DescriptionList, type DescriptionListProps, EmptyState, type EmptyStateProps, ErrorState, Fab, type FabProps, GoalGauge, type GoalGaugeProps, type GridPhoto, type HapticKind, Header, type HeaderProps, IconButton, type IconButtonProps, ImageViewer, type ImageViewerProps, type Insets, KrizakaMark, Loader, LoaderGlyph, type LoaderGlyphProps, type LoaderProps, LoadingState, Mascot, type MascotProps, MascotState, type MascotStateProps, MatchDialog, type MatchDialogProps, MessageBubble, type MessageBubbleLabels, type MessageBubbleProps, MessageComposer, type MessageComposerProps, type MessageStatus, Meter, type MeterPart, type MeterProps, type Mode, MonthPicker, type MonthPickerProps, type Motion, type NativeMarkProps, NumberTicker, type NumberTickerProps, Onboarding, type OnboardingProps, type OnboardingSlide, OrazakaMark, OrochiaMark, OtpInput, type OtpInputProps, Pagination, type PaginationLabels, type PaginationProps, PermissionPrompt, type PermissionPromptProps, type PermissionStatus, PersonCard, type PersonCardProps, Phoenix, type PhoenixProps, PhotoGrid, type PhotoGridLabels, type PhotoGridProps, ProductMark, ProfileCard, type ProfileCardProps, type ProfileStat, Progress, type ProgressProps, PullToRefresh, type PullToRefreshProps, RadioGroup, type RadioGroupProps, type RadioOption, type Radius, Screen, type ScreenProps, SearchField, type SearchFieldProps, Segmented, type SegmentedOption, type SegmentedProps, Select, type SelectOption, type SelectProps, Sheet, type SheetProps, Skeleton, type SkeletonProps, Slider, type SliderProps, type SliderValue, Spinner, type SpinnerProps, SplashHandoff, type SplashHandoffProps, type Step, StepProgress, type StepProgressProps, type StepStatus, Stepper, type StepperProps, SuccessState, type SwipeAction, SwipeDeck, type SwipeDeckLabels, type SwipeDeckProps, type SwipeDirection, SwipeableRow, type SwipeableRowProps, Switch, type SwitchProps, TabBar, type TabBarItem, type TabBarProps, type TabItem, Tabs, type TabsProps, type TagOption, TagSelector, type TagSelectorProps, TextField, type TextFieldProps, type Theme, type ThemeContextValue, type ThemeFonts, type ThemeName, type ThemeOverrides, ThemeProvider, type ThemeProviderProps, TimePicker, type TimePickerLabels, type TimePickerProps, type TimeValue, type ToastItem, type ToastOptions, type ToastTone, Toaster, type ToasterProps, Txt, type TxtProps, type TxtTone, type TxtVariant, TypingIndicator, type TypingIndicatorProps, VerifiedBadge, type VerifiedBadgeProps, type ViewerImage, WelcomeState, Wheel, WheelDivider, type WheelOption, WheelPicker, type WheelPickerProps, type WheelProps, YazakiaMark, YororisMark, addDays, addMonths, ageOn, alpha, calendarLabels, comboboxLabels, composeDate, dateFieldLabels, datePartsOrder, daysInMonth, formatTime, isRealDate, latestBirthDate, monthNames, prefetchNeighbours, splitDuration, textStyles, timeSlots, timeToMinutes, toast, todayIso, useCollapsingHeader, useCountdown, useDelayedWait, useReducedMotion, useTheme, uses12Hours };
|