@sakaniui/react 0.8.9 → 0.8.10
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 +1 -1
- package/CHANGELOG.md +41 -0
- package/README.md +29 -3
- package/bin/sakaniui-mcp.mjs +126 -31
- package/dist/icon-index.json +1 -1
- package/dist/lib/ChartTooltip.d.ts +20 -0
- package/dist/lib/LiquidGlass.d.ts +93 -0
- package/dist/lib/SakaniLogo.d.ts +3 -0
- package/dist/lib/chartPalette.d.ts +12 -0
- package/dist/lib/getContrastColor.d.ts +23 -0
- package/dist/lib/iconStrokeWidth.d.ts +13 -0
- package/dist/lib/useChartTokens.d.ts +31 -0
- package/dist/lib/useHoverHighlight.d.ts +17 -0
- package/dist/lib/usePortalThemeClass.d.ts +31 -0
- package/dist/lib/useThemeTick.d.ts +10 -0
- package/dist/manifest.json +212 -32
- package/package.json +4 -4
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface ChartTooltipPayloadEntry {
|
|
3
|
+
name?: string;
|
|
4
|
+
value?: number | string;
|
|
5
|
+
color?: string;
|
|
6
|
+
fill?: string;
|
|
7
|
+
payload?: {
|
|
8
|
+
fill?: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface ChartTooltipProps {
|
|
13
|
+
active?: boolean;
|
|
14
|
+
payload?: ChartTooltipPayloadEntry[];
|
|
15
|
+
label?: string;
|
|
16
|
+
/** Custom value formatter, e.g. for percentages. */
|
|
17
|
+
formatter?: (value: ChartTooltipPayloadEntry['value'], name: ChartTooltipPayloadEntry['name']) => React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
export declare const ChartTooltip: React.FC<ChartTooltipProps>;
|
|
20
|
+
export default ChartTooltip;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export type LiquidGlassVariant = 'regular' | 'clear';
|
|
3
|
+
/** How much of the backdrop shows through. 'auto' follows the variant
|
|
4
|
+
* (regular 66%, clear 28%); 'subtle' is Figma's glass/bg-subtle (5%), the
|
|
5
|
+
* fill of a full-bleed overlay; 'none' is the lens alone. */
|
|
6
|
+
export type LiquidGlassTint = 'auto' | 'regular' | 'clear' | 'subtle' | 'none';
|
|
7
|
+
/** Figma's Glass effect properties, in Figma's units. */
|
|
8
|
+
export interface LiquidGlassEffect {
|
|
9
|
+
/** 0–1 */
|
|
10
|
+
refraction: number;
|
|
11
|
+
/** px */
|
|
12
|
+
depth: number;
|
|
13
|
+
/** 0–1 */
|
|
14
|
+
dispersion: number;
|
|
15
|
+
/** Figma's frost radius */
|
|
16
|
+
frost: number;
|
|
17
|
+
/** 0–1 */
|
|
18
|
+
lightIntensity: number;
|
|
19
|
+
/** degrees, clockwise from the top: -45 = light from the top-left */
|
|
20
|
+
lightAngle: number;
|
|
21
|
+
}
|
|
22
|
+
export interface LiquidBackdropProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
23
|
+
/** The image behind the glass, cover-fitted. */
|
|
24
|
+
src: string;
|
|
25
|
+
/** background-position of the image. Default 'center'. */
|
|
26
|
+
position?: string;
|
|
27
|
+
/** A color laid over the image, in the backdrop every lens sees too (a scrim in
|
|
28
|
+
* dark mode, Figma's 5% overlay fill in light). Any CSS color, var() included. */
|
|
29
|
+
veil?: string;
|
|
30
|
+
}
|
|
31
|
+
/** The photo (or any image) a liquid-glass UI sits on. Lenses inside refract the
|
|
32
|
+
* image itself instead of what the browser painted below them. */
|
|
33
|
+
export declare const LiquidBackdrop: React.ForwardRefExoticComponent<LiquidBackdropProps & React.RefAttributes<HTMLDivElement>>;
|
|
34
|
+
/** Re-align every lens's backdrop copy right now. Call it after moving lenses
|
|
35
|
+
* from JavaScript (a spring, a drag) in the same frame, so the photo inside a
|
|
36
|
+
* lens never trails the lens by a frame. */
|
|
37
|
+
export declare function syncLiquidBackdrop(): void;
|
|
38
|
+
export interface UseLiquidGlassOptions {
|
|
39
|
+
enabled?: boolean;
|
|
40
|
+
/** 'off' forces the frosted fallback (e.g. to preview Safari in Chrome). */
|
|
41
|
+
refraction?: 'auto' | 'off';
|
|
42
|
+
/** Re-read the --liquid-* properties when this changes (e.g. an inline effect override). */
|
|
43
|
+
watch?: string;
|
|
44
|
+
/** Inside a <LiquidBackdrop>, refract its image (default). Pass false for an
|
|
45
|
+
* element that floats over other UI (Modal's card sits over a scrim). */
|
|
46
|
+
source?: boolean;
|
|
47
|
+
/** Inside a <LiquidBackdrop>: 'auto' (default) bakes lenses bigger than 300×300
|
|
48
|
+
* into a canvas once (they don't move); false keeps the filter live (a big lens
|
|
49
|
+
* you animate or drag); true always bakes. */
|
|
50
|
+
bake?: boolean | 'auto';
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The material as a hook, for components that own their element (Modal's
|
|
54
|
+
* card). Spread `props` onto the element and render `filter` inside it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function useLiquidGlass(ref: React.RefObject<HTMLElement | null>, { enabled, refraction, watch, source, bake }?: UseLiquidGlassOptions): {
|
|
57
|
+
filter: React.JSX.Element | null;
|
|
58
|
+
refracting: boolean;
|
|
59
|
+
props: {
|
|
60
|
+
readonly 'data-surface': "liquid";
|
|
61
|
+
readonly 'data-refraction': "source" | "off" | "on";
|
|
62
|
+
readonly style: {
|
|
63
|
+
backdropFilter: string;
|
|
64
|
+
} | undefined;
|
|
65
|
+
readonly onPointerMove: (e: React.PointerEvent<HTMLElement>) => void;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
export interface LiquidGlassProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
69
|
+
/** regular: text-safe tint (panels, sidebars, modals). clear: icons and large labels only. */
|
|
70
|
+
variant?: LiquidGlassVariant;
|
|
71
|
+
/** How much of the backdrop shows through. Default 'auto' (follows `variant`). */
|
|
72
|
+
tint?: LiquidGlassTint;
|
|
73
|
+
/** Corner radius in px. Default 20. */
|
|
74
|
+
radius?: number;
|
|
75
|
+
/** 'off' forces the frosted fallback. */
|
|
76
|
+
refraction?: 'auto' | 'off';
|
|
77
|
+
/** Override any of Figma's Glass properties for this element, in Figma's units
|
|
78
|
+
* (e.g. { refraction: 0.8, depth: 20, dispersion: 0.4, frost: 1 }). Defaults
|
|
79
|
+
* come from the variant's --liquid-* tokens. */
|
|
80
|
+
effect?: Partial<LiquidGlassEffect>;
|
|
81
|
+
/** Inside a <LiquidBackdrop>: true (default) refracts the backdrop image;
|
|
82
|
+
* false bends whatever is painted below instead (UI under a slider knob). */
|
|
83
|
+
source?: boolean;
|
|
84
|
+
/** 'auto' (default): inside a LiquidBackdrop, lenses over 300×300 bake their glass
|
|
85
|
+
* once (fast; for surfaces that stay put). false: always live (a big lens that moves). */
|
|
86
|
+
bake?: boolean | 'auto';
|
|
87
|
+
/** Squish slightly when pressed (buttons, toolbar pills). */
|
|
88
|
+
interactive?: boolean;
|
|
89
|
+
}
|
|
90
|
+
export declare const LiquidGlass: React.ForwardRefExoticComponent<LiquidGlassProps & React.RefAttributes<HTMLDivElement>>;
|
|
91
|
+
/** Class names for components that apply the material via the hook. */
|
|
92
|
+
export declare const liquidGlassClass: (variant?: LiquidGlassVariant, tint?: LiquidGlassTint) => string;
|
|
93
|
+
export default LiquidGlass;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Real values of --color-chart-1..6, used only when getComputedStyle can't
|
|
3
|
+
* run — which in practice means server-side rendering, where the charts paint
|
|
4
|
+
* once before useThemeTick's mount bump re-reads the live tokens.
|
|
5
|
+
*
|
|
6
|
+
* Indexed rather than a single value on purpose: every chart used to fall
|
|
7
|
+
* back to chart-1 for all five slots, so a server-rendered multi-series chart
|
|
8
|
+
* painted every line, slice and ring the same orange until hydration.
|
|
9
|
+
*
|
|
10
|
+
* Keep in sync with src/styles/tokens.css.
|
|
11
|
+
*/
|
|
12
|
+
export declare const CHART_PALETTE_FALLBACK: string[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Given any valid CSS color string, returns whichever of this system's own
|
|
3
|
+
* fixed light/dark icon colors (fg/on-inverse #FAFAF9 vs fg/default
|
|
4
|
+
* #141414) has the higher WCAG contrast ratio against it.
|
|
5
|
+
*
|
|
6
|
+
* Used for icon/text glyphs drawn on top of a consumer-supplied background
|
|
7
|
+
* color (e.g. ColorSwatch's checkmark) -- a flat "always white" choice
|
|
8
|
+
* fails contrast on light swatch colors (confirmed: a white check on
|
|
9
|
+
* #E0D8D1 is not accessible), and a flat luminance>0.5 threshold is less
|
|
10
|
+
* accurate than actually comparing both candidates' real contrast ratios,
|
|
11
|
+
* so this does the full WCAG comparison instead.
|
|
12
|
+
*
|
|
13
|
+
* Hex and rgb() are parsed directly (identically on server and client);
|
|
14
|
+
* anything else parses via a 1x1 canvas fillStyle instead of hand-rolling a hex/rgb/hsl
|
|
15
|
+
* parser -- the canvas 2D context's color parser already accepts every
|
|
16
|
+
* valid CSS color syntax (hex, rgb(), hsl(), named colors, ...) and
|
|
17
|
+
* normalizes it to concrete RGB, so this works for any `color` a consumer
|
|
18
|
+
* might pass without this library needing its own parser.
|
|
19
|
+
*/
|
|
20
|
+
/** Returns fg/on-inverse (#fafaf9) or fg/default (#141414), whichever
|
|
21
|
+
* contrasts better against `backgroundColor`. Falls back to fg/on-inverse
|
|
22
|
+
* if run outside a browser (canvas unavailable, e.g. SSR). */
|
|
23
|
+
export declare const getContrastColor: (backgroundColor: string) => string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lucide icons are always drawn on a fixed 24-unit grid regardless of the
|
|
3
|
+
* requested pixel `size` -- `strokeWidth` is defined in that same 24-unit
|
|
4
|
+
* space, so rendering below 24px visually scales a stroke down
|
|
5
|
+
* proportionally (e.g. strokeWidth={1.5} at size={16} renders as an
|
|
6
|
+
* effective ~1px line), noticeably thinner than Figma's own same-size-
|
|
7
|
+
* native icon exports, which have no such scaling.
|
|
8
|
+
*
|
|
9
|
+
* Scaling strokeWidth up by 24/size compensates so the rendered stroke
|
|
10
|
+
* actually measures `targetPx`, matching Figma. Every icon in this design
|
|
11
|
+
* system is exported at 1.5px, hence the default.
|
|
12
|
+
*/
|
|
13
|
+
export declare const iconStrokeWidth: (size: number, targetPx?: number) => number;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a chart's color tokens against the chart's OWN element, and
|
|
3
|
+
* re-renders whenever any scope enclosing it changes theme.
|
|
4
|
+
*
|
|
5
|
+
* Recharts needs real color strings, not `var(--…)`, so these have to be read
|
|
6
|
+
* with getComputedStyle. Two things that looked equivalent were not:
|
|
7
|
+
*
|
|
8
|
+
* 1. Reading from document.documentElement ignores any scope between <html>
|
|
9
|
+
* and the chart. Both `.dark` and `.force-light` redeclare the whole token
|
|
10
|
+
* set on a container -- that's the entire point of them: a docs preview
|
|
11
|
+
* panel showing a light component while the site around it is dark, or one
|
|
12
|
+
* dashboard demo toggled independently of the page. Read from <html>, such
|
|
13
|
+
* a chart painted the OUTER theme's colors on the INNER theme's
|
|
14
|
+
* background: dark grid lines on a white panel.
|
|
15
|
+
*
|
|
16
|
+
* 2. Watching only <html>'s class misses those same containers. Flipping a
|
|
17
|
+
* preview panel to dark changes a wrapper div's class, not <html>'s, and
|
|
18
|
+
* the chart is passed down as `children` — a stable element React reuses
|
|
19
|
+
* rather than re-rendering — so nothing re-read the tokens and the chart
|
|
20
|
+
* kept the previous theme's colors. Every ancestor is observed, not just
|
|
21
|
+
* the root.
|
|
22
|
+
*
|
|
23
|
+
* The mount tick matters on its own: under SSR there is no getComputedStyle,
|
|
24
|
+
* so the server paints each chart's hardcoded fallbacks, and React treats
|
|
25
|
+
* differing attributes on hydration as "won't be patched up". Bumping once on
|
|
26
|
+
* mount is what replaces those fallbacks with real tokens — and it is also
|
|
27
|
+
* the point at which the ref is finally attached.
|
|
28
|
+
*/
|
|
29
|
+
export declare function useChartTokens(element: {
|
|
30
|
+
current: HTMLElement | null;
|
|
31
|
+
}): (name: string) => string | undefined;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export declare function useHoverHighlight<T extends HTMLElement = HTMLDivElement>(): {
|
|
3
|
+
ref: (el: T | null) => void;
|
|
4
|
+
groupProps: {
|
|
5
|
+
'data-hover-group': string;
|
|
6
|
+
onMouseOver: (e: React.MouseEvent) => void;
|
|
7
|
+
onMouseLeave: () => void;
|
|
8
|
+
};
|
|
9
|
+
highlight: React.JSX.Element;
|
|
10
|
+
showItem: (item: HTMLElement | null) => void;
|
|
11
|
+
};
|
|
12
|
+
export interface HoverGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
/** Wraps any set of `data-hover-item` children (ListItem, MenuItem, ...)
|
|
16
|
+
* in a flowing hover group, for compositions with no container of their own. */
|
|
17
|
+
export declare const HoverGroup: React.FC<HoverGroupProps>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the theme-scope class enclosing `anchor`, so a portaled surface can
|
|
3
|
+
* re-apply it to itself.
|
|
4
|
+
*
|
|
5
|
+
* Floating surfaces (a Select's listbox, a Modal) portal to <body> so they
|
|
6
|
+
* can position with `fixed` without being clipped by an ancestor's overflow.
|
|
7
|
+
* That works for layout, but it moves them out from under any `.dark` or
|
|
8
|
+
* `.force-light` container: the panel then inherits <html>'s tokens instead
|
|
9
|
+
* of the ones in effect where the trigger actually lives. In the docs site,
|
|
10
|
+
* whose preview panels render a light component inside a dark page, that
|
|
11
|
+
* showed up as a dark dropdown opening over a white panel.
|
|
12
|
+
*
|
|
13
|
+
* Copying the class onto the portaled element keeps the body portal (and its
|
|
14
|
+
* positioning) while restoring the tokens the trigger sees.
|
|
15
|
+
*
|
|
16
|
+
* Returns '' when no scope encloses the anchor, which is the common case and
|
|
17
|
+
* correctly means "inherit from <html>".
|
|
18
|
+
*/
|
|
19
|
+
export declare function usePortalThemeClass(anchor: {
|
|
20
|
+
current: HTMLElement | null;
|
|
21
|
+
}, active: boolean): string;
|
|
22
|
+
/**
|
|
23
|
+
* Same idea for the Surface layer: returns the `data-surface` value
|
|
24
|
+
* ("solid" | "glass") in effect where `anchor` lives, so a portaled surface
|
|
25
|
+
* can re-apply it. Without it, a Modal opened from inside a glass area would
|
|
26
|
+
* portal out of it and render solid. Returns undefined (no attribute) when
|
|
27
|
+
* no surface scope encloses the anchor -- i.e. the Solid default.
|
|
28
|
+
*/
|
|
29
|
+
export declare function usePortalSurface(anchor: {
|
|
30
|
+
current: HTMLElement | null;
|
|
31
|
+
}, active: boolean): string | undefined;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chart components read color tokens once per render via getComputedStyle
|
|
3
|
+
* (Recharts needs real color strings, not CSS vars). That read is frozen at
|
|
4
|
+
* render time, so toggling the app's .dark class on <html> after a chart has
|
|
5
|
+
* already mounted leaves it showing stale (light-mode) colors until it
|
|
6
|
+
* happens to re-render for an unrelated reason. This watches <html>'s class
|
|
7
|
+
* attribute and bumps a counter on change, so a chart calling this hook
|
|
8
|
+
* re-renders — and re-reads its colors — right when the theme flips.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useThemeTick(): number;
|