@fungi.computer/caps 0.0.0-stage → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1125 -2
- package/dist/blocks/app-bar.d.ts +43 -0
- package/dist/blocks/app-bar.js +244 -0
- package/dist/blocks/app-status-bar.d.ts +93 -0
- package/dist/blocks/app-status-bar.js +42 -0
- package/dist/blocks/async-state.d.ts +21 -0
- package/dist/blocks/async-state.js +8 -0
- package/dist/blocks/card-grid.d.ts +11 -0
- package/dist/blocks/card-grid.js +21 -0
- package/dist/blocks/command-menu.d.ts +26 -0
- package/dist/blocks/command-menu.js +70 -0
- package/dist/blocks/composer.d.ts +23 -0
- package/dist/blocks/composer.js +13 -0
- package/dist/blocks/empty-state.d.ts +59 -0
- package/dist/blocks/empty-state.js +35 -0
- package/dist/blocks/faq-chat.d.ts +62 -0
- package/dist/blocks/faq-chat.js +77 -0
- package/dist/blocks/game-share-card.d.ts +17 -0
- package/dist/blocks/game-share-card.js +9 -0
- package/dist/blocks/launcher-grid.d.ts +50 -0
- package/dist/blocks/launcher-grid.js +11 -0
- package/dist/blocks/listing-detail.d.ts +23 -0
- package/dist/blocks/listing-detail.js +12 -0
- package/dist/blocks/loading-state.d.ts +5 -0
- package/dist/blocks/loading-state.js +8 -0
- package/dist/blocks/mosaic.d.ts +29 -0
- package/dist/blocks/mosaic.js +19 -0
- package/dist/blocks/permission-grid.d.ts +45 -0
- package/dist/blocks/permission-grid.js +14 -0
- package/dist/blocks/pricing-card.d.ts +53 -0
- package/dist/blocks/pricing-card.js +12 -0
- package/dist/blocks/release-tag.d.ts +20 -0
- package/dist/blocks/release-tag.js +10 -0
- package/dist/blocks/resource-select.d.ts +22 -0
- package/dist/blocks/resource-select.js +16 -0
- package/dist/blocks/result-state.d.ts +15 -0
- package/dist/blocks/result-state.js +8 -0
- package/dist/blocks/section-card.d.ts +31 -0
- package/dist/blocks/section-card.js +7 -0
- package/dist/blocks/section-heading.d.ts +13 -0
- package/dist/blocks/section-heading.js +11 -0
- package/dist/blocks/spec-sheet.d.ts +125 -0
- package/dist/blocks/spec-sheet.js +47 -0
- package/dist/blocks/status-tray.d.ts +83 -0
- package/dist/blocks/status-tray.js +79 -0
- package/dist/blocks/upload-queue.d.ts +48 -0
- package/dist/blocks/upload-queue.js +24 -0
- package/dist/components/action-row.d.ts +16 -0
- package/dist/components/action-row.js +11 -0
- package/dist/components/activity-line.d.ts +33 -0
- package/dist/components/activity-line.js +69 -0
- package/dist/components/alert.d.ts +17 -0
- package/dist/components/alert.js +17 -0
- package/dist/components/badge.d.ts +19 -0
- package/dist/components/badge.js +24 -0
- package/dist/components/button.d.ts +55 -0
- package/dist/components/button.js +230 -0
- package/dist/components/card.d.ts +61 -0
- package/dist/components/card.js +48 -0
- package/dist/components/chat-bubble.d.ts +34 -0
- package/dist/components/chat-bubble.js +10 -0
- package/dist/components/checkbox-bead.d.ts +6 -0
- package/dist/components/checkbox-bead.js +67 -0
- package/dist/components/checkbox.d.ts +21 -0
- package/dist/components/checkbox.js +46 -0
- package/dist/components/code-input.d.ts +35 -0
- package/dist/components/code-input.js +126 -0
- package/dist/components/combobox.d.ts +86 -0
- package/dist/components/combobox.js +218 -0
- package/dist/components/confirm-action.d.ts +23 -0
- package/dist/components/confirm-action.js +64 -0
- package/dist/components/copy-field.d.ts +53 -0
- package/dist/components/copy-field.js +49 -0
- package/dist/components/count-badge.d.ts +15 -0
- package/dist/components/count-badge.js +9 -0
- package/dist/components/cover-pattern.d.ts +19 -0
- package/dist/components/cover-pattern.js +74 -0
- package/dist/components/data-list.d.ts +25 -0
- package/dist/components/data-list.js +16 -0
- package/dist/components/dialog.d.ts +39 -0
- package/dist/components/dialog.js +73 -0
- package/dist/components/diff-view.d.ts +14 -0
- package/dist/components/diff-view.js +13 -0
- package/dist/components/disclosure.d.ts +29 -0
- package/dist/components/disclosure.js +19 -0
- package/dist/components/dropdown-menu.d.ts +49 -0
- package/dist/components/dropdown-menu.js +98 -0
- package/dist/components/field-guide.d.ts +41 -0
- package/dist/components/field-guide.js +18 -0
- package/dist/components/field.d.ts +164 -0
- package/dist/components/field.js +228 -0
- package/dist/components/game-feedback.d.ts +84 -0
- package/dist/components/game-feedback.js +48 -0
- package/dist/components/game-hud.d.ts +126 -0
- package/dist/components/game-hud.js +136 -0
- package/dist/components/generation-frame.d.ts +36 -0
- package/dist/components/generation-frame.js +97 -0
- package/dist/components/gooey.d.ts +32 -0
- package/dist/components/gooey.js +25 -0
- package/dist/components/hold-button.d.ts +26 -0
- package/dist/components/hold-button.js +115 -0
- package/dist/components/icon-button.d.ts +24 -0
- package/dist/components/icon-button.js +18 -0
- package/dist/components/icon-checkbox.d.ts +20 -0
- package/dist/components/icon-checkbox.js +9 -0
- package/dist/components/icon-choice-mark.d.ts +6 -0
- package/dist/components/icon-choice-mark.js +5 -0
- package/dist/components/icon-lamp.d.ts +42 -0
- package/dist/components/icon-lamp.js +15 -0
- package/dist/components/icon-radio.d.ts +16 -0
- package/dist/components/icon-radio.js +9 -0
- package/dist/components/inline-code.d.ts +3 -0
- package/dist/components/inline-code.js +7 -0
- package/dist/components/input-group.d.ts +9 -0
- package/dist/components/input-group.js +15 -0
- package/dist/components/input.d.ts +15 -0
- package/dist/components/input.js +15 -0
- package/dist/components/item-grid.d.ts +110 -0
- package/dist/components/item-grid.js +136 -0
- package/dist/components/keycap.d.ts +80 -0
- package/dist/components/keycap.js +18 -0
- package/dist/components/label.d.ts +13 -0
- package/dist/components/label.js +7 -0
- package/dist/components/listbox.d.ts +50 -0
- package/dist/components/listbox.js +134 -0
- package/dist/components/loader-blobs.d.ts +5 -0
- package/dist/components/loader-blobs.js +128 -0
- package/dist/components/loader.d.ts +21 -0
- package/dist/components/loader.js +25 -0
- package/dist/components/markdown.d.ts +23 -0
- package/dist/components/markdown.js +70 -0
- package/dist/components/minimap-labels.d.ts +39 -0
- package/dist/components/minimap-labels.js +113 -0
- package/dist/components/monogram.d.ts +32 -0
- package/dist/components/monogram.js +24 -0
- package/dist/components/motion-visibility.d.ts +2 -0
- package/dist/components/motion-visibility.js +25 -0
- package/dist/components/navigation-rail.d.ts +11 -0
- package/dist/components/navigation-rail.js +55 -0
- package/dist/components/overlay-root.d.ts +16 -0
- package/dist/components/overlay-root.js +24 -0
- package/dist/components/pixel-number.d.ts +50 -0
- package/dist/components/pixel-number.js +113 -0
- package/dist/components/popover.d.ts +31 -0
- package/dist/components/popover.js +24 -0
- package/dist/components/presence.d.ts +59 -0
- package/dist/components/presence.js +232 -0
- package/dist/components/price-tag.d.ts +11 -0
- package/dist/components/price-tag.js +6 -0
- package/dist/components/progress.d.ts +25 -0
- package/dist/components/progress.js +24 -0
- package/dist/components/prose.d.ts +14 -0
- package/dist/components/prose.js +10 -0
- package/dist/components/quota-meter.d.ts +24 -0
- package/dist/components/quota-meter.js +11 -0
- package/dist/components/radio-bead.d.ts +4 -0
- package/dist/components/radio-bead.js +53 -0
- package/dist/components/radio-group.d.ts +54 -0
- package/dist/components/radio-group.js +64 -0
- package/dist/components/resize-handle.d.ts +23 -0
- package/dist/components/resize-handle.js +31 -0
- package/dist/components/rough-drawing.d.ts +42 -0
- package/dist/components/rough-drawing.js +231 -0
- package/dist/components/rough.d.ts +68 -0
- package/dist/components/rough.js +33 -0
- package/dist/components/scroll-area.d.ts +12 -0
- package/dist/components/scroll-area.js +96 -0
- package/dist/components/scroll-motion.d.ts +12 -0
- package/dist/components/scroll-motion.js +31 -0
- package/dist/components/scroll-to-bottom-blob-state.d.ts +40 -0
- package/dist/components/scroll-to-bottom-blob-state.js +109 -0
- package/dist/components/scroll-to-bottom-blob.d.ts +16 -0
- package/dist/components/scroll-to-bottom-blob.js +174 -0
- package/dist/components/select.d.ts +9 -0
- package/dist/components/select.js +12 -0
- package/dist/components/selectable.d.ts +13 -0
- package/dist/components/selectable.js +45 -0
- package/dist/components/send-action.d.ts +33 -0
- package/dist/components/send-action.js +96 -0
- package/dist/components/separator.d.ts +11 -0
- package/dist/components/separator.js +7 -0
- package/dist/components/skeleton.d.ts +5 -0
- package/dist/components/skeleton.js +7 -0
- package/dist/components/slider.d.ts +18 -0
- package/dist/components/slider.js +31 -0
- package/dist/components/stat.d.ts +17 -0
- package/dist/components/stat.js +7 -0
- package/dist/components/status-bead.d.ts +9 -0
- package/dist/components/status-bead.js +107 -0
- package/dist/components/status-mark.d.ts +12 -0
- package/dist/components/status-mark.js +177 -0
- package/dist/components/status.d.ts +38 -0
- package/dist/components/status.js +28 -0
- package/dist/components/store-card.d.ts +21 -0
- package/dist/components/store-card.js +10 -0
- package/dist/components/surface.d.ts +89 -0
- package/dist/components/surface.js +31 -0
- package/dist/components/switch-bead.d.ts +4 -0
- package/dist/components/switch-bead.js +62 -0
- package/dist/components/switch.d.ts +11 -0
- package/dist/components/switch.js +36 -0
- package/dist/components/tabs.d.ts +55 -0
- package/dist/components/tabs.js +81 -0
- package/dist/components/technonomicon.d.ts +192 -0
- package/dist/components/technonomicon.js +121 -0
- package/dist/components/textarea.d.ts +9 -0
- package/dist/components/textarea.js +11 -0
- package/dist/components/toaster.d.ts +4 -0
- package/dist/components/toaster.js +13 -0
- package/dist/components/tool-call-chip.d.ts +22 -0
- package/dist/components/tool-call-chip.js +100 -0
- package/dist/components/tooltip.d.ts +41 -0
- package/dist/components/tooltip.js +169 -0
- package/dist/components/trading-card.d.ts +60 -0
- package/dist/components/trading-card.js +13 -0
- package/dist/components/undo-action.d.ts +52 -0
- package/dist/components/undo-action.js +100 -0
- package/dist/components/undo-toast.d.ts +21 -0
- package/dist/components/undo-toast.js +58 -0
- package/dist/components/visually-hidden.d.ts +9 -0
- package/dist/components/visually-hidden.js +11 -0
- package/dist/components/window.d.ts +65 -0
- package/dist/components/window.js +31 -0
- package/dist/components/wizard.d.ts +17 -0
- package/dist/components/wizard.js +19 -0
- package/dist/enhance/cigarette-card.d.ts +8 -0
- package/dist/enhance/cigarette-card.js +33 -0
- package/dist/enhance/sketch.d.ts +16 -0
- package/dist/enhance/sketch.js +130 -0
- package/dist/form-error.d.ts +7 -0
- package/dist/form-error.js +14 -0
- package/dist/form-fields.d.ts +15 -0
- package/dist/form-fields.js +250 -0
- package/dist/form-schema.d.ts +166 -0
- package/dist/form-schema.js +398 -0
- package/dist/form.d.ts +30 -0
- package/dist/form.js +20 -0
- package/dist/lib/cn.d.ts +8 -0
- package/dist/lib/cn.js +12 -0
- package/dist/lib/format-money.d.ts +2 -0
- package/dist/lib/format-money.js +22 -0
- package/dist/lib/glide.d.ts +12 -0
- package/dist/lib/glide.js +143 -0
- package/dist/lib/ime.d.ts +3 -0
- package/dist/lib/ime.js +8 -0
- package/dist/lib/motion-spring.d.ts +27 -0
- package/dist/lib/motion-spring.js +36 -0
- package/dist/lib/motion.d.ts +51 -0
- package/dist/lib/motion.js +161 -0
- package/dist/lib/reorder-motion.d.ts +13 -0
- package/dist/lib/reorder-motion.js +201 -0
- package/dist/lib/seed-hash.d.ts +6 -0
- package/dist/lib/seed-hash.js +13 -0
- package/dist/lib/tanstack-highlight.d.ts +4 -0
- package/dist/lib/tanstack-highlight.js +41 -0
- package/dist/schema-form.d.ts +120 -0
- package/dist/schema-form.js +129 -0
- package/dist/styles.css +18814 -0
- package/docs/api/README.md +134 -0
- package/docs/api/blocks/app-bar.md +227 -0
- package/docs/api/blocks/app-status-bar.md +257 -0
- package/docs/api/blocks/async-state.md +53 -0
- package/docs/api/blocks/card-grid.md +31 -0
- package/docs/api/blocks/command-menu.md +89 -0
- package/docs/api/blocks/composer.md +40 -0
- package/docs/api/blocks/empty-state.md +97 -0
- package/docs/api/blocks/faq-chat.md +147 -0
- package/docs/api/blocks/game-share-card.md +40 -0
- package/docs/api/blocks/launcher-grid.md +86 -0
- package/docs/api/blocks/listing-detail.md +51 -0
- package/docs/api/blocks/loading-state.md +21 -0
- package/docs/api/blocks/mosaic.md +94 -0
- package/docs/api/blocks/permission-grid.md +79 -0
- package/docs/api/blocks/pricing-card.md +90 -0
- package/docs/api/blocks/release-tag.md +62 -0
- package/docs/api/blocks/resource-select.md +126 -0
- package/docs/api/blocks/result-state.md +42 -0
- package/docs/api/blocks/section-card.md +42 -0
- package/docs/api/blocks/section-heading.md +61 -0
- package/docs/api/blocks/spec-sheet.md +400 -0
- package/docs/api/blocks/status-tray.md +141 -0
- package/docs/api/blocks/upload-queue.md +110 -0
- package/docs/api/components/action-row.md +51 -0
- package/docs/api/components/activity-line.md +103 -0
- package/docs/api/components/alert.md +60 -0
- package/docs/api/components/badge.md +77 -0
- package/docs/api/components/button.md +94 -0
- package/docs/api/components/card.md +165 -0
- package/docs/api/components/chat-bubble.md +66 -0
- package/docs/api/components/checkbox-bead.md +20 -0
- package/docs/api/components/checkbox.md +42 -0
- package/docs/api/components/code-input.md +61 -0
- package/docs/api/components/combobox.md +303 -0
- package/docs/api/components/confirm-action.md +58 -0
- package/docs/api/components/copy-field.md +106 -0
- package/docs/api/components/count-badge.md +39 -0
- package/docs/api/components/cover-pattern.md +43 -0
- package/docs/api/components/data-list.md +80 -0
- package/docs/api/components/dialog.md +235 -0
- package/docs/api/components/diff-view.md +59 -0
- package/docs/api/components/disclosure.md +71 -0
- package/docs/api/components/dropdown-menu.md +269 -0
- package/docs/api/components/field-guide.md +174 -0
- package/docs/api/components/field.md +252 -0
- package/docs/api/components/game-feedback.md +157 -0
- package/docs/api/components/game-hud.md +359 -0
- package/docs/api/components/generation-frame.md +59 -0
- package/docs/api/components/hold-button.md +44 -0
- package/docs/api/components/icon-button.md +56 -0
- package/docs/api/components/icon-checkbox.md +42 -0
- package/docs/api/components/icon-choice-mark.md +31 -0
- package/docs/api/components/icon-lamp.md +92 -0
- package/docs/api/components/icon-radio.md +42 -0
- package/docs/api/components/inline-code.md +21 -0
- package/docs/api/components/input-group.md +53 -0
- package/docs/api/components/input.md +54 -0
- package/docs/api/components/item-grid.md +262 -0
- package/docs/api/components/keycap.md +102 -0
- package/docs/api/components/label.md +40 -0
- package/docs/api/components/listbox.md +131 -0
- package/docs/api/components/loader-blobs.md +9 -0
- package/docs/api/components/loader.md +51 -0
- package/docs/api/components/markdown.md +91 -0
- package/docs/api/components/minimap-labels.md +84 -0
- package/docs/api/components/monogram.md +96 -0
- package/docs/api/components/motion-visibility.md +9 -0
- package/docs/api/components/navigation-rail.md +37 -0
- package/docs/api/components/overlay-root.md +92 -0
- package/docs/api/components/pixel-number.md +120 -0
- package/docs/api/components/popover.md +80 -0
- package/docs/api/components/presence.md +106 -0
- package/docs/api/components/price-tag.md +48 -0
- package/docs/api/components/progress.md +90 -0
- package/docs/api/components/prose.md +48 -0
- package/docs/api/components/quota-meter.md +47 -0
- package/docs/api/components/radio-bead.md +9 -0
- package/docs/api/components/radio-group.md +126 -0
- package/docs/api/components/resize-handle.md +46 -0
- package/docs/api/components/rough-drawing.md +122 -0
- package/docs/api/components/rough.md +66 -0
- package/docs/api/components/scroll-area.md +22 -0
- package/docs/api/components/scroll-motion.md +9 -0
- package/docs/api/components/scroll-to-bottom-blob-state.md +162 -0
- package/docs/api/components/scroll-to-bottom-blob.md +73 -0
- package/docs/api/components/select.md +39 -0
- package/docs/api/components/send-action.md +58 -0
- package/docs/api/components/separator.md +38 -0
- package/docs/api/components/skeleton.md +31 -0
- package/docs/api/components/slider.md +70 -0
- package/docs/api/components/stat.md +42 -0
- package/docs/api/components/status-bead.md +19 -0
- package/docs/api/components/status-mark.md +19 -0
- package/docs/api/components/status.md +105 -0
- package/docs/api/components/store-card.md +53 -0
- package/docs/api/components/surface.md +161 -0
- package/docs/api/components/switch-bead.md +9 -0
- package/docs/api/components/switch.md +40 -0
- package/docs/api/components/tabs.md +138 -0
- package/docs/api/components/technonomicon.md +773 -0
- package/docs/api/components/textarea.md +40 -0
- package/docs/api/components/toaster.md +29 -0
- package/docs/api/components/tool-call-chip.md +68 -0
- package/docs/api/components/tooltip.md +113 -0
- package/docs/api/components/trading-card.md +95 -0
- package/docs/api/components/undo-action.md +117 -0
- package/docs/api/components/undo-toast.md +49 -0
- package/docs/api/components/visually-hidden.md +37 -0
- package/docs/api/components/window.md +291 -0
- package/docs/api/components/wizard.md +65 -0
- package/docs/api/enhance/cigarette-card.md +52 -0
- package/docs/api/enhance/sketch.md +42 -0
- package/docs/api/form.md +1623 -0
- package/docs/api/lib/cn.md +46 -0
- package/docs/api/lib/format-money.md +30 -0
- package/docs/api/lib/glide.md +36 -0
- package/docs/api/lib/ime.md +29 -0
- package/docs/api/lib/motion-spring.md +91 -0
- package/docs/api/lib/motion.md +212 -0
- package/docs/api/lib/reorder-motion.md +46 -0
- package/docs/api/lib/seed-hash.md +31 -0
- package/docs/api/lib/tanstack-highlight.md +40 -0
- package/package.json +597 -3
- package/src/app-status-bar.css +158 -0
- package/src/fonts.css +1 -0
- package/src/status-tray.css +282 -0
- package/src/styles.css +10177 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useImperativeHandle, useLayoutEffect, useRef, useState, } from "react";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
import { canAnimate, motionEasing, readMotion, useReducedMotion, } from "../lib/motion.js";
|
|
5
|
+
/**
|
|
6
|
+
* The gap a vertical grid or flex container puts before this element, or 0
|
|
7
|
+
* when it is the first child or its container doesn't stack.
|
|
8
|
+
*/
|
|
9
|
+
function stackGap(element) {
|
|
10
|
+
const parent = element.parentElement;
|
|
11
|
+
if (!parent || element.previousElementSibling === null)
|
|
12
|
+
return 0;
|
|
13
|
+
const style = getComputedStyle(parent);
|
|
14
|
+
const stacks = style.display.includes("grid") ||
|
|
15
|
+
(style.display.includes("flex") &&
|
|
16
|
+
style.flexDirection.startsWith("column"));
|
|
17
|
+
if (!stacks)
|
|
18
|
+
return 0;
|
|
19
|
+
const gap = Number.parseFloat(style.rowGap);
|
|
20
|
+
return Number.isFinite(gap) ? gap : 0;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Content that arrives and leaves instead of popping: it makes room, fades in
|
|
24
|
+
* while travelling the theme's `--stipe-motion-distance`, and on leaving fades
|
|
25
|
+
* out and gives its room back before it unmounts. Reduced motion keeps a short
|
|
26
|
+
* fade only.
|
|
27
|
+
*/
|
|
28
|
+
export const Presence = forwardRef(function Presence({ show, appear = false, children, className, ...props }, ref) {
|
|
29
|
+
const node = useRef(null);
|
|
30
|
+
useImperativeHandle(ref, () => node.current);
|
|
31
|
+
const reduced = useReducedMotion();
|
|
32
|
+
const [mounted, setMounted] = useState(show);
|
|
33
|
+
const first = useRef(true);
|
|
34
|
+
if (show && !mounted)
|
|
35
|
+
setMounted(true);
|
|
36
|
+
useLayoutEffect(() => {
|
|
37
|
+
const element = node.current;
|
|
38
|
+
const initial = first.current;
|
|
39
|
+
first.current = false;
|
|
40
|
+
if (!element || (initial && !appear))
|
|
41
|
+
return;
|
|
42
|
+
if (!canAnimate(element)) {
|
|
43
|
+
if (!show)
|
|
44
|
+
setMounted(false);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const motion = readMotion(element);
|
|
48
|
+
const travel = `translateY(${String(motion.distance)}px)`;
|
|
49
|
+
const easing = motionEasing(motion, motion.ease);
|
|
50
|
+
// In flow, arriving content makes room and leaving content gives it
|
|
51
|
+
// back, so nothing below jumps. Reduced motion changes the room at once.
|
|
52
|
+
const height = element.getBoundingClientRect().height;
|
|
53
|
+
const gap = stackGap(element);
|
|
54
|
+
const room = (from, to) => {
|
|
55
|
+
element.style.overflow = "clip";
|
|
56
|
+
const edge = (size) => ({
|
|
57
|
+
height: `${String(size)}px`,
|
|
58
|
+
marginBlockStart: `${String(size === 0 ? -gap : 0)}px`,
|
|
59
|
+
});
|
|
60
|
+
const animation = element.animate([edge(from), edge(to)], {
|
|
61
|
+
duration: motion.normal,
|
|
62
|
+
easing,
|
|
63
|
+
});
|
|
64
|
+
const restore = () => {
|
|
65
|
+
element.style.removeProperty("overflow");
|
|
66
|
+
};
|
|
67
|
+
animation.addEventListener("finish", restore);
|
|
68
|
+
animation.addEventListener("cancel", restore);
|
|
69
|
+
return animation;
|
|
70
|
+
};
|
|
71
|
+
if (show) {
|
|
72
|
+
const animations = [
|
|
73
|
+
element.animate([
|
|
74
|
+
{ opacity: 0, transform: travel },
|
|
75
|
+
{ opacity: 1, transform: "none" },
|
|
76
|
+
], { duration: motion.normal, easing }),
|
|
77
|
+
];
|
|
78
|
+
if (!reduced && height > 0)
|
|
79
|
+
animations.push(room(0, height));
|
|
80
|
+
return () => {
|
|
81
|
+
for (const animation of animations)
|
|
82
|
+
animation.cancel();
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const fade = element.animate([
|
|
86
|
+
{ opacity: 1, transform: "none" },
|
|
87
|
+
{ opacity: 0, transform: travel },
|
|
88
|
+
], {
|
|
89
|
+
duration: motion.fast,
|
|
90
|
+
easing: motionEasing(motion, motion.easeExit),
|
|
91
|
+
fill: "forwards",
|
|
92
|
+
});
|
|
93
|
+
const last = !reduced && height > 0 ? room(height, 0) : fade;
|
|
94
|
+
if (last !== fade)
|
|
95
|
+
last.effect?.updateTiming({ fill: "forwards" });
|
|
96
|
+
last.addEventListener("finish", () => {
|
|
97
|
+
setMounted(false);
|
|
98
|
+
});
|
|
99
|
+
return () => {
|
|
100
|
+
fade.cancel();
|
|
101
|
+
last.cancel();
|
|
102
|
+
};
|
|
103
|
+
}, [show, appear, reduced]);
|
|
104
|
+
if (!mounted)
|
|
105
|
+
return null;
|
|
106
|
+
return (_jsx("div", { ...props, ref: node, className: cn("caps-presence", className), "data-present": show, "aria-hidden": show ? undefined : true, children: children }));
|
|
107
|
+
});
|
|
108
|
+
/**
|
|
109
|
+
* Content that opens and closes its own space: an inserted alert, a field
|
|
110
|
+
* error, a disclosure body. Height and opacity follow the theme's tempo; under
|
|
111
|
+
* reduced motion the space changes at once and only the fade remains.
|
|
112
|
+
*/
|
|
113
|
+
export const Collapse = forwardRef(function Collapse({ open, children, className, ...props }, ref) {
|
|
114
|
+
return (_jsx("div", { ...props, ref: ref, className: cn("caps-collapse", className), "data-open": open, "aria-hidden": open ? undefined : true, children: _jsx("div", { className: "caps-collapse-clip", children: children }) }));
|
|
115
|
+
});
|
|
116
|
+
/**
|
|
117
|
+
* One piece of content replaced by another without a hard cut: loading to
|
|
118
|
+
* loaded, "Saving…" to "Saved". The old content fades out (blurred by the
|
|
119
|
+
* theme's `--stipe-motion-blur`) as the new one arrives, and the box eases to
|
|
120
|
+
* the new size. Reduced motion keeps the crossfade and drops the travel.
|
|
121
|
+
*/
|
|
122
|
+
export const Swap = forwardRef(function Swap({ swapKey, anchor = "start", children, className, ...props }, ref) {
|
|
123
|
+
const node = useRef(null);
|
|
124
|
+
useImperativeHandle(ref, () => node.current);
|
|
125
|
+
const reduced = useReducedMotion();
|
|
126
|
+
// The latest content rendered under the current key, kept so it can leave.
|
|
127
|
+
const [shown, setShown] = useState({
|
|
128
|
+
key: swapKey,
|
|
129
|
+
content: children,
|
|
130
|
+
});
|
|
131
|
+
const [leaving, setLeaving] = useState([]);
|
|
132
|
+
if (shown.key !== swapKey) {
|
|
133
|
+
setLeaving([
|
|
134
|
+
...leaving.filter((layer) => layer.key !== swapKey && layer.key !== shown.key),
|
|
135
|
+
shown,
|
|
136
|
+
]);
|
|
137
|
+
setShown({ key: swapKey, content: children });
|
|
138
|
+
}
|
|
139
|
+
else if (shown.content !== children) {
|
|
140
|
+
setShown({ key: swapKey, content: children });
|
|
141
|
+
}
|
|
142
|
+
const size = useRef(null);
|
|
143
|
+
useLayoutEffect(() => {
|
|
144
|
+
const element = node.current;
|
|
145
|
+
if (!element || !("ResizeObserver" in globalThis))
|
|
146
|
+
return;
|
|
147
|
+
size.current = element.getBoundingClientRect();
|
|
148
|
+
const observer = new ResizeObserver(() => {
|
|
149
|
+
if (element.getAnimations().length === 0)
|
|
150
|
+
size.current = element.getBoundingClientRect();
|
|
151
|
+
});
|
|
152
|
+
observer.observe(element);
|
|
153
|
+
return () => {
|
|
154
|
+
observer.disconnect();
|
|
155
|
+
};
|
|
156
|
+
}, []);
|
|
157
|
+
useLayoutEffect(() => {
|
|
158
|
+
const element = node.current;
|
|
159
|
+
if (!element)
|
|
160
|
+
return;
|
|
161
|
+
const exits = [
|
|
162
|
+
...element.querySelectorAll(":scope > [data-swap-leaving]"),
|
|
163
|
+
];
|
|
164
|
+
const entering = element.querySelector(":scope > [data-swap-current]");
|
|
165
|
+
if (entering === null || exits.length === 0)
|
|
166
|
+
return;
|
|
167
|
+
if (!canAnimate(element)) {
|
|
168
|
+
setLeaving([]);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const before = size.current;
|
|
172
|
+
const after = element.getBoundingClientRect();
|
|
173
|
+
const motion = readMotion(element);
|
|
174
|
+
const animations = [
|
|
175
|
+
entering.animate([
|
|
176
|
+
{
|
|
177
|
+
opacity: 0,
|
|
178
|
+
filter: `blur(${String(motion.blur)}px)`,
|
|
179
|
+
transform: `translateY(${String(motion.distance / 2)}px)`,
|
|
180
|
+
},
|
|
181
|
+
{ opacity: 1, filter: "blur(0px)", transform: "none" },
|
|
182
|
+
], {
|
|
183
|
+
duration: motion.normal,
|
|
184
|
+
easing: motionEasing(motion, motion.ease),
|
|
185
|
+
}),
|
|
186
|
+
];
|
|
187
|
+
for (const layer of exits) {
|
|
188
|
+
const exit = layer.animate([
|
|
189
|
+
{ opacity: 1, filter: "blur(0px)", transform: "none" },
|
|
190
|
+
{
|
|
191
|
+
opacity: 0,
|
|
192
|
+
filter: `blur(${String(motion.blur)}px)`,
|
|
193
|
+
transform: `translateY(${String(-motion.distance / 2)}px)`,
|
|
194
|
+
},
|
|
195
|
+
], {
|
|
196
|
+
duration: motion.fast,
|
|
197
|
+
easing: motionEasing(motion, motion.easeExit),
|
|
198
|
+
fill: "forwards",
|
|
199
|
+
});
|
|
200
|
+
const key = layer.dataset.swapLeaving;
|
|
201
|
+
exit.onfinish = () => {
|
|
202
|
+
setLeaving((layers) => layers.filter((layer) => layer.key !== key));
|
|
203
|
+
};
|
|
204
|
+
animations.push(exit);
|
|
205
|
+
}
|
|
206
|
+
const resized = before !== null &&
|
|
207
|
+
(Math.abs(before.height - after.height) > 0.5 ||
|
|
208
|
+
Math.abs(before.width - after.width) > 0.5);
|
|
209
|
+
if (!reduced && resized)
|
|
210
|
+
animations.push(element.animate([
|
|
211
|
+
{
|
|
212
|
+
width: `${String(before.width)}px`,
|
|
213
|
+
height: `${String(before.height)}px`,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
width: `${String(after.width)}px`,
|
|
217
|
+
height: `${String(after.height)}px`,
|
|
218
|
+
},
|
|
219
|
+
], {
|
|
220
|
+
duration: motion.normal,
|
|
221
|
+
easing: motionEasing(motion, motion.ease),
|
|
222
|
+
}));
|
|
223
|
+
return () => {
|
|
224
|
+
for (const animation of animations)
|
|
225
|
+
animation.cancel();
|
|
226
|
+
};
|
|
227
|
+
}, [swapKey, reduced]);
|
|
228
|
+
return (_jsx("div", { ...props, ref: node, className: cn("caps-swap", className), "data-anchor": anchor, children: [
|
|
229
|
+
...leaving.map((layer) => (_jsx("div", { className: "caps-swap-layer", "data-swap-leaving": layer.key, "aria-hidden": "true", children: layer.content }, layer.key))),
|
|
230
|
+
_jsx("div", { className: "caps-swap-layer", "data-swap-current": "", children: children }, swapKey),
|
|
231
|
+
] }));
|
|
232
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** The caller-provided price shown on a store entry. */
|
|
2
|
+
export type PriceTagProps = Readonly<{
|
|
3
|
+
price: {
|
|
4
|
+
kind: "free";
|
|
5
|
+
} | {
|
|
6
|
+
kind: "one-time";
|
|
7
|
+
label: string;
|
|
8
|
+
};
|
|
9
|
+
}>;
|
|
10
|
+
/** A compact, theme-backed price label for store entries. */
|
|
11
|
+
export declare function PriceTag({ price }: PriceTagProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Badge } from "./badge.js";
|
|
3
|
+
/** A compact, theme-backed price label for store entries. */
|
|
4
|
+
export function PriceTag({ price }) {
|
|
5
|
+
return (_jsx(Badge, { tone: "success", variant: "quiet", children: price.kind === "free" ? ("Free") : (_jsx("span", { className: "caps-numeric", children: price.label })) }));
|
|
6
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ProgressHTMLAttributes } from "react";
|
|
2
|
+
/** Supported ProgressTone values. */
|
|
3
|
+
export type ProgressTone = "neutral" | "primary" | "secondary" | "accent" | "success" | "info" | "warning" | "error";
|
|
4
|
+
/** Props accepted by Progress. */
|
|
5
|
+
export type ProgressProps = {
|
|
6
|
+
tone?: ProgressTone;
|
|
7
|
+
} & ProgressHTMLAttributes<HTMLProgressElement>;
|
|
8
|
+
/** A progress indicator for caller-provided progress values. */
|
|
9
|
+
export declare const Progress: import("react").ForwardRefExoticComponent<{
|
|
10
|
+
tone?: ProgressTone;
|
|
11
|
+
} & ProgressHTMLAttributes<HTMLProgressElement> & import("react").RefAttributes<HTMLProgressElement>>;
|
|
12
|
+
/** A compact labelled resource meter for game windows. Values come from the game. */
|
|
13
|
+
export type GameMeterProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
14
|
+
label: string;
|
|
15
|
+
value: number;
|
|
16
|
+
max: number;
|
|
17
|
+
tone?: ProgressTone;
|
|
18
|
+
};
|
|
19
|
+
/** Pair a game's bounded resource value with its visible and accessible meter. */
|
|
20
|
+
export declare const GameMeter: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
21
|
+
label: string;
|
|
22
|
+
value: number;
|
|
23
|
+
max: number;
|
|
24
|
+
tone?: ProgressTone;
|
|
25
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, } from "react";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
const progressToneClasses = {
|
|
5
|
+
neutral: "progress-neutral",
|
|
6
|
+
primary: "progress-primary",
|
|
7
|
+
secondary: "progress-secondary",
|
|
8
|
+
accent: "progress-accent",
|
|
9
|
+
success: "progress-success",
|
|
10
|
+
info: "progress-info",
|
|
11
|
+
warning: "progress-warning",
|
|
12
|
+
error: "progress-error",
|
|
13
|
+
};
|
|
14
|
+
/** A progress indicator for caller-provided progress values. */
|
|
15
|
+
export const Progress = forwardRef(function Progress({ className, tone = "primary", ...props }, ref) {
|
|
16
|
+
return (_jsx("progress", { ...props, "data-complete": props.value !== undefined &&
|
|
17
|
+
Number(props.value) >= Number(props.max ?? 1)
|
|
18
|
+
? "true"
|
|
19
|
+
: undefined, className: cn("progress caps-gooey-motion caps-gooey-progress w-full", progressToneClasses[tone], className), ref: ref }));
|
|
20
|
+
});
|
|
21
|
+
/** Pair a game's bounded resource value with its visible and accessible meter. */
|
|
22
|
+
export const GameMeter = forwardRef(function GameMeter({ label, value, max, tone = "info", className, ...props }, ref) {
|
|
23
|
+
return (_jsxs("div", { ...props, ref: ref, className: cn("caps-game-meter", className), children: [_jsxs("div", { className: "caps-game-meter-readout", children: [_jsx("span", { children: label }), _jsxs("span", { className: "caps-game-meter-value", children: [value, " / ", max] })] }), _jsx(Progress, { "aria-label": label, value: value, max: max, tone: tone })] }));
|
|
24
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type HTMLAttributes } from "react";
|
|
2
|
+
/** Supported Prose treatments. */
|
|
3
|
+
export type ProseVariant = "default" | "dropcap";
|
|
4
|
+
/** Props accepted by Prose. */
|
|
5
|
+
export type ProseProps = {
|
|
6
|
+
variant?: ProseVariant;
|
|
7
|
+
} & HTMLAttributes<HTMLElement>;
|
|
8
|
+
/**
|
|
9
|
+
* Tailwind Typography's `prose` rhythm and measure in the active theme's
|
|
10
|
+
* colours and faces; the caller supplies the document content.
|
|
11
|
+
*/
|
|
12
|
+
export declare const Prose: import("react").ForwardRefExoticComponent<{
|
|
13
|
+
variant?: ProseVariant;
|
|
14
|
+
} & HTMLAttributes<HTMLElement> & import("react").RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
/**
|
|
5
|
+
* Tailwind Typography's `prose` rhythm and measure in the active theme's
|
|
6
|
+
* colours and faces; the caller supplies the document content.
|
|
7
|
+
*/
|
|
8
|
+
export const Prose = forwardRef(function Prose({ className, variant = "default", ...props }, ref) {
|
|
9
|
+
return (_jsx("article", { ...props, className: cn("prose prose-caps", variant === "dropcap" && "caps-prose-dropcap", className), ref: ref }));
|
|
10
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactNode } from "react";
|
|
2
|
+
import { type ProgressTone } from "./progress.js";
|
|
3
|
+
/** Props accepted by QuotaMeter. */
|
|
4
|
+
export type QuotaMeterProps = {
|
|
5
|
+
label: ReactNode;
|
|
6
|
+
value: number;
|
|
7
|
+
max: number;
|
|
8
|
+
valueLabel?: ReactNode;
|
|
9
|
+
maxLabel?: ReactNode;
|
|
10
|
+
description?: ReactNode;
|
|
11
|
+
indicator?: ReactNode;
|
|
12
|
+
tone?: ProgressTone;
|
|
13
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "children">;
|
|
14
|
+
/** A meter presentation for caller-provided quota values. */
|
|
15
|
+
export declare const QuotaMeter: import("react").ForwardRefExoticComponent<{
|
|
16
|
+
label: ReactNode;
|
|
17
|
+
value: number;
|
|
18
|
+
max: number;
|
|
19
|
+
valueLabel?: ReactNode;
|
|
20
|
+
maxLabel?: ReactNode;
|
|
21
|
+
description?: ReactNode;
|
|
22
|
+
indicator?: ReactNode;
|
|
23
|
+
tone?: ProgressTone;
|
|
24
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "children"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useId } from "react";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
import { Progress } from "./progress.js";
|
|
5
|
+
/** A meter presentation for caller-provided quota values. */
|
|
6
|
+
export const QuotaMeter = forwardRef(function QuotaMeter({ className, label, value, max, valueLabel, maxLabel, description, indicator, tone, ...props }, ref) {
|
|
7
|
+
const id = useId();
|
|
8
|
+
const labelId = `${id}-label`;
|
|
9
|
+
const descriptionId = `${id}-description`;
|
|
10
|
+
return (_jsxs("div", { ...props, className: cn("space-y-sm", className), ref: ref, children: [_jsxs("div", { className: "flex items-center justify-between gap-sm", children: [_jsxs("div", { className: "flex items-center gap-sm", children: [_jsx("div", { className: "font-medium", id: labelId, children: label }), indicator !== undefined ? _jsx("div", { children: indicator }) : null] }), _jsxs("div", { className: "caps-numeric", children: [valueLabel ?? value, " / ", maxLabel ?? max] })] }), _jsx(Progress, { "aria-describedby": description !== undefined ? descriptionId : undefined, "aria-labelledby": labelId, max: max, ...(tone === undefined ? {} : { tone }), value: value }), description !== undefined ? (_jsx("p", { className: "text-sm text-base-content", id: descriptionId, children: description })) : null] }));
|
|
11
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMotion } from "../lib/motion.js";
|
|
3
|
+
import { animate } from "animejs";
|
|
4
|
+
import { themedEase, themedSpring } from "../lib/motion-spring.js";
|
|
5
|
+
import { useId, useLayoutEffect, useRef } from "react";
|
|
6
|
+
import { GooeyInsetDefinition, GooeyShadowDefinition, GooeySurfaceDefinition, } from "./gooey.js";
|
|
7
|
+
/** @internal A selected bead emerging from a recessed radio well. */
|
|
8
|
+
export function RadioBead({ checked }) {
|
|
9
|
+
const id = `caps-radio-${useId().replaceAll(":", "")}`;
|
|
10
|
+
const body = useRef(null);
|
|
11
|
+
const initial = useRef(checked).current;
|
|
12
|
+
const previous = useRef(checked);
|
|
13
|
+
const root = useRef(null);
|
|
14
|
+
const motion = useMotion(root);
|
|
15
|
+
const { reduced } = motion;
|
|
16
|
+
useLayoutEffect(() => {
|
|
17
|
+
if (!body.current)
|
|
18
|
+
return;
|
|
19
|
+
const immediate = reduced || previous.current === checked;
|
|
20
|
+
previous.current = checked;
|
|
21
|
+
const radius = checked ? 4 : 0;
|
|
22
|
+
// The radio's own lively settle, in the theme's feel.
|
|
23
|
+
const press = themedEase(motion, { ease: "outCubic", duration: 75 });
|
|
24
|
+
const settle = checked
|
|
25
|
+
? themedSpring(motion, { bounce: 0.65, duration: 300 })
|
|
26
|
+
: themedEase(motion, { ease: "inCubic", duration: 100 });
|
|
27
|
+
const bead = animate(body.current, immediate
|
|
28
|
+
? {
|
|
29
|
+
rx: radius,
|
|
30
|
+
ry: radius,
|
|
31
|
+
cy: 6,
|
|
32
|
+
duration: 0,
|
|
33
|
+
}
|
|
34
|
+
: {
|
|
35
|
+
rx: [
|
|
36
|
+
{ to: checked ? 3.5 : 4.15, ...press },
|
|
37
|
+
{ to: radius, ...settle },
|
|
38
|
+
],
|
|
39
|
+
ry: [
|
|
40
|
+
{ to: checked ? 4.5 : 3.85, ...press },
|
|
41
|
+
{ to: radius, ...settle },
|
|
42
|
+
],
|
|
43
|
+
cy: [
|
|
44
|
+
{ to: checked ? 5.85 : 6.1, ...press },
|
|
45
|
+
{ to: 6, ...settle },
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
return () => {
|
|
49
|
+
bead.cancel();
|
|
50
|
+
};
|
|
51
|
+
}, [checked, reduced, motion]);
|
|
52
|
+
return (_jsxs("svg", { ref: root, className: "caps-radio-visual", width: "24", height: "24", viewBox: "0 0 12 12", "aria-hidden": "true", focusable: "false", children: [_jsxs("defs", { children: [_jsx(GooeySurfaceDefinition, { id: `${id}-surface`, transform: "matrix(1 0 0 1 6 6)" }), _jsx(GooeyShadowDefinition, { id: `${id}-shadow` }), _jsx(GooeyInsetDefinition, { id: `${id}-inset` }), _jsx("clipPath", { id: `${id}-well`, children: _jsx("circle", { cx: "6", cy: "6", r: "5" }) })] }), _jsx("circle", { className: "caps-radio-track", cx: "6", cy: "6", r: "5.5", filter: `url(#${id}-inset)` }), _jsx("g", { clipPath: `url(#${id}-well)`, children: _jsx("ellipse", { ref: body, cx: "6", cy: "6", rx: initial ? 4 : 0, ry: initial ? 4 : 0, fill: `url(#${id}-surface)`, filter: `url(#${id}-shadow)` }) })] }));
|
|
53
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type FieldsetHTMLAttributes, type InputHTMLAttributes, type ReactNode } from "react";
|
|
2
|
+
/** Props accepted by RadioGroup. */
|
|
3
|
+
export type RadioGroupProps = {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
defaultValue?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
/** Called after the selected radio value changes. */
|
|
8
|
+
onValueChange?: (value: string) => void;
|
|
9
|
+
orientation?: "horizontal" | "vertical";
|
|
10
|
+
value?: string;
|
|
11
|
+
} & Omit<FieldsetHTMLAttributes<HTMLFieldSetElement>, "defaultValue" | "onChange">;
|
|
12
|
+
/** A radio-group primitive with caller-owned selection state. */
|
|
13
|
+
export declare const RadioGroup: import("react").ForwardRefExoticComponent<{
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
defaultValue?: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
/** Called after the selected radio value changes. */
|
|
18
|
+
onValueChange?: (value: string) => void;
|
|
19
|
+
orientation?: "horizontal" | "vertical";
|
|
20
|
+
value?: string;
|
|
21
|
+
} & Omit<FieldsetHTMLAttributes<HTMLFieldSetElement>, "defaultValue" | "onChange"> & import("react").RefAttributes<HTMLFieldSetElement>>;
|
|
22
|
+
/** Props accepted by RadioGroupItem. */
|
|
23
|
+
export type RadioGroupItemProps = {
|
|
24
|
+
value: string;
|
|
25
|
+
/** Replaces the bead while the native input continues to own selection. */
|
|
26
|
+
indicator?: ReactNode;
|
|
27
|
+
} & Omit<InputHTMLAttributes<HTMLInputElement>, "checked" | "defaultChecked" | "name" | "type" | "value">;
|
|
28
|
+
/** A selectable item in a RadioGroup. */
|
|
29
|
+
export declare const RadioGroupItem: import("react").ForwardRefExoticComponent<{
|
|
30
|
+
value: string;
|
|
31
|
+
/** Replaces the bead while the native input continues to own selection. */
|
|
32
|
+
indicator?: ReactNode;
|
|
33
|
+
} & Omit<InputHTMLAttributes<HTMLInputElement>, "name" | "defaultChecked" | "type" | "value" | "checked"> & import("react").RefAttributes<HTMLInputElement>>;
|
|
34
|
+
/** Props accepted by RadioGroupCard. */
|
|
35
|
+
export type RadioGroupCardProps = {
|
|
36
|
+
title: ReactNode;
|
|
37
|
+
description?: ReactNode;
|
|
38
|
+
/** A short readout on the card's trailing edge, such as a price or size. */
|
|
39
|
+
meta?: ReactNode;
|
|
40
|
+
} & RadioGroupItemProps;
|
|
41
|
+
/**
|
|
42
|
+
* A radio choice presented as a card: bead, title, optional description and a
|
|
43
|
+
* trailing readout. The whole card is the hit area; the title names it.
|
|
44
|
+
*/
|
|
45
|
+
export declare const RadioGroupCard: import("react").ForwardRefExoticComponent<{
|
|
46
|
+
title: ReactNode;
|
|
47
|
+
description?: ReactNode;
|
|
48
|
+
/** A short readout on the card's trailing edge, such as a price or size. */
|
|
49
|
+
meta?: ReactNode;
|
|
50
|
+
} & {
|
|
51
|
+
value: string;
|
|
52
|
+
/** Replaces the bead while the native input continues to own selection. */
|
|
53
|
+
indicator?: ReactNode;
|
|
54
|
+
} & Omit<InputHTMLAttributes<HTMLInputElement>, "name" | "defaultChecked" | "type" | "value" | "checked"> & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, forwardRef, useContext, useId, useEffect, useImperativeHandle, useRef, useState, } from "react";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
import { RadioBead } from "./radio-bead.js";
|
|
5
|
+
const RadioGroupContext = createContext(null);
|
|
6
|
+
/** A radio-group primitive with caller-owned selection state. */
|
|
7
|
+
export const RadioGroup = forwardRef(function RadioGroup({ children, className, defaultValue, disabled = false, name: providedName, onValueChange, orientation = "vertical", value: controlledValue, ...props }, ref) {
|
|
8
|
+
const generatedName = useId();
|
|
9
|
+
const fieldset = useRef(null);
|
|
10
|
+
useImperativeHandle(ref, () => {
|
|
11
|
+
if (!fieldset.current)
|
|
12
|
+
throw new Error("RadioGroup is not mounted");
|
|
13
|
+
return fieldset.current;
|
|
14
|
+
}, []);
|
|
15
|
+
const name = providedName ?? `radio-group-${generatedName}`;
|
|
16
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
17
|
+
const value = controlledValue ?? uncontrolledValue;
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const form = fieldset.current?.form;
|
|
20
|
+
if (!form || controlledValue !== undefined)
|
|
21
|
+
return;
|
|
22
|
+
const reset = (event) => {
|
|
23
|
+
queueMicrotask(() => {
|
|
24
|
+
if (!event.defaultPrevented)
|
|
25
|
+
setUncontrolledValue(defaultValue);
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
form.addEventListener("reset", reset);
|
|
29
|
+
return () => {
|
|
30
|
+
form.removeEventListener("reset", reset);
|
|
31
|
+
};
|
|
32
|
+
}, [controlledValue, defaultValue, props.form]);
|
|
33
|
+
const handleChange = (next) => {
|
|
34
|
+
if (controlledValue === undefined)
|
|
35
|
+
setUncontrolledValue(next);
|
|
36
|
+
onValueChange?.(next);
|
|
37
|
+
};
|
|
38
|
+
return (_jsx(RadioGroupContext.Provider, { value: { disabled, name, onValueChange: handleChange, value }, children: _jsx("fieldset", { ...props, className: cn("flex gap-md", orientation === "horizontal" ? "flex-row flex-wrap" : "flex-col", className), disabled: disabled, role: props.role ?? "radiogroup", ref: fieldset, children: children }) }));
|
|
39
|
+
});
|
|
40
|
+
/** A selectable item in a RadioGroup. */
|
|
41
|
+
export const RadioGroupItem = forwardRef(function RadioGroupItem({ className, indicator, onChange, onClick, value: itemValue, ...props }, ref) {
|
|
42
|
+
const context = useContext(RadioGroupContext);
|
|
43
|
+
if (!context)
|
|
44
|
+
throw new Error("RadioGroupItem must be used inside <RadioGroup>");
|
|
45
|
+
const checked = context.value === itemValue;
|
|
46
|
+
const handleChange = (event) => {
|
|
47
|
+
onChange?.(event);
|
|
48
|
+
if (event.target.checked)
|
|
49
|
+
context.onValueChange?.(itemValue);
|
|
50
|
+
};
|
|
51
|
+
return (_jsxs("span", { className: "caps-radio", "data-checked": checked, "data-custom-indicator": indicator !== undefined || undefined, children: [_jsx("input", { ...props, "aria-checked": checked, checked: checked, className: cn("caps-radio-input", className), disabled: context.disabled || props.disabled, name: context.name, onChange: handleChange, onClick: onClick, ref: ref, type: "radio", value: itemValue }), indicator !== undefined ? indicator : _jsx(RadioBead, { checked: checked })] }));
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* A radio choice presented as a card: bead, title, optional description and a
|
|
55
|
+
* trailing readout. The whole card is the hit area; the title names it.
|
|
56
|
+
*/
|
|
57
|
+
export const RadioGroupCard = forwardRef(function RadioGroupCard({ description, id, meta, title, ...props }, ref) {
|
|
58
|
+
const context = useContext(RadioGroupContext);
|
|
59
|
+
const generatedId = useId();
|
|
60
|
+
const inputId = id ?? generatedId;
|
|
61
|
+
const checked = context?.value === props.value;
|
|
62
|
+
const disabled = context?.disabled === true || props.disabled === true;
|
|
63
|
+
return (_jsxs("label", { className: "caps-choice-card", "data-checked": checked, "data-disabled": disabled || undefined, htmlFor: inputId, children: [_jsx(RadioGroupItem, { ...props, "aria-describedby": description ? `${inputId}-description` : undefined, "aria-labelledby": `${inputId}-title`, id: inputId, ref: ref }), _jsxs("span", { className: "caps-choice-card-copy", children: [_jsx("span", { className: "caps-choice-card-title", id: `${inputId}-title`, children: title }), description ? (_jsx("span", { className: "caps-choice-card-description", id: `${inputId}-description`, children: description })) : null] }), meta ? _jsx("span", { className: "caps-choice-card-meta", children: meta }) : null] }));
|
|
64
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type HTMLAttributes } from "react";
|
|
2
|
+
/** Accessible grip presentation with caller-owned resize state and pointer gesture. */
|
|
3
|
+
export type ResizeHandleProps = Omit<HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
4
|
+
"aria-label": string;
|
|
5
|
+
orientation: "horizontal" | "vertical";
|
|
6
|
+
variant?: "grip" | "notch";
|
|
7
|
+
value: number;
|
|
8
|
+
min: number;
|
|
9
|
+
max: number;
|
|
10
|
+
/** Receives a clamped pixel position from keyboard controls. */
|
|
11
|
+
onValueChange: (value: number) => void;
|
|
12
|
+
};
|
|
13
|
+
/** Visual and keyboard surface for a caller-owned resize gesture. */
|
|
14
|
+
export declare const ResizeHandle: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
15
|
+
"aria-label": string;
|
|
16
|
+
orientation: "horizontal" | "vertical";
|
|
17
|
+
variant?: "grip" | "notch";
|
|
18
|
+
value: number;
|
|
19
|
+
min: number;
|
|
20
|
+
max: number;
|
|
21
|
+
/** Receives a clamped pixel position from keyboard controls. */
|
|
22
|
+
onValueChange: (value: number) => void;
|
|
23
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
/** Visual and keyboard surface for a caller-owned resize gesture. */
|
|
5
|
+
export const ResizeHandle = forwardRef(function ResizeHandle({ className, orientation, variant = "grip", value, min, max, onValueChange, onKeyDown, ...props }, ref) {
|
|
6
|
+
return (_jsx("div", { ...props, ref: ref, className: cn("caps-resize-handle", className), "data-resize-variant": variant, role: "separator", "aria-orientation": orientation, "aria-valuemin": Math.round(min), "aria-valuemax": Math.round(max), "aria-valuenow": Math.round(value), tabIndex: props.tabIndex ?? 0, onKeyDown: (event) => {
|
|
7
|
+
onKeyDown?.(event);
|
|
8
|
+
if (event.defaultPrevented)
|
|
9
|
+
return;
|
|
10
|
+
if (event.key === "Home" || event.key === "End") {
|
|
11
|
+
event.preventDefault();
|
|
12
|
+
onValueChange(event.key === "Home" ? min : max);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const step = orientation === "horizontal"
|
|
16
|
+
? event.key === "ArrowUp"
|
|
17
|
+
? -32
|
|
18
|
+
: event.key === "ArrowDown"
|
|
19
|
+
? 32
|
|
20
|
+
: null
|
|
21
|
+
: event.key === "ArrowLeft"
|
|
22
|
+
? -32
|
|
23
|
+
: event.key === "ArrowRight"
|
|
24
|
+
? 32
|
|
25
|
+
: null;
|
|
26
|
+
if (step === null)
|
|
27
|
+
return;
|
|
28
|
+
event.preventDefault();
|
|
29
|
+
onValueChange(Math.min(max, Math.max(min, value + step)));
|
|
30
|
+
}, children: _jsx("span", { className: "caps-resize-grip", "aria-hidden": "true" }) }));
|
|
31
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hand-drawn Rough.js chrome for any element marked `data-caps-rough`: boxes,
|
|
3
|
+
* underlines, circles, highlights, speech bubbles and leader lines drawn in the
|
|
4
|
+
* theme's ink or primary. The {@link Rough} component writes that markup; pages
|
|
5
|
+
* without React call {@link drawRough} once. Until Rough.js has drawn an
|
|
6
|
+
* element (or without JavaScript), plain CSS in `styles.css` stands in for it.
|
|
7
|
+
*
|
|
8
|
+
* Each element keeps its seed, so a redraw after a resize bends the same way.
|
|
9
|
+
*/
|
|
10
|
+
/** A hand-drawn mark around, under or behind an element. */
|
|
11
|
+
export type RoughMark = "box" | "underline" | "circle" | "highlight" | "bubble" | "line";
|
|
12
|
+
/** Theme ink (`currentColor` by default) or the theme's primary accent. */
|
|
13
|
+
export type RoughTone = "ink" | "primary";
|
|
14
|
+
/** Parsed `data-rough-*` settings for one element. */
|
|
15
|
+
export type RoughSpec = Readonly<{
|
|
16
|
+
mark: RoughMark;
|
|
17
|
+
seed: number;
|
|
18
|
+
/** Stroke width in CSS pixels. */
|
|
19
|
+
weight: number;
|
|
20
|
+
/** Rough.js roughness; 0 is a ruler, 3 is a scribble. */
|
|
21
|
+
roughness: number;
|
|
22
|
+
/** Fill inside a box, circle or bubble: flat, or screentone-like hachure. */
|
|
23
|
+
fill: "none" | "solid" | "hachure";
|
|
24
|
+
/** For `bubble`: which lower corner the tail leaves from. */
|
|
25
|
+
tail: "left" | "right" | "none";
|
|
26
|
+
/**
|
|
27
|
+
* For `line`: points in percent of the element's box, such as
|
|
28
|
+
* `0,100 40,20 100,0`. Two points draw a straight stroke; more draw a curve.
|
|
29
|
+
*/
|
|
30
|
+
points: readonly (readonly [number, number])[];
|
|
31
|
+
}>;
|
|
32
|
+
/** Read `0,100 40,20 100,0` as percent points, dropping malformed pairs. */
|
|
33
|
+
export declare function parseRoughPoints(value: string | undefined): readonly (readonly [number, number])[];
|
|
34
|
+
/** Parse an element's `data-caps-rough` and `data-rough-*` attributes. */
|
|
35
|
+
export declare function readRoughSpec(element: HTMLElement): RoughSpec | null;
|
|
36
|
+
/**
|
|
37
|
+
* Draw every `[data-caps-rough]` element inside `root` (and `root` itself),
|
|
38
|
+
* loading Rough.js on first use, and redraw each one when its size changes.
|
|
39
|
+
* Returns a function that stops watching sizes. If Rough.js cannot load, the
|
|
40
|
+
* CSS fallback stays.
|
|
41
|
+
*/
|
|
42
|
+
export declare function drawRough(root?: ParentNode): () => void;
|