@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,177 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { animate } from "animejs";
|
|
3
|
+
import { useId, useLayoutEffect, useRef } from "react";
|
|
4
|
+
import { readMotion, useReducedMotion } from "../lib/motion.js";
|
|
5
|
+
import { immediateTiming, themedEase, themedSpring, } from "../lib/motion-spring.js";
|
|
6
|
+
import { GooeySurfaceDefinition } from "./gooey.js";
|
|
7
|
+
import { observeMotionVisibility } from "./motion-visibility.js";
|
|
8
|
+
/** An indeterminate arc covers this much of the ring while it spins. */
|
|
9
|
+
const spinnerSweep = 0.28;
|
|
10
|
+
function poseFor(glyph, progress) {
|
|
11
|
+
switch (glyph) {
|
|
12
|
+
case "ring":
|
|
13
|
+
return {
|
|
14
|
+
dashes: 1,
|
|
15
|
+
track: 0,
|
|
16
|
+
arc: 0,
|
|
17
|
+
sweep: 0,
|
|
18
|
+
disc: 0,
|
|
19
|
+
tick: 0,
|
|
20
|
+
cross: 0,
|
|
21
|
+
};
|
|
22
|
+
case "arc":
|
|
23
|
+
return {
|
|
24
|
+
dashes: 0,
|
|
25
|
+
track: 1,
|
|
26
|
+
arc: 1,
|
|
27
|
+
sweep: progress === undefined
|
|
28
|
+
? spinnerSweep
|
|
29
|
+
: Math.min(1, Math.max(0, progress)),
|
|
30
|
+
disc: 0,
|
|
31
|
+
tick: 0,
|
|
32
|
+
cross: 0,
|
|
33
|
+
};
|
|
34
|
+
case "check":
|
|
35
|
+
return {
|
|
36
|
+
dashes: 0,
|
|
37
|
+
track: 0,
|
|
38
|
+
arc: 1,
|
|
39
|
+
sweep: 1,
|
|
40
|
+
disc: 1,
|
|
41
|
+
tick: 1,
|
|
42
|
+
cross: 0,
|
|
43
|
+
};
|
|
44
|
+
case "cross":
|
|
45
|
+
return {
|
|
46
|
+
dashes: 0,
|
|
47
|
+
track: 0,
|
|
48
|
+
arc: 1,
|
|
49
|
+
sweep: 1,
|
|
50
|
+
disc: 1,
|
|
51
|
+
tick: 0,
|
|
52
|
+
cross: 1,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** The disc's radius when full, just covering the ring. */
|
|
57
|
+
const discRadius = 7.25;
|
|
58
|
+
/**
|
|
59
|
+
* @internal A 16-unit task mark. A dashed ring waits; an arc works (spinning,
|
|
60
|
+
* or filling to `progress`); when done the arc closes, the bead's material
|
|
61
|
+
* springs out to a disc and a check (or cross) is drawn out of it.
|
|
62
|
+
*/
|
|
63
|
+
export function StatusMark({ className, glyph, progress, }) {
|
|
64
|
+
const id = `caps-status-mark-${useId().replaceAll(":", "")}`;
|
|
65
|
+
const visual = useRef(null);
|
|
66
|
+
const dashes = useRef(null);
|
|
67
|
+
const track = useRef(null);
|
|
68
|
+
const arc = useRef(null);
|
|
69
|
+
const spin = useRef(null);
|
|
70
|
+
const disc = useRef(null);
|
|
71
|
+
const tick = useRef(null);
|
|
72
|
+
const cross = useRef(null);
|
|
73
|
+
const initial = useRef(poseFor(glyph, progress)).current;
|
|
74
|
+
const previous = useRef(glyph);
|
|
75
|
+
const reduced = useReducedMotion();
|
|
76
|
+
useLayoutEffect(() => {
|
|
77
|
+
const svg = visual.current;
|
|
78
|
+
const dashRing = dashes.current;
|
|
79
|
+
const trackRing = track.current;
|
|
80
|
+
const arcRing = arc.current;
|
|
81
|
+
const bead = disc.current;
|
|
82
|
+
const tickPath = tick.current;
|
|
83
|
+
const crossPath = cross.current;
|
|
84
|
+
if (!svg ||
|
|
85
|
+
!dashRing ||
|
|
86
|
+
!trackRing ||
|
|
87
|
+
!arcRing ||
|
|
88
|
+
!bead ||
|
|
89
|
+
!tickPath ||
|
|
90
|
+
!crossPath)
|
|
91
|
+
return;
|
|
92
|
+
const pose = poseFor(glyph, progress);
|
|
93
|
+
const from = previous.current;
|
|
94
|
+
previous.current = glyph;
|
|
95
|
+
const motion = readMotion(svg);
|
|
96
|
+
const still = reduced || (from === glyph && glyph !== "arc");
|
|
97
|
+
const fade = still
|
|
98
|
+
? reduced
|
|
99
|
+
? { ease: motion.ease, duration: motion.fast }
|
|
100
|
+
: immediateTiming
|
|
101
|
+
: themedEase(motion, { ease: "outQuad", duration: 160 });
|
|
102
|
+
const finishing = (glyph === "check" || glyph === "cross") && !still;
|
|
103
|
+
// The arc closes first, then the disc springs out, then the mark draws.
|
|
104
|
+
const close = themedEase(motion, { ease: "inOutSine", duration: 220 });
|
|
105
|
+
const animations = [
|
|
106
|
+
animate(dashRing, { opacity: pose.dashes, ...fade }),
|
|
107
|
+
animate(trackRing, { opacity: pose.track * 0.28, ...fade }),
|
|
108
|
+
animate(arcRing, {
|
|
109
|
+
opacity: pose.arc,
|
|
110
|
+
"stroke-dasharray": `${String(pose.sweep)} 1`,
|
|
111
|
+
...(still ? (reduced ? immediateTiming : fade) : close),
|
|
112
|
+
}),
|
|
113
|
+
animate(bead, {
|
|
114
|
+
r: pose.disc * discRadius,
|
|
115
|
+
...(finishing
|
|
116
|
+
? {
|
|
117
|
+
delay: close.duration * 0.7,
|
|
118
|
+
...themedSpring(motion, { bounce: 0.35, duration: 360 }),
|
|
119
|
+
}
|
|
120
|
+
: reduced
|
|
121
|
+
? immediateTiming
|
|
122
|
+
: themedEase(motion, { ease: "inCubic", duration: 140 })),
|
|
123
|
+
}),
|
|
124
|
+
animate(tickPath, {
|
|
125
|
+
"stroke-dashoffset": 1 - pose.tick,
|
|
126
|
+
...(finishing && pose.tick > 0
|
|
127
|
+
? {
|
|
128
|
+
delay: close.duration * 0.7 + motion.fast,
|
|
129
|
+
...themedEase(motion, { ease: "outCubic", duration: 240 }),
|
|
130
|
+
}
|
|
131
|
+
: immediateTiming),
|
|
132
|
+
}),
|
|
133
|
+
animate(crossPath, {
|
|
134
|
+
"stroke-dashoffset": 1 - pose.cross,
|
|
135
|
+
...(finishing && pose.cross > 0
|
|
136
|
+
? {
|
|
137
|
+
delay: close.duration * 0.7 + motion.fast,
|
|
138
|
+
...themedEase(motion, { ease: "outCubic", duration: 240 }),
|
|
139
|
+
}
|
|
140
|
+
: immediateTiming),
|
|
141
|
+
}),
|
|
142
|
+
];
|
|
143
|
+
if (glyph === "cross" && finishing && motion.shake > 0)
|
|
144
|
+
animations.push(animate(svg, {
|
|
145
|
+
translateX: [0, -motion.shake, motion.shake, -motion.shake / 2, 0],
|
|
146
|
+
delay: close.duration + motion.fast,
|
|
147
|
+
...themedEase(motion, { ease: "linear", duration: 300 }),
|
|
148
|
+
}));
|
|
149
|
+
return () => {
|
|
150
|
+
for (const animation of animations)
|
|
151
|
+
animation.cancel();
|
|
152
|
+
};
|
|
153
|
+
}, [glyph, progress, reduced]);
|
|
154
|
+
// An indeterminate arc turns while it is on screen; reduced motion holds it.
|
|
155
|
+
const spinning = glyph === "arc" && progress === undefined && !reduced;
|
|
156
|
+
useLayoutEffect(() => {
|
|
157
|
+
if (!spinning || !spin.current || !visual.current)
|
|
158
|
+
return;
|
|
159
|
+
const motion = readMotion(visual.current);
|
|
160
|
+
const loop = animate(spin.current, {
|
|
161
|
+
rotate: [0, 360],
|
|
162
|
+
...themedEase(motion, { ease: "linear", duration: 900 }),
|
|
163
|
+
loop: true,
|
|
164
|
+
});
|
|
165
|
+
const stopObserving = observeMotionVisibility(visual.current, (visible) => {
|
|
166
|
+
if (visible)
|
|
167
|
+
loop.resume();
|
|
168
|
+
else
|
|
169
|
+
loop.pause();
|
|
170
|
+
});
|
|
171
|
+
return () => {
|
|
172
|
+
stopObserving();
|
|
173
|
+
loop.revert();
|
|
174
|
+
};
|
|
175
|
+
}, [spinning]);
|
|
176
|
+
return (_jsxs("svg", { ref: visual, "aria-hidden": "true", className: `caps-status-mark ${className ?? ""}`, viewBox: "0 0 16 16", focusable: "false", children: [_jsxs("defs", { children: [_jsx(GooeySurfaceDefinition, { id: `${id}-surface`, transform: "matrix(1.6 0 0 1.6 8 8)" }), _jsxs("mask", { id: `${id}-knock`, maskUnits: "userSpaceOnUse", x: "0", y: "0", width: "16", height: "16", children: [_jsx("rect", { width: "16", height: "16", fill: "var(--color-white)" }), _jsx("path", { ref: tick, d: "M4.9 8.3 7.1 10.5 11.2 5.9", fill: "none", stroke: "var(--color-black)", strokeWidth: "1.9", strokeLinecap: "round", strokeLinejoin: "round", pathLength: 1, strokeDasharray: "1 1", strokeDashoffset: 1 - initial.tick }), _jsx("path", { ref: cross, d: "M5.4 5.4 10.6 10.6 M10.6 5.4 5.4 10.6", fill: "none", stroke: "var(--color-black)", strokeWidth: "1.9", strokeLinecap: "round", pathLength: 1, strokeDasharray: "1 1", strokeDashoffset: 1 - initial.cross })] })] }), _jsx("circle", { ref: dashes, cx: "8", cy: "8", r: "6.25", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeDasharray: "1.7 2.2", opacity: initial.dashes }), _jsx("circle", { ref: track, cx: "8", cy: "8", r: "6.25", fill: "none", stroke: "currentColor", strokeWidth: "1.5", opacity: initial.track * 0.28 }), _jsx("g", { ref: spin, className: "caps-status-mark-spin", children: _jsx("circle", { ref: arc, cx: "8", cy: "8", r: "6.25", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", pathLength: 1, strokeDasharray: `${String(initial.sweep)} 1`, transform: "rotate(-90 8 8)", opacity: initial.arc }) }), _jsx("circle", { ref: disc, cx: "8", cy: "8", r: initial.disc * discRadius, fill: `url(#${id}-surface)`, mask: `url(#${id}-knock)` })] }));
|
|
177
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactNode } from "react";
|
|
2
|
+
import { type StatusMarkGlyph } from "./status-mark.js";
|
|
3
|
+
/**
|
|
4
|
+
* The target silhouette. Bead glyphs (`dot`, `pill`, `bang`) morph between
|
|
5
|
+
* each other; task glyphs (`ring` waiting, `arc` working, `check` finished,
|
|
6
|
+
* `cross` refused) morph between each other.
|
|
7
|
+
*/
|
|
8
|
+
export type StatusGlyph = "dot" | "pill" | "bang" | StatusMarkGlyph;
|
|
9
|
+
/** Continuous activity, independent of the target silhouette. */
|
|
10
|
+
export type StatusMotion = "none" | "pulse" | "bounce";
|
|
11
|
+
/** Semantic colors supplied by the current Stipe theme. */
|
|
12
|
+
export type StatusTone = "neutral" | "primary" | "secondary" | "accent" | "success" | "info" | "warning" | "error";
|
|
13
|
+
/** Status size keeps secondary state compact in dense rows. */
|
|
14
|
+
export type StatusSize = "default" | "compact";
|
|
15
|
+
/** `chip` seats the bead and label in a tone-tinted pill. */
|
|
16
|
+
export type StatusAppearance = "plain" | "chip";
|
|
17
|
+
/** Presentation only: the caller maps its state to glyph, tone, and motion. */
|
|
18
|
+
export type StatusProps = {
|
|
19
|
+
label?: ReactNode;
|
|
20
|
+
glyph?: StatusGlyph;
|
|
21
|
+
motion?: StatusMotion;
|
|
22
|
+
tone?: StatusTone;
|
|
23
|
+
size?: StatusSize;
|
|
24
|
+
appearance?: StatusAppearance;
|
|
25
|
+
/** For `arc`: how much is done, 0 to 1. Absent, the arc spins. */
|
|
26
|
+
progress?: number | undefined;
|
|
27
|
+
} & Omit<HTMLAttributes<HTMLSpanElement>, "children">;
|
|
28
|
+
/** A gooey SVG status bead with automatic, interruptible glyph transitions. */
|
|
29
|
+
export declare const Status: import("react").ForwardRefExoticComponent<{
|
|
30
|
+
label?: ReactNode;
|
|
31
|
+
glyph?: StatusGlyph;
|
|
32
|
+
motion?: StatusMotion;
|
|
33
|
+
tone?: StatusTone;
|
|
34
|
+
size?: StatusSize;
|
|
35
|
+
appearance?: StatusAppearance;
|
|
36
|
+
/** For `arc`: how much is done, 0 to 1. Absent, the arc spins. */
|
|
37
|
+
progress?: number | undefined;
|
|
38
|
+
} & Omit<HTMLAttributes<HTMLSpanElement>, "children"> & import("react").RefAttributes<HTMLSpanElement>>;
|
|
@@ -0,0 +1,28 @@
|
|
|
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
|
+
import { StatusBead } from "./status-bead.js";
|
|
5
|
+
import { StatusMark } from "./status-mark.js";
|
|
6
|
+
const markGlyphs = new Set([
|
|
7
|
+
"ring",
|
|
8
|
+
"arc",
|
|
9
|
+
"check",
|
|
10
|
+
"cross",
|
|
11
|
+
]);
|
|
12
|
+
function isMarkGlyph(glyph) {
|
|
13
|
+
return markGlyphs.has(glyph);
|
|
14
|
+
}
|
|
15
|
+
const toneClasses = {
|
|
16
|
+
neutral: "text-base-content",
|
|
17
|
+
primary: "text-primary",
|
|
18
|
+
secondary: "text-secondary",
|
|
19
|
+
accent: "text-accent",
|
|
20
|
+
success: "text-success",
|
|
21
|
+
info: "text-info",
|
|
22
|
+
warning: "text-warning",
|
|
23
|
+
error: "text-error",
|
|
24
|
+
};
|
|
25
|
+
/** A gooey SVG status bead with automatic, interruptible glyph transitions. */
|
|
26
|
+
export const Status = forwardRef(function Status({ className, label, glyph = "dot", motion = "none", tone = "neutral", size = "default", appearance = "plain", progress, ...props }, ref) {
|
|
27
|
+
return (_jsxs("span", { ...props, className: cn("caps-status", size === "compact" && "caps-status-compact", appearance === "chip" && "caps-status-chip", className), "data-tone": appearance === "chip" ? tone : undefined, "data-glyph": glyph, "data-motion": motion, ref: ref, children: [isMarkGlyph(glyph) ? (_jsx(StatusMark, { className: toneClasses[tone], glyph: glyph, progress: progress })) : (_jsx(StatusBead, { className: toneClasses[tone], glyph: glyph, motion: motion })), label !== undefined ? _jsx("span", { children: label }) : null] }));
|
|
28
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import { type PriceTagProps } from "./price-tag.js";
|
|
3
|
+
/** A shelf entry with independent opening and acquisition controls. */
|
|
4
|
+
export type StoreCardProps = Omit<HTMLAttributes<HTMLDivElement>, "title"> & Readonly<{
|
|
5
|
+
title: string;
|
|
6
|
+
tagline: string;
|
|
7
|
+
variant?: "listing" | "cartridge" | "server";
|
|
8
|
+
/** Split wide feature cards into cover and copy columns. */
|
|
9
|
+
layout?: "stack" | "split";
|
|
10
|
+
cover?: ReactNode;
|
|
11
|
+
icon?: ReactNode;
|
|
12
|
+
seller?: ReactNode;
|
|
13
|
+
price?: PriceTagProps["price"];
|
|
14
|
+
badges?: readonly string[];
|
|
15
|
+
action?: ReactNode;
|
|
16
|
+
href?: string;
|
|
17
|
+
/** Open the listing independently of its footer action. */
|
|
18
|
+
onSelect?: () => void;
|
|
19
|
+
}>;
|
|
20
|
+
/** Caps owns the cover, copy, metadata and independent interaction states. */
|
|
21
|
+
export declare function StoreCard({ title, tagline, variant, layout, cover, icon, seller, price, badges, action, href, onSelect, className, ...props }: StoreCardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Badge } from "./badge.js";
|
|
3
|
+
import { Card } from "./card.js";
|
|
4
|
+
import { PriceTag } from "./price-tag.js";
|
|
5
|
+
import { cn } from "../lib/cn.js";
|
|
6
|
+
/** Caps owns the cover, copy, metadata and independent interaction states. */
|
|
7
|
+
export function StoreCard({ title, tagline, variant = "listing", layout = "stack", cover, icon, seller, price, badges = [], action, href, onSelect, className, ...props }) {
|
|
8
|
+
const content = (_jsxs(_Fragment, { children: [cover ? _jsx("span", { className: "caps-store-cover", children: cover }) : null, _jsxs("span", { className: "caps-store-heading", children: [icon ? _jsx("span", { className: "caps-store-icon", children: icon }) : null, _jsxs("span", { className: "caps-store-copy", children: [_jsx("strong", { className: "caps-store-title", children: title }), _jsx("span", { className: "caps-store-tagline", children: tagline })] })] })] }));
|
|
9
|
+
return (_jsx(Card, { ...props, role: "article", "aria-label": title, variant: "interactive", className: cn("caps-store-card", className), "data-variant": variant, "data-layout": layout, children: _jsxs("div", { className: "caps-store-body", children: [href ? (_jsx("a", { className: "caps-store-open", href: href, children: content })) : onSelect ? (_jsx("button", { className: "caps-store-open", type: "button", onClick: onSelect, children: content })) : (_jsx("div", { className: "caps-store-open", children: content })), _jsxs("footer", { className: "caps-store-footer", children: [_jsxs("div", { className: "caps-store-meta", children: [seller, badges.map((badge) => (_jsx(Badge, { tone: "secondary", variant: "quiet", size: "sm", children: badge.replaceAll("-", " ") }, badge))), price ? _jsx(PriceTag, { price: price }) : null] }), action ? _jsx("div", { className: "caps-store-action", children: action }) : null] })] }) }));
|
|
10
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactNode } from "react";
|
|
2
|
+
/** Native surface attributes with independent rim, depth and placement choices. */
|
|
3
|
+
export type SurfaceProps = HTMLAttributes<HTMLDivElement> & {
|
|
4
|
+
/** Rim scale, independent of the content's dimensions. */
|
|
5
|
+
size?: "sm" | "md" | "lg";
|
|
6
|
+
depth?: "shallow" | "deep";
|
|
7
|
+
/** Embedded surfaces borrow their parent's casing; omit the exterior surround. */
|
|
8
|
+
placement?: "standalone" | "embedded";
|
|
9
|
+
};
|
|
10
|
+
/** A themeable frame around a surface. No padding or interaction ownership. */
|
|
11
|
+
export declare const Surface: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
|
|
12
|
+
/** Rim scale, independent of the content's dimensions. */
|
|
13
|
+
size?: "sm" | "md" | "lg";
|
|
14
|
+
depth?: "shallow" | "deep";
|
|
15
|
+
/** Embedded surfaces borrow their parent's casing; omit the exterior surround. */
|
|
16
|
+
placement?: "standalone" | "embedded";
|
|
17
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
18
|
+
/** Display face using theme surfaces while preserving the inherited text font. */
|
|
19
|
+
export declare const Screen: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
|
|
20
|
+
/** A recessed display with a separate gasket and screen face. */
|
|
21
|
+
export type DisplayProps = SurfaceProps & {
|
|
22
|
+
/** Fill a flex region rather than sizing to its content. */
|
|
23
|
+
fit?: "content" | "fill";
|
|
24
|
+
/** Reduce the gasket footprint for compact displays. */
|
|
25
|
+
density?: "normal" | "compact";
|
|
26
|
+
};
|
|
27
|
+
/** Theme-owned recessed screen with a gasket and optional compact fill geometry. */
|
|
28
|
+
export declare const Display: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
|
|
29
|
+
/** Rim scale, independent of the content's dimensions. */
|
|
30
|
+
size?: "sm" | "md" | "lg";
|
|
31
|
+
depth?: "shallow" | "deep";
|
|
32
|
+
/** Embedded surfaces borrow their parent's casing; omit the exterior surround. */
|
|
33
|
+
placement?: "standalone" | "embedded";
|
|
34
|
+
} & {
|
|
35
|
+
/** Fill a flex region rather than sizing to its content. */
|
|
36
|
+
fit?: "content" | "fill";
|
|
37
|
+
/** Reduce the gasket footprint for compact displays. */
|
|
38
|
+
density?: "normal" | "compact";
|
|
39
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
40
|
+
/** Props accepted by ScreenHeader. */
|
|
41
|
+
export type ScreenHeaderProps = {
|
|
42
|
+
/** A decorative Sigil or App icon before the title. */
|
|
43
|
+
icon?: ReactNode;
|
|
44
|
+
title: ReactNode;
|
|
45
|
+
/** A Status or short readout opposite the title. */
|
|
46
|
+
status?: ReactNode;
|
|
47
|
+
} & Omit<HTMLAttributes<HTMLElement>, "title" | "children">;
|
|
48
|
+
/** A screen's title bar, printed on the glass above a hairline. */
|
|
49
|
+
export declare const ScreenHeader: import("react").ForwardRefExoticComponent<{
|
|
50
|
+
/** A decorative Sigil or App icon before the title. */
|
|
51
|
+
icon?: ReactNode;
|
|
52
|
+
title: ReactNode;
|
|
53
|
+
/** A Status or short readout opposite the title. */
|
|
54
|
+
status?: ReactNode;
|
|
55
|
+
} & Omit<HTMLAttributes<HTMLElement>, "title" | "children"> & import("react").RefAttributes<HTMLElement>>;
|
|
56
|
+
/**
|
|
57
|
+
* An instrument's cells: a grid of hairline-ruled cells that reflows to one
|
|
58
|
+
* column when narrow. Put ScreenCells straight inside a Screen or Display.
|
|
59
|
+
*/
|
|
60
|
+
export declare const ScreenCells: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
|
|
61
|
+
/** Compact instruments retain full-width rows instead of a cell grid. */
|
|
62
|
+
appearance?: "default" | "compact";
|
|
63
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
64
|
+
/** Props accepted by ScreenCell. */
|
|
65
|
+
export type ScreenCellProps = {
|
|
66
|
+
/** Compact rows put their subject icon and legend before the controls. */
|
|
67
|
+
appearance?: "default" | "compact";
|
|
68
|
+
/** A leading subject icon. */
|
|
69
|
+
icon?: ReactNode;
|
|
70
|
+
/** The cell's tiny mono legend, such as "Processes". */
|
|
71
|
+
legend?: ReactNode;
|
|
72
|
+
/** A short value readout in the cell's corner, such as "2/4 ON". */
|
|
73
|
+
readout?: ReactNode;
|
|
74
|
+
/** Span the full row instead of one column. */
|
|
75
|
+
wide?: boolean;
|
|
76
|
+
} & HTMLAttributes<HTMLDivElement>;
|
|
77
|
+
/** One instrument cell: a legend, an optional corner readout and its content. */
|
|
78
|
+
export declare const ScreenCell: import("react").ForwardRefExoticComponent<{
|
|
79
|
+
/** Compact rows put their subject icon and legend before the controls. */
|
|
80
|
+
appearance?: "default" | "compact";
|
|
81
|
+
/** A leading subject icon. */
|
|
82
|
+
icon?: ReactNode;
|
|
83
|
+
/** The cell's tiny mono legend, such as "Processes". */
|
|
84
|
+
legend?: ReactNode;
|
|
85
|
+
/** A short value readout in the cell's corner, such as "2/4 ON". */
|
|
86
|
+
readout?: ReactNode;
|
|
87
|
+
/** Span the full row instead of one column. */
|
|
88
|
+
wide?: boolean;
|
|
89
|
+
} & HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
/** A themeable frame around a surface. No padding or interaction ownership. */
|
|
5
|
+
export const Surface = forwardRef(function Surface({ className, size = "md", depth = "shallow", placement = "standalone", ...props }, ref) {
|
|
6
|
+
return (_jsx("div", { ...props, ref: ref, "data-surface-size": size, "data-surface-depth": depth, "data-surface-placement": placement, className: cn("caps-surface", className) }));
|
|
7
|
+
});
|
|
8
|
+
/** Display face using theme surfaces while preserving the inherited text font. */
|
|
9
|
+
export const Screen = forwardRef(function Screen({ className, ...props }, ref) {
|
|
10
|
+
return _jsx("div", { ...props, ref: ref, className: cn("caps-screen", className) });
|
|
11
|
+
});
|
|
12
|
+
/** Theme-owned recessed screen with a gasket and optional compact fill geometry. */
|
|
13
|
+
export const Display = forwardRef(function Display({ children, className, depth = "deep", fit = "content", density = "normal", ...props }, ref) {
|
|
14
|
+
const fill = fit === "fill";
|
|
15
|
+
return (_jsx(Surface, { ...props, className: cn(className, fill && "flex min-h-0 flex-1"), depth: depth, ref: ref, children: _jsx("div", { className: cn("caps-display-gasket", fill && "flex min-h-0 min-w-0 flex-1"), "data-display-density": density, children: _jsx(Screen, { className: cn(fill && "flex min-h-0 min-w-0 flex-1 overflow-hidden"), children: children }) }) }));
|
|
16
|
+
});
|
|
17
|
+
/** A screen's title bar, printed on the glass above a hairline. */
|
|
18
|
+
export const ScreenHeader = forwardRef(function ScreenHeader({ className, icon, status, title, ...props }, ref) {
|
|
19
|
+
return (_jsxs("header", { ...props, className: cn("caps-screen-header", className), ref: ref, children: [icon ? (_jsx("span", { className: "caps-screen-header-icon", "aria-hidden": "true", children: icon })) : null, _jsx("span", { className: "caps-screen-header-title", children: title }), status ? (_jsx("span", { className: "caps-screen-header-status", children: status })) : null] }));
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* An instrument's cells: a grid of hairline-ruled cells that reflows to one
|
|
23
|
+
* column when narrow. Put ScreenCells straight inside a Screen or Display.
|
|
24
|
+
*/
|
|
25
|
+
export const ScreenCells = forwardRef(function ScreenCells({ appearance, className, ...props }, ref) {
|
|
26
|
+
return (_jsx("div", { ...props, className: cn("caps-screen-cells", className), "data-appearance": appearance === "compact" ? appearance : undefined, ref: ref }));
|
|
27
|
+
});
|
|
28
|
+
/** One instrument cell: a legend, an optional corner readout and its content. */
|
|
29
|
+
export const ScreenCell = forwardRef(function ScreenCell({ children, className, legend, readout, icon, appearance, wide = false, ...props }, ref) {
|
|
30
|
+
return (_jsxs("div", { ...props, className: cn("caps-screen-cell", className), "data-wide": wide || undefined, "data-appearance": appearance === "compact" ? appearance : undefined, ref: ref, children: [icon ? _jsx("span", { className: "caps-screen-cell-icon", children: icon }) : null, legend ? (_jsx("span", { className: "caps-screen-cell-legend", children: legend })) : null, readout ? (_jsx("span", { className: "caps-screen-cell-readout", children: readout })) : null, appearance === "compact" ? (_jsx("div", { className: "caps-screen-cell-controls", children: children })) : (children)] }));
|
|
31
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { animate } from "animejs";
|
|
3
|
+
import { readMotion, useReducedMotion } from "../lib/motion.js";
|
|
4
|
+
import { themedEase, themedSpring } from "../lib/motion-spring.js";
|
|
5
|
+
import { useId, useLayoutEffect, useRef } from "react";
|
|
6
|
+
import { GooeySurfaceDefinition, GooeyShadowDefinition, GooeyInsetDefinition, } from "./gooey.js";
|
|
7
|
+
/** @internal A bead that compresses before filling or emptying its track. */
|
|
8
|
+
export function SwitchBead({ checked }) {
|
|
9
|
+
const id = `caps-switch-${useId().replaceAll(":", "")}`;
|
|
10
|
+
const body = useRef(null);
|
|
11
|
+
const surface = useRef(null);
|
|
12
|
+
const initial = useRef(checked).current;
|
|
13
|
+
const previous = useRef(checked);
|
|
14
|
+
const reduced = useReducedMotion();
|
|
15
|
+
useLayoutEffect(() => {
|
|
16
|
+
if (!body.current || !surface.current)
|
|
17
|
+
return;
|
|
18
|
+
const immediate = reduced || previous.current === checked;
|
|
19
|
+
previous.current = checked;
|
|
20
|
+
const width = checked ? 16 : 8;
|
|
21
|
+
const motion = readMotion(body.current);
|
|
22
|
+
const settle = themedSpring(motion, { bounce: 0.25, duration: 440 });
|
|
23
|
+
const squeeze = themedEase(motion, { ease: "inOutSine", duration: 100 });
|
|
24
|
+
const fill = animate(body.current, immediate
|
|
25
|
+
? {
|
|
26
|
+
x: 2,
|
|
27
|
+
y: 2,
|
|
28
|
+
width,
|
|
29
|
+
height: 8,
|
|
30
|
+
duration: 0,
|
|
31
|
+
}
|
|
32
|
+
: {
|
|
33
|
+
x: [
|
|
34
|
+
{ to: checked ? 2.5 : 1.5, ...squeeze },
|
|
35
|
+
{ to: 2, ...settle },
|
|
36
|
+
],
|
|
37
|
+
y: [
|
|
38
|
+
{ to: 1.5, ...squeeze },
|
|
39
|
+
{ to: 2, ...settle },
|
|
40
|
+
],
|
|
41
|
+
height: [
|
|
42
|
+
{ to: 9, ...squeeze },
|
|
43
|
+
{ to: 8, ...settle },
|
|
44
|
+
],
|
|
45
|
+
width: [
|
|
46
|
+
{ to: checked ? 7 : 16.5, ...squeeze },
|
|
47
|
+
{ to: width, ...settle },
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
const light = animate(surface.current, {
|
|
51
|
+
gradientTransform: checked
|
|
52
|
+
? "matrix(2 0 0 1 10 6)"
|
|
53
|
+
: "matrix(1 0 0 1 6 6)",
|
|
54
|
+
...(immediate ? { duration: 0 } : { delay: squeeze.duration, ...settle }),
|
|
55
|
+
});
|
|
56
|
+
return () => {
|
|
57
|
+
fill.cancel();
|
|
58
|
+
light.cancel();
|
|
59
|
+
};
|
|
60
|
+
}, [checked, reduced]);
|
|
61
|
+
return (_jsxs("svg", { className: "caps-switch-visual", width: "40", height: "24", viewBox: "0 0 20 12", "aria-hidden": "true", focusable: "false", children: [_jsxs("defs", { children: [_jsx(GooeySurfaceDefinition, { ref: surface, id: `${id}-surface`, transform: initial ? "matrix(2 0 0 1 10 6)" : "matrix(1 0 0 1 6 6)" }), _jsx(GooeyShadowDefinition, { id: `${id}-shadow` }), _jsx(GooeyInsetDefinition, { id: `${id}-inset` }), _jsx("clipPath", { id: `${id}-track`, children: _jsx("rect", { x: "1", y: "1", width: "18", height: "10", rx: "5" }) })] }), _jsx("rect", { className: "caps-switch-track", filter: `url(#${id}-inset)`, x: "0.5", y: "0.5", width: "19", height: "11", rx: "5.5" }), _jsx("g", { clipPath: `url(#${id}-track)`, children: _jsx("rect", { ref: body, x: "2", y: "2", width: initial ? 16 : 8, height: "8", rx: "4", fill: `url(#${id}-surface)`, filter: `url(#${id}-shadow)` }) })] }));
|
|
62
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type InputHTMLAttributes } from "react";
|
|
2
|
+
/** Props accepted by Switch. */
|
|
3
|
+
export type SwitchProps = {
|
|
4
|
+
/** Called after the checked state changes. */
|
|
5
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
6
|
+
} & Omit<InputHTMLAttributes<HTMLInputElement>, "defaultValue" | "type">;
|
|
7
|
+
/** A switch primitive with caller-owned checked state. */
|
|
8
|
+
export declare const Switch: import("react").ForwardRefExoticComponent<{
|
|
9
|
+
/** Called after the checked state changes. */
|
|
10
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
11
|
+
} & Omit<InputHTMLAttributes<HTMLInputElement>, "defaultValue" | "type"> & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useEffect, useImperativeHandle, useRef, useState, } from "react";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
import { SwitchBead } from "./switch-bead.js";
|
|
5
|
+
/** A switch primitive with caller-owned checked state. */
|
|
6
|
+
export const Switch = forwardRef(function Switch({ className, checked, defaultChecked = false, onChange, onCheckedChange, ...props }, ref) {
|
|
7
|
+
const input = useRef(null);
|
|
8
|
+
const [localChecked, setLocalChecked] = useState(defaultChecked);
|
|
9
|
+
const selected = checked ?? localChecked;
|
|
10
|
+
useImperativeHandle(ref, () => {
|
|
11
|
+
if (!input.current)
|
|
12
|
+
throw new Error("Switch input is not mounted");
|
|
13
|
+
return input.current;
|
|
14
|
+
}, []);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const form = input.current?.form;
|
|
17
|
+
if (!form || checked !== undefined)
|
|
18
|
+
return;
|
|
19
|
+
const reset = (event) => {
|
|
20
|
+
queueMicrotask(() => {
|
|
21
|
+
if (!event.defaultPrevented && input.current)
|
|
22
|
+
setLocalChecked(defaultChecked);
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
form.addEventListener("reset", reset);
|
|
26
|
+
return () => {
|
|
27
|
+
form.removeEventListener("reset", reset);
|
|
28
|
+
};
|
|
29
|
+
}, [checked, defaultChecked, props.form]);
|
|
30
|
+
return (_jsxs("span", { className: "caps-switch", "data-checked": selected, children: [_jsx("input", { ...props, checked: selected, className: cn("caps-switch-input", className), onChange: (event) => {
|
|
31
|
+
if (checked === undefined)
|
|
32
|
+
setLocalChecked(event.target.checked);
|
|
33
|
+
onChange?.(event);
|
|
34
|
+
onCheckedChange?.(event.target.checked);
|
|
35
|
+
}, ref: input, role: "switch", type: "checkbox" }), _jsx(SwitchBead, { checked: selected })] }));
|
|
36
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes, type HTMLAttributes, type ReactNode } from "react";
|
|
2
|
+
/** Props accepted by Tabs. */
|
|
3
|
+
export type TabsProps = {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
defaultValue?: string;
|
|
6
|
+
/** Called after the active tab value changes. */
|
|
7
|
+
onValueChange?: (value: string) => void;
|
|
8
|
+
value?: string;
|
|
9
|
+
} & HTMLAttributes<HTMLDivElement>;
|
|
10
|
+
/** A tab-list controller with explicit controlled or uncontrolled value state. */
|
|
11
|
+
export declare const Tabs: import("react").ForwardRefExoticComponent<{
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
defaultValue?: string;
|
|
14
|
+
/** Called after the active tab value changes. */
|
|
15
|
+
onValueChange?: (value: string) => void;
|
|
16
|
+
value?: string;
|
|
17
|
+
} & HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
|
|
18
|
+
/** Supported tab-list presentations. */
|
|
19
|
+
export type TabsListVariant = "bordered" | "segmented";
|
|
20
|
+
/** Props accepted by TabsList. */
|
|
21
|
+
export type TabsListProps = {
|
|
22
|
+
/**
|
|
23
|
+
* `bordered` underlines the selected tab. `segmented` presents a small set
|
|
24
|
+
* of equal, mutually exclusive choices as one inset control.
|
|
25
|
+
*/
|
|
26
|
+
variant?: TabsListVariant;
|
|
27
|
+
} & HTMLAttributes<HTMLDivElement>;
|
|
28
|
+
/** The tab-list layout for a Tabs controller. */
|
|
29
|
+
export declare const TabsList: import("react").ForwardRefExoticComponent<{
|
|
30
|
+
/**
|
|
31
|
+
* `bordered` underlines the selected tab. `segmented` presents a small set
|
|
32
|
+
* of equal, mutually exclusive choices as one inset control.
|
|
33
|
+
*/
|
|
34
|
+
variant?: TabsListVariant;
|
|
35
|
+
} & HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
|
|
36
|
+
/** Props accepted by TabsTrigger. */
|
|
37
|
+
export type TabsTriggerProps = {
|
|
38
|
+
value: string;
|
|
39
|
+
} & ButtonHTMLAttributes<HTMLButtonElement>;
|
|
40
|
+
/** A selectable tab in a Tabs controller. */
|
|
41
|
+
export declare const TabsTrigger: import("react").ForwardRefExoticComponent<{
|
|
42
|
+
value: string;
|
|
43
|
+
} & ButtonHTMLAttributes<HTMLButtonElement> & import("react").RefAttributes<HTMLButtonElement>>;
|
|
44
|
+
/** Props accepted by TabsContent. */
|
|
45
|
+
export type TabsContentProps = {
|
|
46
|
+
children: ReactNode;
|
|
47
|
+
forceMount?: boolean;
|
|
48
|
+
value: string;
|
|
49
|
+
} & HTMLAttributes<HTMLDivElement>;
|
|
50
|
+
/** The content panel associated with a Tabs value. */
|
|
51
|
+
export declare const TabsContent: import("react").ForwardRefExoticComponent<{
|
|
52
|
+
children: ReactNode;
|
|
53
|
+
forceMount?: boolean;
|
|
54
|
+
value: string;
|
|
55
|
+
} & HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
|