@sableui/react 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +189 -0
- package/CONTRIBUTING.md +1 -1
- package/THIRD_PARTY_NOTICES.md +11 -0
- package/bin/sable-lint.mjs +2 -1
- package/bin/sable.mjs +3 -2
- package/dist/{_contract-Cn3lUpih.d.ts → _contract-C2M1SjBf.d.ts} +20 -2
- package/dist/blocks/index.js +21 -53
- package/dist/{chunk-CCUDFLU3.js → chunk-7QSDYBXO.js} +652 -38
- package/dist/{chunk-FBSL2LZQ.js → chunk-EDXLM7YL.js} +11 -30
- package/dist/chunk-FKZXAFIY.js +12 -0
- package/dist/{chunk-OQACYT2D.js → chunk-NETUFI34.js} +23 -1
- package/dist/{chunk-NGBDP3BM.js → chunk-QJ6FWTUG.js} +1 -1
- package/dist/{chunk-D2ETQBHV.js → chunk-VVW4UCDI.js} +5 -5
- package/dist/{chunk-TH563WLW.js → chunk-XAZGMY73.js} +10 -3
- package/dist/foundations/index.js +6 -0
- package/dist/icon/index.js +2 -2
- package/dist/icon-sets/brands.d.ts +0 -27
- package/dist/icon-sets/brands.js +7 -1
- package/dist/icon-sets/reicon.js +1 -1
- package/dist/index.d.ts +164 -23
- package/dist/index.js +116 -29
- package/dist/ios/index.d.ts +6 -1
- package/dist/ios/index.js +4 -3
- package/dist/ios/styles.css +9 -0
- package/dist/patterns/index.js +24 -30
- package/dist/presets/index.d.ts +108 -5
- package/dist/presets/index.js +239 -6
- package/dist/styles.css +57 -0
- package/dist/{theme-provider-CGeiusgu.d.ts → theme-provider-kQszHYji.d.ts} +1 -1
- package/dist/themes/atelier/atelier.css +31 -3
- package/dist/themes/atelier/index.d.ts +1 -1
- package/dist/themes/ember/ember.css +38 -7
- package/dist/themes/ember/index.d.ts +1 -1
- package/dist/themes/index.d.ts +2 -2
- package/dist/themes/meridian/index.d.ts +1 -1
- package/dist/themes/meridian/meridian.css +33 -4
- package/dist/themes/poppy/index.d.ts +1 -1
- package/dist/themes/poppy/poppy.css +28 -0
- package/dist/themes/prism/index.d.ts +1 -1
- package/dist/themes/prism/prism.css +26 -0
- package/dist/themes/sable/index.d.ts +1 -1
- package/dist/themes/sable/sable.css +24 -11
- package/dist/themes/verdant/index.d.ts +1 -1
- package/dist/themes/verdant/verdant.css +34 -4
- package/llms/blocks/danger-zone-block.md +1 -1
- package/llms/blocks/event-card-block.md +1 -1
- package/llms/blocks/feedback-form-block.md +1 -1
- package/llms/blocks/invite-team-block.md +1 -1
- package/llms/blocks/media-player-block.md +3 -16
- package/llms/blocks/notification-list-block.md +3 -3
- package/llms/blocks/product-card-block.md +3 -17
- package/llms/blocks/profile-card-block.md +4 -17
- package/llms/blocks/profile-form-block.md +2 -2
- package/llms/blocks/team-members-block.md +1 -1
- package/llms/blocks/testimonial-block.md +1 -1
- package/llms/components/avatar.md +13 -1
- package/llms/components/card.md +1 -1
- package/llms/components/gradient-art.md +80 -0
- package/llms/components/sheet.md +1 -1
- package/llms/components/tabs.md +1 -1
- package/llms/components/toast.md +12 -1
- package/llms/foundations/accessibility.md +1 -0
- package/llms/patterns/auth-page.md +5 -19
- package/llms/patterns/brand-landing-page.md +1 -1
- package/llms/patterns/chat-panel.md +1 -1
- package/llms/patterns/dashboard-page.md +4 -4
- package/llms/patterns/feed-page.md +4 -4
- package/llms/patterns/landing-page.md +1 -1
- package/llms/patterns/list-detail-page.md +3 -2
- package/llms/patterns/settings-page.md +3 -3
- package/llms/reference/token-intent.md +9 -1
- package/llms/tasks/auditing-an-app.md +6 -0
- package/llms/tasks/building-an-ios-prototype.md +3 -1
- package/llms/tasks/converting-an-app.md +1 -1
- package/llms/tasks/creating-a-preset.md +24 -0
- package/llms/tasks/reviewing-a-design.md +9 -0
- package/llms/tasks/using-presets.md +6 -1
- package/llms-full.txt +214 -106
- package/llms.txt +4 -3
- package/package.json +9 -7
- package/registry.json +310 -32
- package/scripts/design-presets.mjs +27 -4
- package/scripts/grade.mjs +2 -1
- package/scripts/label-contrast.mjs +138 -0
- package/scripts/lint-rules.mjs +23 -2
- package/skills/sable/SKILL.md +3 -1
- package/targets/ios.json +18 -2
- package/third-party/paper-shaders-LICENSE.txt +201 -0
- package/third-party/paper-shaders-NOTICE.txt +5 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { StackedActionsContext, CardDepthContext, usePresentation, PresentationProvider } from './chunk-FKZXAFIY.js';
|
|
1
2
|
import { cn } from './chunk-SRQWQUTW.js';
|
|
2
|
-
import { Icon } from './chunk-
|
|
3
|
+
import { Icon } from './chunk-QJ6FWTUG.js';
|
|
3
4
|
import { createContext, useMemo, useState, useRef, useLayoutEffect, useEffect, useSyncExternalStore, useCallback, useContext, isValidElement, Children, useId, cloneElement } from 'react';
|
|
4
5
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
5
6
|
import { cva } from 'class-variance-authority';
|
|
@@ -11,6 +12,7 @@ import { Input as Input$1 } from '@base-ui/react/input';
|
|
|
11
12
|
import { Field as Field$1 } from '@base-ui/react/field';
|
|
12
13
|
import { Tooltip as Tooltip$1 } from '@base-ui/react/tooltip';
|
|
13
14
|
import { Switch as Switch$1 } from '@base-ui/react/switch';
|
|
15
|
+
import { grainGradientMeta, staticMeshGradientMeta, getShaderNoiseTexture, grainGradientFragmentShader, staticMeshGradientFragmentShader } from '@paper-design/shaders';
|
|
14
16
|
import { Avatar as Avatar$1 } from '@base-ui/react/avatar';
|
|
15
17
|
import { Progress as Progress$1 } from '@base-ui/react/progress';
|
|
16
18
|
import { Select as Select$1 } from '@base-ui/react/select';
|
|
@@ -462,7 +464,8 @@ function Button({
|
|
|
462
464
|
}) {
|
|
463
465
|
const tier = useTypeTier();
|
|
464
466
|
const isNativeButton = render === void 0;
|
|
465
|
-
const
|
|
467
|
+
const stacked = useContext(StackedActionsContext) && !String(size ?? "md").startsWith("icon");
|
|
468
|
+
const resolvedSize = stacked ? "cta" : size ?? "md";
|
|
466
469
|
const hasLabel = children != null && children !== false;
|
|
467
470
|
const spinner = /* @__PURE__ */ jsx(Spinner, { className: "size-(--button-icon)", thickness: 2 });
|
|
468
471
|
const start = loading ? spinner : iconStart;
|
|
@@ -486,7 +489,8 @@ function Button({
|
|
|
486
489
|
props: {
|
|
487
490
|
...props,
|
|
488
491
|
className: cn(
|
|
489
|
-
buttonVariants({ variant, size }),
|
|
492
|
+
buttonVariants({ variant, size: resolvedSize }),
|
|
493
|
+
stacked ? "w-full" : null,
|
|
490
494
|
tier.action,
|
|
491
495
|
optical,
|
|
492
496
|
// Busy is not disabled. Loading sets `disabled` so the action cannot
|
|
@@ -793,7 +797,9 @@ function Card({
|
|
|
793
797
|
ref,
|
|
794
798
|
...props
|
|
795
799
|
}) {
|
|
796
|
-
|
|
800
|
+
const depth = useContext(CardDepthContext);
|
|
801
|
+
const bleed = usePresentation() === "sheet" && variant === "flat" && depth === 0;
|
|
802
|
+
const element = useRender({
|
|
797
803
|
render: render ?? /* @__PURE__ */ jsx("div", {}),
|
|
798
804
|
ref,
|
|
799
805
|
props: {
|
|
@@ -818,10 +824,15 @@ function Card({
|
|
|
818
824
|
INTERACTIVE_HOVER[variant],
|
|
819
825
|
className
|
|
820
826
|
),
|
|
821
|
-
style: {
|
|
827
|
+
style: {
|
|
828
|
+
"--card-p": DENSITY_PAD[density],
|
|
829
|
+
...bleed ? { margin: "calc(var(--card-p) * -1)", width: "calc(100% + var(--card-p) * 2)", maxWidth: "none" } : null,
|
|
830
|
+
...style
|
|
831
|
+
}
|
|
822
832
|
},
|
|
823
833
|
defaultTagName: "div"
|
|
824
834
|
});
|
|
835
|
+
return /* @__PURE__ */ jsx(CardDepthContext.Provider, { value: depth + 1, children: element });
|
|
825
836
|
}
|
|
826
837
|
Card.displayName = "Card";
|
|
827
838
|
function CardHeader({
|
|
@@ -837,8 +848,11 @@ function CardHeader({
|
|
|
837
848
|
// one it collapses to a single stacked column (same as before).
|
|
838
849
|
// Zeroes its own bottom padding so it owns the CardHeader/CardContent
|
|
839
850
|
// seam — CardContent always has full padding on its own (see below),
|
|
840
|
-
// so a standalone CardContent never loses its top padding.
|
|
841
|
-
|
|
851
|
+
// so a standalone CardContent never loses its top padding. As the
|
|
852
|
+
// card's last child (a stat card: label, number, sparkline) nothing
|
|
853
|
+
// follows to pad the bottom, so it keeps its own; zeroed, the number
|
|
854
|
+
// sat on the card's bottom edge.
|
|
855
|
+
"grid auto-rows-min grid-cols-1 items-start gap-1.5 p-[var(--card-p,--spacing(6))] pb-0 last:pb-[var(--card-p,--spacing(6))] has-data-[slot=card-action]:grid-cols-[1fr_auto]",
|
|
842
856
|
className
|
|
843
857
|
),
|
|
844
858
|
...props
|
|
@@ -921,20 +935,27 @@ function CardList({
|
|
|
921
935
|
);
|
|
922
936
|
}
|
|
923
937
|
function CardFooter({
|
|
938
|
+
actions = false,
|
|
924
939
|
className,
|
|
940
|
+
children,
|
|
925
941
|
...props
|
|
926
942
|
}) {
|
|
943
|
+
const depth = useContext(CardDepthContext);
|
|
944
|
+
const stacked = usePresentation() === "sheet" && actions && depth <= 1;
|
|
927
945
|
return /* @__PURE__ */ jsx(
|
|
928
946
|
"div",
|
|
929
947
|
{
|
|
930
948
|
"data-slot": "card-footer",
|
|
949
|
+
"data-actions": actions ? stacked ? "stack" : "row" : void 0,
|
|
931
950
|
className: cn(
|
|
932
951
|
"flex items-center gap-2 p-[var(--card-p,--spacing(6))] pt-0",
|
|
933
952
|
"[[data-slot=card-header]+&]:pt-[var(--card-p,--spacing(6))]",
|
|
934
953
|
"[:is([data-slot=card-list],[data-slot=card-content][data-flush])+&]:border-t [:is([data-slot=card-list],[data-slot=card-content][data-flush])+&]:border-border [:is([data-slot=card-list],[data-slot=card-content][data-flush])+&]:pt-[var(--card-p,--spacing(6))]",
|
|
935
|
-
className
|
|
954
|
+
className,
|
|
955
|
+
stacked && "mt-auto flex-col-reverse items-stretch justify-start"
|
|
936
956
|
),
|
|
937
|
-
...props
|
|
957
|
+
...props,
|
|
958
|
+
children: stacked ? /* @__PURE__ */ jsx(StackedActionsContext.Provider, { value: true, children }) : children
|
|
938
959
|
}
|
|
939
960
|
);
|
|
940
961
|
}
|
|
@@ -1069,8 +1090,8 @@ var cardMeta = {
|
|
|
1069
1090
|
},
|
|
1070
1091
|
{
|
|
1071
1092
|
name: "CardFooter",
|
|
1072
|
-
type: 'ComponentPropsWithRef<"div">',
|
|
1073
|
-
description: "Bottom row for actions/meta. Padding follows the density knob."
|
|
1093
|
+
type: 'ComponentPropsWithRef<"div"> & { actions?: boolean }',
|
|
1094
|
+
description: "Bottom row for actions/meta. Padding follows the density knob. `actions` marks it as the card's action row (buttons only): in a sheet (IosSheet, a bottom SheetContent) it becomes a full-width stack pinned to the bottom, primary on top; on a page nothing changes."
|
|
1074
1095
|
}
|
|
1075
1096
|
],
|
|
1076
1097
|
variants: {
|
|
@@ -1322,16 +1343,18 @@ var MATRIX = {
|
|
|
1322
1343
|
// raw tone clears 4.5:1 on the page, but on its own 15% wash it did not
|
|
1323
1344
|
// (light info 4.2:1, dark edition 3.6:1, most of Verdant's tones ~4.1:1).
|
|
1324
1345
|
// Mixing toward --foreground moves it AWAY from the wash in both modes and
|
|
1325
|
-
// every theme, and keeps the hue.
|
|
1346
|
+
// every theme, and keeps the hue. Status tones mix from their -text token,
|
|
1347
|
+
// not the fill: dark fills now sit low enough for a white label, and ink
|
|
1348
|
+
// mixed from them fell under 4.5:1 (Meridian dark destructive, 3.8:1).
|
|
1326
1349
|
soft: {
|
|
1327
1350
|
neutral: "bg-secondary text-secondary-foreground",
|
|
1328
1351
|
standard: "bg-tone-standard/15 text-[color-mix(in_oklch,var(--tone-standard)_75%,var(--foreground))]",
|
|
1329
1352
|
collectible: "bg-tone-collectible/15 text-[color-mix(in_oklch,var(--tone-collectible)_75%,var(--foreground))]",
|
|
1330
1353
|
edition: "bg-tone-edition/15 text-[color-mix(in_oklch,var(--tone-edition)_75%,var(--foreground))]",
|
|
1331
|
-
info: "bg-tone-info/15 text-[color-mix(in_oklch,var(--tone-info)_75%,var(--foreground))]",
|
|
1332
|
-
success: "bg-success/15 text-[color-mix(in_oklch,var(--success)_75%,var(--foreground))]",
|
|
1333
|
-
warning: "bg-tone-warning/15 text-[color-mix(in_oklch,var(--tone-warning)_75%,var(--foreground))]",
|
|
1334
|
-
destructive: "bg-destructive/15 text-[color-mix(in_oklch,var(--destructive)_75%,var(--foreground))]"
|
|
1354
|
+
info: "bg-tone-info/15 text-[color-mix(in_oklch,var(--tone-info-text)_75%,var(--foreground))]",
|
|
1355
|
+
success: "bg-success/15 text-[color-mix(in_oklch,var(--success-text)_75%,var(--foreground))]",
|
|
1356
|
+
warning: "bg-tone-warning/15 text-[color-mix(in_oklch,var(--tone-warning-text)_75%,var(--foreground))]",
|
|
1357
|
+
destructive: "bg-destructive/15 text-[color-mix(in_oklch,var(--destructive-text)_75%,var(--foreground))]"
|
|
1335
1358
|
},
|
|
1336
1359
|
outline: {
|
|
1337
1360
|
neutral: "border border-border text-foreground",
|
|
@@ -1636,16 +1659,16 @@ function usePortalThemeScope() {
|
|
|
1636
1659
|
const [portal, setPortal] = useState(null);
|
|
1637
1660
|
const [probed, setProbed] = useState(null);
|
|
1638
1661
|
const probeRef = useRef(null);
|
|
1639
|
-
const
|
|
1662
|
+
const pending2 = portal !== null && probed !== portal;
|
|
1640
1663
|
useIsomorphicLayoutEffect(() => {
|
|
1641
|
-
if (!
|
|
1664
|
+
if (!pending2 || !portal) return;
|
|
1642
1665
|
const probe = probeRef.current;
|
|
1643
1666
|
if (probe) applyPortalThemeScope(portal, resolvePortalThemeScope(probe));
|
|
1644
1667
|
setProbed(portal);
|
|
1645
|
-
}, [
|
|
1668
|
+
}, [pending2, portal]);
|
|
1646
1669
|
return {
|
|
1647
1670
|
portalRef: setPortal,
|
|
1648
|
-
probe:
|
|
1671
|
+
probe: pending2 ? /* @__PURE__ */ jsx("span", { ref: probeRef, hidden: true, "data-sable-portal-probe": "" }) : null
|
|
1649
1672
|
};
|
|
1650
1673
|
}
|
|
1651
1674
|
function withPortalThemeScope(Portal) {
|
|
@@ -1717,7 +1740,7 @@ function FullscreenContent({
|
|
|
1717
1740
|
),
|
|
1718
1741
|
...props,
|
|
1719
1742
|
children: [
|
|
1720
|
-
children,
|
|
1743
|
+
/* @__PURE__ */ jsx(PresentationProvider, { value: "page", children }),
|
|
1721
1744
|
showCloseButton ? (
|
|
1722
1745
|
// The floating Button: Sable's control over content. Its own
|
|
1723
1746
|
// translucent popover chip and border keep it legible over bright
|
|
@@ -1775,7 +1798,7 @@ function CardContent2({
|
|
|
1775
1798
|
),
|
|
1776
1799
|
...props,
|
|
1777
1800
|
children: [
|
|
1778
|
-
scroll ? /* @__PURE__ */ jsx("div", { className: "-m-2 min-h-0 overflow-y-auto overscroll-contain p-2 scrollbar-quiet", children }) : children,
|
|
1801
|
+
/* @__PURE__ */ jsx(PresentationProvider, { value: "page", children: scroll ? /* @__PURE__ */ jsx("div", { className: "-m-2 min-h-0 overflow-y-auto overscroll-contain p-2 scrollbar-quiet", children }) : children }),
|
|
1779
1802
|
showCloseButton ? /* @__PURE__ */ jsx(
|
|
1780
1803
|
Dialog$1.Close,
|
|
1781
1804
|
{
|
|
@@ -2888,7 +2911,7 @@ function Switch({ className, ...props }) {
|
|
|
2888
2911
|
className
|
|
2889
2912
|
),
|
|
2890
2913
|
...props,
|
|
2891
|
-
children: /* @__PURE__ */ jsx(Switch$1.Thumb, { className: "block h-5 w-5 rounded-full bg-(--switch-thumb) shadow-
|
|
2914
|
+
children: /* @__PURE__ */ jsx(Switch$1.Thumb, { className: "block h-5 w-5 rounded-full bg-(--switch-thumb) shadow-(--knob-shadow) motion-interactive ease-spring data-[checked]:translate-x-4 rtl:data-[checked]:-translate-x-4 data-[checked]:bg-primary-foreground" })
|
|
2892
2915
|
}
|
|
2893
2916
|
);
|
|
2894
2917
|
}
|
|
@@ -3024,6 +3047,539 @@ var switchMeta = {
|
|
|
3024
3047
|
}
|
|
3025
3048
|
]
|
|
3026
3049
|
};
|
|
3050
|
+
var VERTEX = `#version 300 es
|
|
3051
|
+
precision mediump float;
|
|
3052
|
+
|
|
3053
|
+
layout(location = 0) in vec4 a_position;
|
|
3054
|
+
|
|
3055
|
+
uniform vec2 u_resolution;
|
|
3056
|
+
uniform float u_pixelRatio;
|
|
3057
|
+
uniform float u_originX;
|
|
3058
|
+
uniform float u_originY;
|
|
3059
|
+
uniform float u_worldWidth;
|
|
3060
|
+
uniform float u_worldHeight;
|
|
3061
|
+
uniform float u_fit;
|
|
3062
|
+
uniform float u_scale;
|
|
3063
|
+
uniform float u_rotation;
|
|
3064
|
+
uniform float u_offsetX;
|
|
3065
|
+
uniform float u_offsetY;
|
|
3066
|
+
|
|
3067
|
+
out vec2 v_objectUV;
|
|
3068
|
+
out vec2 v_objectBoxSize;
|
|
3069
|
+
out vec2 v_patternUV;
|
|
3070
|
+
out vec2 v_patternBoxSize;
|
|
3071
|
+
|
|
3072
|
+
vec3 getBoxSize(float boxRatio, vec2 givenBoxSize) {
|
|
3073
|
+
vec2 box = vec2(0.);
|
|
3074
|
+
box.x = boxRatio * min(givenBoxSize.x / boxRatio, givenBoxSize.y);
|
|
3075
|
+
float noFitBoxWidth = box.x;
|
|
3076
|
+
if (u_fit == 1.) {
|
|
3077
|
+
box.x = boxRatio * min(u_resolution.x / boxRatio, u_resolution.y);
|
|
3078
|
+
} else if (u_fit == 2.) {
|
|
3079
|
+
box.x = boxRatio * max(u_resolution.x / boxRatio, u_resolution.y);
|
|
3080
|
+
}
|
|
3081
|
+
box.y = box.x / boxRatio;
|
|
3082
|
+
return vec3(box, noFitBoxWidth);
|
|
3083
|
+
}
|
|
3084
|
+
|
|
3085
|
+
void main() {
|
|
3086
|
+
gl_Position = a_position;
|
|
3087
|
+
|
|
3088
|
+
vec2 uv = gl_Position.xy * .5;
|
|
3089
|
+
vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);
|
|
3090
|
+
vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);
|
|
3091
|
+
givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;
|
|
3092
|
+
float r = u_rotation * 3.14159265358979323846 / 180.;
|
|
3093
|
+
mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));
|
|
3094
|
+
vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);
|
|
3095
|
+
|
|
3096
|
+
vec2 fixedRatioBoxGivenSize = vec2(
|
|
3097
|
+
(u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,
|
|
3098
|
+
(u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y
|
|
3099
|
+
);
|
|
3100
|
+
v_objectBoxSize = getBoxSize(1., fixedRatioBoxGivenSize).xy;
|
|
3101
|
+
vec2 objectWorldScale = u_resolution.xy / v_objectBoxSize;
|
|
3102
|
+
v_objectUV = uv;
|
|
3103
|
+
v_objectUV *= objectWorldScale;
|
|
3104
|
+
v_objectUV += boxOrigin * (objectWorldScale - 1.);
|
|
3105
|
+
v_objectUV += graphicOffset;
|
|
3106
|
+
v_objectUV /= u_scale;
|
|
3107
|
+
v_objectUV = graphicRotation * v_objectUV;
|
|
3108
|
+
|
|
3109
|
+
vec2 patternBoxGivenSize = vec2(
|
|
3110
|
+
(u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,
|
|
3111
|
+
(u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y
|
|
3112
|
+
);
|
|
3113
|
+
float patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;
|
|
3114
|
+
vec3 boxSizeData = getBoxSize(patternBoxRatio, patternBoxGivenSize);
|
|
3115
|
+
v_patternBoxSize = boxSizeData.xy;
|
|
3116
|
+
float patternBoxNoFitBoxWidth = boxSizeData.z;
|
|
3117
|
+
vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;
|
|
3118
|
+
v_patternUV = uv;
|
|
3119
|
+
v_patternUV += graphicOffset / patternBoxScale;
|
|
3120
|
+
v_patternUV += boxOrigin;
|
|
3121
|
+
v_patternUV -= boxOrigin / patternBoxScale;
|
|
3122
|
+
v_patternUV *= u_resolution.xy;
|
|
3123
|
+
v_patternUV /= u_pixelRatio;
|
|
3124
|
+
if (u_fit > 0.) {
|
|
3125
|
+
v_patternUV *= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);
|
|
3126
|
+
}
|
|
3127
|
+
v_patternUV /= u_scale;
|
|
3128
|
+
v_patternUV = graphicRotation * v_patternUV;
|
|
3129
|
+
v_patternUV += boxOrigin / patternBoxScale;
|
|
3130
|
+
v_patternUV -= boxOrigin;
|
|
3131
|
+
v_patternUV *= .01;
|
|
3132
|
+
}
|
|
3133
|
+
`;
|
|
3134
|
+
var FRAGMENTS = { mesh: staticMeshGradientFragmentShader, grain: grainGradientFragmentShader };
|
|
3135
|
+
var MAX_COLORS = { mesh: staticMeshGradientMeta.maxColorCount, grain: grainGradientMeta.maxColorCount };
|
|
3136
|
+
var GRAIN_CORNERS = 4;
|
|
3137
|
+
var state;
|
|
3138
|
+
var noiseImage = null;
|
|
3139
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
3140
|
+
function onArtInvalidate(listener) {
|
|
3141
|
+
listeners.add(listener);
|
|
3142
|
+
return () => listeners.delete(listener);
|
|
3143
|
+
}
|
|
3144
|
+
var invalidate = () => {
|
|
3145
|
+
for (const listener of listeners) listener();
|
|
3146
|
+
};
|
|
3147
|
+
function compile(gl, type, source) {
|
|
3148
|
+
const shader = gl.createShader(type);
|
|
3149
|
+
if (!shader) return null;
|
|
3150
|
+
gl.shaderSource(shader, source);
|
|
3151
|
+
gl.compileShader(shader);
|
|
3152
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
3153
|
+
console.error("GradientArt: shader failed to compile", gl.getShaderInfoLog(shader));
|
|
3154
|
+
gl.deleteShader(shader);
|
|
3155
|
+
return null;
|
|
3156
|
+
}
|
|
3157
|
+
return shader;
|
|
3158
|
+
}
|
|
3159
|
+
function programFor(s, variant) {
|
|
3160
|
+
const cached = s.programs[variant];
|
|
3161
|
+
if (cached !== void 0) return cached;
|
|
3162
|
+
s.programs[variant] = null;
|
|
3163
|
+
const { gl } = s;
|
|
3164
|
+
const vertex = compile(gl, gl.VERTEX_SHADER, VERTEX);
|
|
3165
|
+
const fragment = compile(gl, gl.FRAGMENT_SHADER, FRAGMENTS[variant]);
|
|
3166
|
+
if (!vertex || !fragment) return null;
|
|
3167
|
+
const program = gl.createProgram();
|
|
3168
|
+
if (!program) return null;
|
|
3169
|
+
gl.attachShader(program, vertex);
|
|
3170
|
+
gl.attachShader(program, fragment);
|
|
3171
|
+
gl.linkProgram(program);
|
|
3172
|
+
gl.deleteShader(vertex);
|
|
3173
|
+
gl.deleteShader(fragment);
|
|
3174
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
3175
|
+
console.error("GradientArt: shader failed to link", gl.getProgramInfoLog(program));
|
|
3176
|
+
return null;
|
|
3177
|
+
}
|
|
3178
|
+
const entry = { program, uniforms: /* @__PURE__ */ new Map() };
|
|
3179
|
+
s.programs[variant] = entry;
|
|
3180
|
+
return entry;
|
|
3181
|
+
}
|
|
3182
|
+
function setup(s) {
|
|
3183
|
+
const { gl } = s;
|
|
3184
|
+
const buffer = gl.createBuffer();
|
|
3185
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
3186
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]), gl.STATIC_DRAW);
|
|
3187
|
+
gl.enableVertexAttribArray(0);
|
|
3188
|
+
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
|
3189
|
+
s.programs = {};
|
|
3190
|
+
s.noise = null;
|
|
3191
|
+
if (noiseImage?.complete && noiseImage.naturalWidth) uploadNoise(s, noiseImage);
|
|
3192
|
+
}
|
|
3193
|
+
function uploadNoise(s, image) {
|
|
3194
|
+
const { gl } = s;
|
|
3195
|
+
const texture = gl.createTexture();
|
|
3196
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
3197
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
3198
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
3199
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
3200
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
3201
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
3202
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
|
3203
|
+
s.noise = texture;
|
|
3204
|
+
}
|
|
3205
|
+
function getState() {
|
|
3206
|
+
if (state !== void 0) return state;
|
|
3207
|
+
if (typeof document === "undefined") return null;
|
|
3208
|
+
const canvas = document.createElement("canvas");
|
|
3209
|
+
const gl = canvas.getContext("webgl2", { alpha: true, premultipliedAlpha: true, antialias: false, preserveDrawingBuffer: true });
|
|
3210
|
+
if (!gl) {
|
|
3211
|
+
state = null;
|
|
3212
|
+
return state;
|
|
3213
|
+
}
|
|
3214
|
+
const s = { canvas, gl, programs: {}, noise: null, lost: false };
|
|
3215
|
+
setup(s);
|
|
3216
|
+
canvas.addEventListener("webglcontextlost", (event) => {
|
|
3217
|
+
event.preventDefault();
|
|
3218
|
+
s.lost = true;
|
|
3219
|
+
});
|
|
3220
|
+
canvas.addEventListener("webglcontextrestored", () => {
|
|
3221
|
+
s.lost = false;
|
|
3222
|
+
setup(s);
|
|
3223
|
+
invalidate();
|
|
3224
|
+
});
|
|
3225
|
+
state = s;
|
|
3226
|
+
return state;
|
|
3227
|
+
}
|
|
3228
|
+
function noiseReady(s) {
|
|
3229
|
+
if (s.noise) return true;
|
|
3230
|
+
if (!noiseImage) {
|
|
3231
|
+
noiseImage = getShaderNoiseTexture() ?? null;
|
|
3232
|
+
noiseImage?.decode().then(
|
|
3233
|
+
() => {
|
|
3234
|
+
const current = getState();
|
|
3235
|
+
if (current && noiseImage) uploadNoise(current, noiseImage);
|
|
3236
|
+
invalidate();
|
|
3237
|
+
},
|
|
3238
|
+
() => {
|
|
3239
|
+
}
|
|
3240
|
+
);
|
|
3241
|
+
}
|
|
3242
|
+
return false;
|
|
3243
|
+
}
|
|
3244
|
+
function artSupported() {
|
|
3245
|
+
return getState() !== null;
|
|
3246
|
+
}
|
|
3247
|
+
function paintArt(target, job) {
|
|
3248
|
+
const s = getState();
|
|
3249
|
+
if (!s || s.lost) return false;
|
|
3250
|
+
if (job.variant === "grain" && !noiseReady(s)) return false;
|
|
3251
|
+
const entry = programFor(s, job.variant);
|
|
3252
|
+
if (!entry) return false;
|
|
3253
|
+
const { gl, canvas } = s;
|
|
3254
|
+
const { width, height } = job;
|
|
3255
|
+
if (canvas.width !== width || canvas.height !== height) {
|
|
3256
|
+
canvas.width = width;
|
|
3257
|
+
canvas.height = height;
|
|
3258
|
+
}
|
|
3259
|
+
gl.viewport(0, 0, width, height);
|
|
3260
|
+
gl.useProgram(entry.program);
|
|
3261
|
+
const at = (name) => {
|
|
3262
|
+
if (!entry.uniforms.has(name)) entry.uniforms.set(name, gl.getUniformLocation(entry.program, name));
|
|
3263
|
+
return entry.uniforms.get(name) ?? null;
|
|
3264
|
+
};
|
|
3265
|
+
const float = (name, value) => gl.uniform1f(at(name), value);
|
|
3266
|
+
gl.uniform2f(at("u_resolution"), width, height);
|
|
3267
|
+
float("u_pixelRatio", job.pixelRatio);
|
|
3268
|
+
float("u_originX", 0.5);
|
|
3269
|
+
float("u_originY", 0.5);
|
|
3270
|
+
float("u_worldWidth", 0);
|
|
3271
|
+
float("u_worldHeight", 0);
|
|
3272
|
+
float("u_fit", 2);
|
|
3273
|
+
float("u_scale", 1);
|
|
3274
|
+
float("u_offsetX", 0);
|
|
3275
|
+
float("u_offsetY", 0);
|
|
3276
|
+
const max = MAX_COLORS[job.variant];
|
|
3277
|
+
const fill = (colors) => {
|
|
3278
|
+
const flat = new Float32Array(max * 4);
|
|
3279
|
+
colors.slice(0, max).forEach((color, i) => flat.set(color, i * 4));
|
|
3280
|
+
gl.uniform4fv(at("u_colors"), flat);
|
|
3281
|
+
float("u_colorsCount", Math.min(colors.length, max));
|
|
3282
|
+
};
|
|
3283
|
+
if (job.variant === "mesh") {
|
|
3284
|
+
float("u_scale", 0.72);
|
|
3285
|
+
float("u_rotation", job.seed * 360);
|
|
3286
|
+
fill(job.colors);
|
|
3287
|
+
float("u_positions", job.seed * 100);
|
|
3288
|
+
float("u_waveX", job.warp);
|
|
3289
|
+
float("u_waveXShift", job.seed);
|
|
3290
|
+
float("u_waveY", job.warp);
|
|
3291
|
+
float("u_waveYShift", job.seed * 7.3 % 1);
|
|
3292
|
+
float("u_mixing", job.softness);
|
|
3293
|
+
float("u_grainMixer", job.grain * 0.6);
|
|
3294
|
+
float("u_grainOverlay", job.grain);
|
|
3295
|
+
} else {
|
|
3296
|
+
const [ground2 = [0, 0, 0, 1], ...bands] = job.colors;
|
|
3297
|
+
float("u_rotation", job.seed * 360);
|
|
3298
|
+
gl.uniform4fv(at("u_colorBack"), ground2);
|
|
3299
|
+
fill(bands.length ? bands : [ground2]);
|
|
3300
|
+
float("u_time", job.seed * 100);
|
|
3301
|
+
float("u_softness", job.softness * 0.8);
|
|
3302
|
+
float("u_intensity", 0.15 + job.warp * 0.2);
|
|
3303
|
+
float("u_noise", 0.15 + job.grain * 0.5);
|
|
3304
|
+
float("u_shape", GRAIN_CORNERS);
|
|
3305
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
3306
|
+
gl.bindTexture(gl.TEXTURE_2D, s.noise);
|
|
3307
|
+
gl.uniform1i(at("u_noiseTexture"), 0);
|
|
3308
|
+
}
|
|
3309
|
+
gl.clearColor(0, 0, 0, 0);
|
|
3310
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
3311
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
3312
|
+
if (target.width !== width || target.height !== height) {
|
|
3313
|
+
target.width = width;
|
|
3314
|
+
target.height = height;
|
|
3315
|
+
}
|
|
3316
|
+
const context = target.getContext("2d");
|
|
3317
|
+
if (!context) return false;
|
|
3318
|
+
context.clearRect(0, 0, width, height);
|
|
3319
|
+
context.drawImage(canvas, 0, 0);
|
|
3320
|
+
return true;
|
|
3321
|
+
}
|
|
3322
|
+
var swatch;
|
|
3323
|
+
var parsed = /* @__PURE__ */ new Map();
|
|
3324
|
+
function cssColorToRgba(color) {
|
|
3325
|
+
const hit = parsed.get(color);
|
|
3326
|
+
if (hit) return hit;
|
|
3327
|
+
if (swatch === void 0) {
|
|
3328
|
+
swatch = typeof document === "undefined" ? null : document.createElement("canvas").getContext("2d", { willReadFrequently: true });
|
|
3329
|
+
if (swatch) swatch.canvas.width = swatch.canvas.height = 1;
|
|
3330
|
+
}
|
|
3331
|
+
if (!swatch) return null;
|
|
3332
|
+
swatch.clearRect(0, 0, 1, 1);
|
|
3333
|
+
swatch.fillStyle = "transparent";
|
|
3334
|
+
swatch.fillStyle = color;
|
|
3335
|
+
swatch.fillRect(0, 0, 1, 1);
|
|
3336
|
+
const [r, g, b, a] = swatch.getImageData(0, 0, 1, 1).data;
|
|
3337
|
+
const out = [r / 255, g / 255, b / 255, a / 255];
|
|
3338
|
+
if (parsed.size > 512) parsed.clear();
|
|
3339
|
+
parsed.set(color, out);
|
|
3340
|
+
return out;
|
|
3341
|
+
}
|
|
3342
|
+
var themeListeners = /* @__PURE__ */ new Set();
|
|
3343
|
+
var observer = null;
|
|
3344
|
+
var pending = 0;
|
|
3345
|
+
function onThemeChange(listener) {
|
|
3346
|
+
themeListeners.add(listener);
|
|
3347
|
+
if (!observer && typeof MutationObserver !== "undefined") {
|
|
3348
|
+
const notify = () => {
|
|
3349
|
+
if (pending) return;
|
|
3350
|
+
pending = requestAnimationFrame(() => {
|
|
3351
|
+
pending = 0;
|
|
3352
|
+
for (const fn of themeListeners) fn();
|
|
3353
|
+
});
|
|
3354
|
+
};
|
|
3355
|
+
observer = new MutationObserver(notify);
|
|
3356
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class", "style", "data-sable-theme"] });
|
|
3357
|
+
observer.observe(document.head, { childList: true, subtree: true, characterData: true });
|
|
3358
|
+
}
|
|
3359
|
+
return () => {
|
|
3360
|
+
themeListeners.delete(listener);
|
|
3361
|
+
if (!themeListeners.size && observer) {
|
|
3362
|
+
observer.disconnect();
|
|
3363
|
+
observer = null;
|
|
3364
|
+
cancelAnimationFrame(pending);
|
|
3365
|
+
pending = 0;
|
|
3366
|
+
}
|
|
3367
|
+
};
|
|
3368
|
+
}
|
|
3369
|
+
var ART_SLOTS = ["var(--art-1)", "var(--art-2)", "var(--art-3)", "var(--art-4)", "var(--art-5)", "var(--art-6)"];
|
|
3370
|
+
var ART_GROUND = "var(--art-ground)";
|
|
3371
|
+
var lifted = (tone) => `oklch(from var(--tone-${tone}) clamp(0.5, calc(l + 0.16), 0.9) max(calc(c * 1.25), 0.1) h)`;
|
|
3372
|
+
var ground = (tone) => `color-mix(in oklab, var(--primary) 55%, oklch(from var(--tone-${tone}) 0.3 c h))`;
|
|
3373
|
+
function seedValue(seed) {
|
|
3374
|
+
if (seed == null) return 0.37;
|
|
3375
|
+
if (typeof seed === "number") return Math.abs(seed * 0.618034) % 1;
|
|
3376
|
+
let hash = 2166136261;
|
|
3377
|
+
for (let i = 0; i < seed.length; i++) {
|
|
3378
|
+
hash ^= seed.charCodeAt(i);
|
|
3379
|
+
hash = Math.imul(hash, 16777619);
|
|
3380
|
+
}
|
|
3381
|
+
return (hash >>> 0) / 4294967296;
|
|
3382
|
+
}
|
|
3383
|
+
function fallback(palette, groundColor, seed) {
|
|
3384
|
+
const spots = palette.map((color, i) => {
|
|
3385
|
+
const angle = (seed + i / palette.length) * Math.PI * 2;
|
|
3386
|
+
const x = Math.round(50 + Math.cos(angle) * 38);
|
|
3387
|
+
const y = Math.round(50 + Math.sin(angle) * 38);
|
|
3388
|
+
return `radial-gradient(in oklab at ${x}% ${y}%, ${color}, transparent 60%)`;
|
|
3389
|
+
});
|
|
3390
|
+
return [...spots, groundColor].join(", ");
|
|
3391
|
+
}
|
|
3392
|
+
function rotate(items, seed) {
|
|
3393
|
+
if (items.length < 2) return [...items];
|
|
3394
|
+
const shift = Math.floor(seed * 7919) % items.length;
|
|
3395
|
+
return [...items.slice(shift), ...items.slice(0, shift)];
|
|
3396
|
+
}
|
|
3397
|
+
function param(style, name, fallbackValue) {
|
|
3398
|
+
const n = Number.parseFloat(style.getPropertyValue(name));
|
|
3399
|
+
return Number.isFinite(n) ? Math.min(1, Math.max(0, n)) : fallbackValue;
|
|
3400
|
+
}
|
|
3401
|
+
var MAX_PIXELS = 15e5;
|
|
3402
|
+
function GradientArt({ variant = "mesh", tones, seed, className, style, children, ...props }) {
|
|
3403
|
+
const root = useRef(null);
|
|
3404
|
+
const canvas = useRef(null);
|
|
3405
|
+
const probes = useRef(null);
|
|
3406
|
+
const value = seedValue(seed);
|
|
3407
|
+
const palette = tones?.length ? tones.map(lifted) : ART_SLOTS;
|
|
3408
|
+
const groundColor = tones?.length ? ground(tones[0]) : ART_GROUND;
|
|
3409
|
+
const paletteKey = palette.join(" ");
|
|
3410
|
+
const background = fallback(rotate(palette, value), groundColor, value);
|
|
3411
|
+
useEffect(() => {
|
|
3412
|
+
const element = root.current;
|
|
3413
|
+
const target = canvas.current;
|
|
3414
|
+
const swatches = probes.current;
|
|
3415
|
+
if (!element || !target || !swatches || !artSupported()) return;
|
|
3416
|
+
if (typeof IntersectionObserver === "undefined" || typeof ResizeObserver === "undefined") return;
|
|
3417
|
+
let visible = false;
|
|
3418
|
+
let frame = 0;
|
|
3419
|
+
let last = "";
|
|
3420
|
+
const paint = () => {
|
|
3421
|
+
frame = 0;
|
|
3422
|
+
if (!visible) return;
|
|
3423
|
+
const rect = element.getBoundingClientRect();
|
|
3424
|
+
if (!rect.width || !rect.height) return;
|
|
3425
|
+
let ratio = Math.min(window.devicePixelRatio || 1, 2);
|
|
3426
|
+
const pixels = rect.width * rect.height * ratio * ratio;
|
|
3427
|
+
if (pixels > MAX_PIXELS) ratio *= Math.sqrt(MAX_PIXELS / pixels);
|
|
3428
|
+
const width = Math.max(1, Math.round(rect.width * ratio));
|
|
3429
|
+
const height = Math.max(1, Math.round(rect.height * ratio));
|
|
3430
|
+
const resolve = (probe) => cssColorToRgba(getComputedStyle(probe).color);
|
|
3431
|
+
const [groundProbe, ...colorProbes] = Array.from(swatches.children);
|
|
3432
|
+
const colors = rotate(
|
|
3433
|
+
colorProbes.map(resolve).filter((c) => c != null && c[3] > 0.01),
|
|
3434
|
+
value
|
|
3435
|
+
);
|
|
3436
|
+
const groundRgba = groundProbe ? resolve(groundProbe) : null;
|
|
3437
|
+
if (!colors.length) return;
|
|
3438
|
+
const own = getComputedStyle(element);
|
|
3439
|
+
const character = { warp: param(own, "--art-warp", 0.8), softness: param(own, "--art-softness", 0.88), grain: param(own, "--art-grain", 0) };
|
|
3440
|
+
const key = JSON.stringify([variant, value, width, height, colors, groundRgba, character]);
|
|
3441
|
+
if (key === last) return;
|
|
3442
|
+
const ordered = variant === "grain" && groundRgba ? [groundRgba, ...colors] : colors;
|
|
3443
|
+
if (paintArt(target, { variant, colors: ordered, seed: value, width, height, pixelRatio: ratio, ...character })) {
|
|
3444
|
+
last = key;
|
|
3445
|
+
target.dataset.painted = "";
|
|
3446
|
+
}
|
|
3447
|
+
};
|
|
3448
|
+
const schedule = () => {
|
|
3449
|
+
if (!frame) frame = requestAnimationFrame(paint);
|
|
3450
|
+
};
|
|
3451
|
+
const repaint = () => {
|
|
3452
|
+
last = "";
|
|
3453
|
+
schedule();
|
|
3454
|
+
};
|
|
3455
|
+
const intersection = new IntersectionObserver(
|
|
3456
|
+
([entry]) => {
|
|
3457
|
+
visible = entry.isIntersecting;
|
|
3458
|
+
if (visible) schedule();
|
|
3459
|
+
},
|
|
3460
|
+
{ rootMargin: "200px" }
|
|
3461
|
+
);
|
|
3462
|
+
intersection.observe(element);
|
|
3463
|
+
const resize = new ResizeObserver(schedule);
|
|
3464
|
+
resize.observe(element);
|
|
3465
|
+
const offTheme = onThemeChange(schedule);
|
|
3466
|
+
const offInvalidate = onArtInvalidate(repaint);
|
|
3467
|
+
return () => {
|
|
3468
|
+
cancelAnimationFrame(frame);
|
|
3469
|
+
intersection.disconnect();
|
|
3470
|
+
resize.disconnect();
|
|
3471
|
+
offTheme();
|
|
3472
|
+
offInvalidate();
|
|
3473
|
+
};
|
|
3474
|
+
}, [variant, value, paletteKey]);
|
|
3475
|
+
return /* @__PURE__ */ jsxs(
|
|
3476
|
+
"div",
|
|
3477
|
+
{
|
|
3478
|
+
ref: root,
|
|
3479
|
+
"data-slot": "gradient-art",
|
|
3480
|
+
"data-variant": variant,
|
|
3481
|
+
className: cn("relative isolate overflow-hidden", className),
|
|
3482
|
+
style: { background, ...style },
|
|
3483
|
+
...props,
|
|
3484
|
+
children: [
|
|
3485
|
+
/* @__PURE__ */ jsx(
|
|
3486
|
+
"canvas",
|
|
3487
|
+
{
|
|
3488
|
+
ref: canvas,
|
|
3489
|
+
"aria-hidden": true,
|
|
3490
|
+
className: "pointer-events-none absolute inset-0 -z-10 size-full opacity-0 motion-interactive data-[painted]:opacity-100",
|
|
3491
|
+
style: { transitionProperty: "opacity" }
|
|
3492
|
+
}
|
|
3493
|
+
),
|
|
3494
|
+
/* @__PURE__ */ jsxs("span", { ref: probes, hidden: true, children: [
|
|
3495
|
+
/* @__PURE__ */ jsx("span", { style: { color: groundColor } }),
|
|
3496
|
+
palette.map((color) => /* @__PURE__ */ jsx("span", { style: { color } }, color))
|
|
3497
|
+
] }),
|
|
3498
|
+
children
|
|
3499
|
+
]
|
|
3500
|
+
}
|
|
3501
|
+
);
|
|
3502
|
+
}
|
|
3503
|
+
GradientArt.displayName = "GradientArt";
|
|
3504
|
+
|
|
3505
|
+
// src/components/gradient-art/gradient-art.meta.ts
|
|
3506
|
+
var gradientArtMeta = {
|
|
3507
|
+
name: "GradientArt",
|
|
3508
|
+
summary: "Placeholder artwork painted by a static WebGL shader from the preset's own art direction (the --art-* tokens: palette, ground, warp, softness, grain) \u2014 Ember burns, Prism airbrushes, Meridian is grainy monochrome \u2014 with a CSS gradient underneath for prerendered pages and browsers without WebGL2.",
|
|
3509
|
+
status: "beta",
|
|
3510
|
+
keywords: ["gradient", "mesh gradient", "grain", "shader", "artwork", "placeholder image", "cover", "banner", "avatar fallback", "generative"],
|
|
3511
|
+
usage: {
|
|
3512
|
+
description: "Use GradientArt where a real image belongs but none exists yet, or where the image is decoration: a product cover before upload, a profile banner, an album tile, an avatar with no photo. It reads the theme's own tokens, so it follows every preset, mode and live edit; `seed` fixes each item's composition so a list of covers or avatars stays individually recognisable.",
|
|
3513
|
+
bestPractices: [
|
|
3514
|
+
{
|
|
3515
|
+
guidance: "do",
|
|
3516
|
+
description: "Pass a stable `seed` per item \u2014 the name for an avatar, the title for a cover. Each item then keeps the same art across renders, reloads and themes, which is what lets someone recognise it."
|
|
3517
|
+
},
|
|
3518
|
+
{
|
|
3519
|
+
guidance: "do",
|
|
3520
|
+
description: "Size it with layout classes (`aspect-[4/3]`, `h-20`, `size-10 rounded-full`) and put any glyph or initials inside as children; they render above the art."
|
|
3521
|
+
},
|
|
3522
|
+
{
|
|
3523
|
+
guidance: "do",
|
|
3524
|
+
description: "Keep the default `mesh` for covers, tiles and avatars. Reach for `grain` where a printed, tactile surface suits \u2014 a banner, a hero card \u2014 and keep one variant per surface type so art reads as a system."
|
|
3525
|
+
},
|
|
3526
|
+
{
|
|
3527
|
+
guidance: "dont",
|
|
3528
|
+
description: "Do not put body text over it. The art spans the palette's lightest and most saturated tones, so no single ink is guaranteed to clear contrast across it; reserve overlays for a short label on a scrim or an avatar's initials."
|
|
3529
|
+
},
|
|
3530
|
+
{
|
|
3531
|
+
guidance: "dont",
|
|
3532
|
+
description: "Do not pass colours, and reach for `tones` rarely. The art follows the preset's --art-* tokens on purpose; to change how a product's art looks, set the --theme-art-* hooks in its theme or preset, so every cover, banner and avatar changes together."
|
|
3533
|
+
},
|
|
3534
|
+
{
|
|
3535
|
+
guidance: "dont",
|
|
3536
|
+
description: "Do not use it as a page or hero background. It paints at the element's pixel size, so a full-viewport instance costs a large frame on every theme change; it is sized for covers, banners and tiles."
|
|
3537
|
+
}
|
|
3538
|
+
]
|
|
3539
|
+
},
|
|
3540
|
+
related: { components: ["Avatar", "Card", "AspectBox"] },
|
|
3541
|
+
props: [
|
|
3542
|
+
{ name: "variant", type: '"mesh" | "grain"', default: '"mesh"', description: "mesh: soft spots of colour pulled together by gentle waves. grain: glowing light over deep corners with a printed texture." },
|
|
3543
|
+
{
|
|
3544
|
+
name: "tones",
|
|
3545
|
+
type: '("info" | "standard" | "collectible" | "edition" | "warning")[]',
|
|
3546
|
+
description: "Paint these `--tone-*` colours instead of the preset's art palette. Leave unset to follow the preset's art direction."
|
|
3547
|
+
},
|
|
3548
|
+
{ name: "seed", type: "string | number", description: "Fixes the composition: the same seed paints the same art in every theme. Pass a stable id." },
|
|
3549
|
+
{ name: "children", type: "ReactNode", description: "Rendered above the art \u2014 initials, a glyph, a short label." },
|
|
3550
|
+
{ name: "className", type: "string", description: "Size and shape: aspect, height, rounding." }
|
|
3551
|
+
],
|
|
3552
|
+
variants: { variant: ["mesh", "grain"] },
|
|
3553
|
+
tokensUsed: ["art-1", "art-2", "art-3", "art-4", "art-5", "art-6", "art-ground", "art-warp", "art-softness", "art-grain", "primary", "tone-info", "tone-standard", "tone-collectible", "tone-edition", "tone-warning"],
|
|
3554
|
+
motion: [
|
|
3555
|
+
{
|
|
3556
|
+
slot: "arrival",
|
|
3557
|
+
recipe: "motion-interactive",
|
|
3558
|
+
part: "canvas",
|
|
3559
|
+
why: "The shader frame fades in over the CSS gradient it replaces, so the swap from fallback to shader reads as the art settling rather than a flash."
|
|
3560
|
+
},
|
|
3561
|
+
{ slot: "response", recipe: "none", part: "root", why: "Artwork, not a control: it does not react to the pointer." },
|
|
3562
|
+
{
|
|
3563
|
+
slot: "transition",
|
|
3564
|
+
recipe: "custom",
|
|
3565
|
+
part: "canvas",
|
|
3566
|
+
why: "A theme change repaints the frame in place on the next animation frame; there are no states to move between."
|
|
3567
|
+
},
|
|
3568
|
+
{ slot: "activity", recipe: "none", part: "root", why: "Static by design: nothing animates between paints, so it costs nothing while idle and respects reduced motion without a branch." }
|
|
3569
|
+
],
|
|
3570
|
+
a11y: [
|
|
3571
|
+
"Decorative by default: the canvas is aria-hidden. When the art stands for something (an avatar), label the element that contains it, not the art.",
|
|
3572
|
+
"Children render above the art in the normal reading order, so initials or a label are announced as usual."
|
|
3573
|
+
],
|
|
3574
|
+
examples: [
|
|
3575
|
+
{ label: "Product cover", code: '<GradientArt seed="Untitled (gold rush)" className="aspect-[4/3] rounded-lg" />' },
|
|
3576
|
+
{ label: "Grain banner", code: '<GradientArt variant="grain" seed="juno" tones={["info", "edition"]} className="h-20 rounded-md" />' },
|
|
3577
|
+
{
|
|
3578
|
+
label: "Avatar with initials",
|
|
3579
|
+
code: '<GradientArt seed="Mara Okafor" className="grid size-10 place-items-center rounded-full text-label-md text-overlay-foreground">MO</GradientArt>'
|
|
3580
|
+
}
|
|
3581
|
+
]
|
|
3582
|
+
};
|
|
3027
3583
|
var avatarVariants = cva(
|
|
3028
3584
|
"relative inline-flex shrink-0 select-none items-center justify-center overflow-hidden rounded-full bg-muted",
|
|
3029
3585
|
{
|
|
@@ -3108,17 +3664,22 @@ AvatarFallback.displayName = "AvatarFallback";
|
|
|
3108
3664
|
function Avatar({
|
|
3109
3665
|
src,
|
|
3110
3666
|
alt,
|
|
3111
|
-
fallback,
|
|
3667
|
+
fallback: fallback2,
|
|
3112
3668
|
fallbackDelay,
|
|
3113
3669
|
size,
|
|
3114
3670
|
status,
|
|
3671
|
+
variant = "neutral",
|
|
3672
|
+
seed,
|
|
3115
3673
|
className,
|
|
3116
3674
|
...props
|
|
3117
3675
|
}) {
|
|
3118
3676
|
const named = !src && alt ? { role: "img", "aria-label": alt } : null;
|
|
3119
3677
|
const avatar = /* @__PURE__ */ jsxs(AvatarRoot, { size, className: status == null ? className : void 0, ...named, ...props, children: [
|
|
3120
3678
|
src ? /* @__PURE__ */ jsx(AvatarImage, { src, alt: alt ?? "" }) : null,
|
|
3121
|
-
/* @__PURE__ */ jsx(AvatarFallback, { delay: fallbackDelay, "aria-hidden": named ? true : void 0, children:
|
|
3679
|
+
variant === "art" ? /* @__PURE__ */ jsx(AvatarFallback, { delay: fallbackDelay, "aria-hidden": named ? true : void 0, className: "size-full", children: /* @__PURE__ */ jsxs(GradientArt, { seed: seed ?? (typeof fallback2 === "string" && fallback2 || alt || void 0), className: "flex size-full items-center justify-center text-overlay-foreground", children: [
|
|
3680
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute inset-0 bg-overlay/30" }),
|
|
3681
|
+
/* @__PURE__ */ jsx("span", { className: "relative", children: fallback2 })
|
|
3682
|
+
] }) }) : /* @__PURE__ */ jsx(AvatarFallback, { delay: fallbackDelay, "aria-hidden": named ? true : void 0, children: fallback2 })
|
|
3122
3683
|
] });
|
|
3123
3684
|
if (status == null) return avatar;
|
|
3124
3685
|
return /* @__PURE__ */ jsxs("span", { "data-slot": "avatar-status-anchor", className: cn("relative inline-flex shrink-0 rounded-full", className), children: [
|
|
@@ -3244,6 +3805,10 @@ var avatarMeta = {
|
|
|
3244
3805
|
usage: {
|
|
3245
3806
|
description: 'Use Avatar to represent a person, team, or account with a compact visual identity. Wrap several in AvatarGroup for collaborators, assignees, or attendees \u2014 it overlaps them, rings each in the surface colour, and collapses the rest into a "+N" count; use the low-level parts only when you need custom image/fallback layout.',
|
|
3246
3807
|
bestPractices: [
|
|
3808
|
+
{
|
|
3809
|
+
guidance: "do",
|
|
3810
|
+
description: 'Use `variant="art"` where people without photos sit side by side \u2014 a member list, an activity feed, a chat. Seeded by the person, each gets their own colour, so faces stay tellable apart at a glance; the neutral fallback makes everyone the same grey circle.'
|
|
3811
|
+
},
|
|
3247
3812
|
{
|
|
3248
3813
|
guidance: "do",
|
|
3249
3814
|
description: "Provide meaningful alt text for profile images, or an empty alt when the adjacent text already names the person."
|
|
@@ -3338,6 +3903,17 @@ var avatarMeta = {
|
|
|
3338
3903
|
type: '"sm" | "md" | "lg"',
|
|
3339
3904
|
default: '"md"',
|
|
3340
3905
|
description: "Square footprint: 32px / 40px / 48px."
|
|
3906
|
+
},
|
|
3907
|
+
{
|
|
3908
|
+
name: "variant",
|
|
3909
|
+
type: '"neutral" | "art"',
|
|
3910
|
+
default: '"neutral"',
|
|
3911
|
+
description: "What the fallback looks like. neutral: initials on the muted surface. art: initials over GradientArt seeded by the person, so each person without a photo gets their own stable colour from the theme."
|
|
3912
|
+
},
|
|
3913
|
+
{
|
|
3914
|
+
name: "seed",
|
|
3915
|
+
type: "string | number",
|
|
3916
|
+
description: "The art variant's seed. Defaults to the fallback text, then `alt`, so a person keeps one colour wherever they appear; pass a user id to tell apart two people who share initials."
|
|
3341
3917
|
}
|
|
3342
3918
|
],
|
|
3343
3919
|
subcomponents: [
|
|
@@ -3368,9 +3944,10 @@ var avatarMeta = {
|
|
|
3368
3944
|
}
|
|
3369
3945
|
],
|
|
3370
3946
|
variants: {
|
|
3371
|
-
size: ["sm", "md", "lg"]
|
|
3947
|
+
size: ["sm", "md", "lg"],
|
|
3948
|
+
variant: ["neutral", "art"]
|
|
3372
3949
|
},
|
|
3373
|
-
tokensUsed: ["muted", "muted-foreground", "background", "card", "popover"],
|
|
3950
|
+
tokensUsed: ["muted", "muted-foreground", "background", "card", "popover", "overlay", "overlay-foreground"],
|
|
3374
3951
|
a11y: [
|
|
3375
3952
|
"Base UI tracks the image loading status and swaps to the fallback on missing/loading/error \u2014 no manual onError wiring.",
|
|
3376
3953
|
"Provide meaningful alt text via the alt prop; pass an empty alt for decorative avatars.",
|
|
@@ -3387,6 +3964,10 @@ var avatarMeta = {
|
|
|
3387
3964
|
label: "Fallback only",
|
|
3388
3965
|
code: '<Avatar fallback="AM" alt="Alex Morgan" />'
|
|
3389
3966
|
},
|
|
3967
|
+
{
|
|
3968
|
+
label: "Art fallback",
|
|
3969
|
+
code: '<Avatar variant="art" fallback="AM" alt="Alex Morgan" />'
|
|
3970
|
+
},
|
|
3390
3971
|
{
|
|
3391
3972
|
label: "Sizes",
|
|
3392
3973
|
code: '<Avatar src="/pfp.png" alt="Alex Morgan" fallback="AM" size="sm" />\n<Avatar src="/pfp.png" alt="Alex Morgan" fallback="AM" size="md" />\n<Avatar src="/pfp.png" alt="Alex Morgan" fallback="AM" size="lg" />'
|
|
@@ -4117,9 +4698,11 @@ function MenuContent({
|
|
|
4117
4698
|
}
|
|
4118
4699
|
var MENU_ITEM_DESTRUCTIVE = (
|
|
4119
4700
|
// The ink is pulled a quarter toward --foreground (as Badge's soft tones
|
|
4120
|
-
// are)
|
|
4121
|
-
//
|
|
4122
|
-
|
|
4701
|
+
// are), from --destructive-text rather than the fill: dark fills sit low
|
|
4702
|
+
// enough for a white label, and ink mixed from them measured 3.8:1 on
|
|
4703
|
+
// Meridian's popover. From the text token every theme clears 4.5:1 (worst
|
|
4704
|
+
// 5.4:1, Prism dark, on the 10% red wash).
|
|
4705
|
+
"text-[color-mix(in_oklch,var(--destructive-text)_75%,var(--foreground))] data-[highlighted]:bg-destructive/10 data-[highlighted]:text-[color-mix(in_oklch,var(--destructive-text)_75%,var(--foreground))]"
|
|
4123
4706
|
);
|
|
4124
4707
|
function MenuItem({ className, variant = "default", ...props }) {
|
|
4125
4708
|
const tier = useTypeTier();
|
|
@@ -4819,6 +5402,29 @@ function useCopy(text, { timeout = 1500 } = {}) {
|
|
|
4819
5402
|
}, [text, timeout]);
|
|
4820
5403
|
return { copy, copied };
|
|
4821
5404
|
}
|
|
5405
|
+
function useEdgeFade(ref, orientation) {
|
|
5406
|
+
const [showStart, setShowStart] = useState(false);
|
|
5407
|
+
const [showEnd, setShowEnd] = useState(false);
|
|
5408
|
+
const sync = useCallback(() => {
|
|
5409
|
+
const el = ref.current;
|
|
5410
|
+
if (!el) return;
|
|
5411
|
+
if (orientation === "horizontal") {
|
|
5412
|
+
const { scrollLeft, scrollWidth, clientWidth } = el;
|
|
5413
|
+
setShowStart(scrollLeft > 0);
|
|
5414
|
+
setShowEnd(scrollLeft < scrollWidth - clientWidth - 1);
|
|
5415
|
+
} else {
|
|
5416
|
+
const { scrollTop, scrollHeight, clientHeight } = el;
|
|
5417
|
+
setShowStart(scrollTop > 0);
|
|
5418
|
+
setShowEnd(scrollTop < scrollHeight - clientHeight - 1);
|
|
5419
|
+
}
|
|
5420
|
+
}, [ref, orientation]);
|
|
5421
|
+
useIsomorphicLayoutEffect(sync);
|
|
5422
|
+
useResizeObserver(sync, [ref]);
|
|
5423
|
+
const fade = "calc(var(--spacing) * 7)";
|
|
5424
|
+
const direction = orientation === "vertical" ? "bottom" : "right";
|
|
5425
|
+
const mask = showStart || showEnd ? `linear-gradient(to ${direction}, ${showStart ? "transparent" : "#000"}, #000 ${showStart ? fade : "0"}, #000 ${showEnd ? `calc(100% - ${fade})` : "100%"}, ${showEnd ? "transparent" : "#000"})` : void 0;
|
|
5426
|
+
return { sync, style: mask ? { maskImage: mask, WebkitMaskImage: mask } : void 0 };
|
|
5427
|
+
}
|
|
4822
5428
|
var CodeHighlightContext = createContext(null);
|
|
4823
5429
|
function CodeHighlightProvider({ highlight, children }) {
|
|
4824
5430
|
return /* @__PURE__ */ jsx(CodeHighlightContext.Provider, { value: highlight, children });
|
|
@@ -4836,6 +5442,8 @@ function CodeBlock({
|
|
|
4836
5442
|
const highlighter = highlight === false ? null : highlight ?? contextHighlight;
|
|
4837
5443
|
const hasHeader = Boolean(filename);
|
|
4838
5444
|
const { copy, copied } = useCopy(code);
|
|
5445
|
+
const preRef = useRef(null);
|
|
5446
|
+
const fade = useEdgeFade(preRef, "horizontal");
|
|
4839
5447
|
if (prompt != null) {
|
|
4840
5448
|
return /* @__PURE__ */ jsxs(
|
|
4841
5449
|
"div",
|
|
@@ -4855,11 +5463,13 @@ function CodeBlock({
|
|
|
4855
5463
|
}
|
|
4856
5464
|
);
|
|
4857
5465
|
}
|
|
5466
|
+
const copyColumn = !hasHeader && showCopy;
|
|
4858
5467
|
return /* @__PURE__ */ jsxs(
|
|
4859
5468
|
"div",
|
|
4860
5469
|
{
|
|
4861
5470
|
className: cn(
|
|
4862
|
-
"
|
|
5471
|
+
"overflow-hidden rounded-md border border-border bg-muted/40",
|
|
5472
|
+
copyColumn && "flex items-start",
|
|
4863
5473
|
className
|
|
4864
5474
|
),
|
|
4865
5475
|
...props,
|
|
@@ -4867,17 +5477,21 @@ function CodeBlock({
|
|
|
4867
5477
|
hasHeader ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-b border-border px-4 py-2", children: [
|
|
4868
5478
|
/* @__PURE__ */ jsx("span", { className: "text-mono-caption text-muted-foreground", children: filename }),
|
|
4869
5479
|
showCopy ? /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Copy code", onClick: copy, className: "text-muted-foreground", children: /* @__PURE__ */ jsx(Icon, { name: copied ? "check" : "copy" }) }) : null
|
|
4870
|
-
] }) :
|
|
5480
|
+
] }) : null,
|
|
4871
5481
|
/* @__PURE__ */ jsx(
|
|
4872
5482
|
"pre",
|
|
4873
5483
|
{
|
|
5484
|
+
ref: preRef,
|
|
5485
|
+
onScroll: fade.sync,
|
|
5486
|
+
style: fade.style,
|
|
4874
5487
|
className: cn(
|
|
4875
5488
|
"overflow-x-auto overscroll-x-contain p-4 text-mono-md text-foreground scrollbar-quiet",
|
|
4876
|
-
|
|
5489
|
+
copyColumn && "min-w-0 flex-1 pe-2"
|
|
4877
5490
|
),
|
|
4878
5491
|
children: /* @__PURE__ */ jsx("code", { children: highlighter ? highlighter(code) : code })
|
|
4879
5492
|
}
|
|
4880
|
-
)
|
|
5493
|
+
),
|
|
5494
|
+
copyColumn ? /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Copy code", onClick: copy, className: "m-2 ms-0 shrink-0 text-muted-foreground", children: /* @__PURE__ */ jsx(Icon, { name: copied ? "check" : "copy" }) }) : null
|
|
4881
5495
|
]
|
|
4882
5496
|
}
|
|
4883
5497
|
);
|
|
@@ -5600,7 +6214,7 @@ function DestructiveActionModal({
|
|
|
5600
6214
|
confirmLabel = "Delete",
|
|
5601
6215
|
cancelLabel = "Cancel",
|
|
5602
6216
|
onConfirm,
|
|
5603
|
-
pending,
|
|
6217
|
+
pending: pending2,
|
|
5604
6218
|
confirmingLabel,
|
|
5605
6219
|
children,
|
|
5606
6220
|
confirmText
|
|
@@ -5609,8 +6223,8 @@ function DestructiveActionModal({
|
|
|
5609
6223
|
const [internalBusy, setInternalBusy] = useState(false);
|
|
5610
6224
|
const inFlight = useRef(false);
|
|
5611
6225
|
const cancelRef = useRef(null);
|
|
5612
|
-
const controlledPending =
|
|
5613
|
-
const busy =
|
|
6226
|
+
const controlledPending = pending2 !== void 0;
|
|
6227
|
+
const busy = pending2 ?? internalBusy;
|
|
5614
6228
|
useEffect(() => {
|
|
5615
6229
|
if (!open) {
|
|
5616
6230
|
setTyped("");
|
|
@@ -6804,4 +7418,4 @@ var attachmentMeta = {
|
|
|
6804
7418
|
]
|
|
6805
7419
|
};
|
|
6806
7420
|
|
|
6807
|
-
export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogTitle, AlertDialogTrigger, Attachment, Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, AvatarRoot, BADGE_APPEARANCES, BADGE_TONES, Badge, Bubble, BubbleReaction, BubbleReactions, Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardList, CardTitle, Code, CodeBlock, CodeHighlightProvider, Density, DensityProvider, DestructiveActionModal, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Entity, FIELD_INVALID, FIELD_SHELL, FIELD_SHELL_XS, Field, Form, HighlightGlide, Input, Label, MENU_ITEM_DESTRUCTIVE, MOBILE_FIELD_TIER, Menu, MenuCheckboxItem, MenuContent, MenuGroup, MenuGroupLabel, MenuItem, MenuPortal, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSubmenu, MenuSubmenuTrigger, MenuTrigger, Message, MotionProvider, OverflowMenu, Pill, Progress, ProgressIndicator, ProgressLabel, ProgressTrack, ProgressValue, Select, SelectContent, SelectGroup, SelectGroupLabel, SelectItem, SelectPortal, SelectSeparator, SelectTrigger, SelectValue, Separator, SimpleTooltip, Spinner, StatusDot, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Textarea, Tooltip, TooltipArrow, TooltipContent, TooltipPortal, TooltipProvider, TooltipTrigger, anchoredListScroll, anchoredScroll, attachmentMeta, avatarGroupVariants, avatarMeta, avatarVariants, badgeMeta, badgeVariants, bubbleMeta, buttonMeta, buttonVariants, cardMeta, codeBlockMeta, codeMeta, destructiveActionModalMeta, dialogMeta, entityMeta, formMeta, inputMeta, labelMeta, menuMeta, mergeRefs, messageMeta, overflowMenuMeta, pillVariants, progressMeta, progressTrackVariants, selectMeta, separatorMeta, setRef, spinnerMeta, statusDotMeta, statusDotVariants, switchMeta, tableMeta, textareaMeta, tooltipMeta, trimLabel, useAnchoredDensity, useCopy, useDensity, useIsomorphicLayoutEffect, useMotion, useReducedMotion, useResizeObserver, useScrollActivity, useTypeTier, withPortalThemeScope };
|
|
7421
|
+
export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogTitle, AlertDialogTrigger, Attachment, Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, AvatarRoot, BADGE_APPEARANCES, BADGE_TONES, Badge, Bubble, BubbleReaction, BubbleReactions, Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardList, CardTitle, Code, CodeBlock, CodeHighlightProvider, Density, DensityProvider, DestructiveActionModal, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Entity, FIELD_INVALID, FIELD_SHELL, FIELD_SHELL_XS, Field, Form, GradientArt, HighlightGlide, Input, Label, MENU_ITEM_DESTRUCTIVE, MOBILE_FIELD_TIER, Menu, MenuCheckboxItem, MenuContent, MenuGroup, MenuGroupLabel, MenuItem, MenuPortal, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSubmenu, MenuSubmenuTrigger, MenuTrigger, Message, MotionProvider, OverflowMenu, Pill, Progress, ProgressIndicator, ProgressLabel, ProgressTrack, ProgressValue, Select, SelectContent, SelectGroup, SelectGroupLabel, SelectItem, SelectPortal, SelectSeparator, SelectTrigger, SelectValue, Separator, SimpleTooltip, Spinner, StatusDot, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Textarea, Tooltip, TooltipArrow, TooltipContent, TooltipPortal, TooltipProvider, TooltipTrigger, anchoredListScroll, anchoredScroll, attachmentMeta, avatarGroupVariants, avatarMeta, avatarVariants, badgeMeta, badgeVariants, bubbleMeta, buttonMeta, buttonVariants, cardMeta, codeBlockMeta, codeMeta, destructiveActionModalMeta, dialogMeta, entityMeta, formMeta, gradientArtMeta, inputMeta, labelMeta, menuMeta, mergeRefs, messageMeta, overflowMenuMeta, pillVariants, progressMeta, progressTrackVariants, selectMeta, separatorMeta, setRef, spinnerMeta, statusDotMeta, statusDotVariants, switchMeta, tableMeta, textareaMeta, tooltipMeta, trimLabel, useAnchoredDensity, useCopy, useDensity, useEdgeFade, useIsomorphicLayoutEffect, useMotion, useReducedMotion, useResizeObserver, useScrollActivity, useTypeTier, withPortalThemeScope };
|