@fairmint/ui 0.2.31 → 0.2.32
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/dist/components/specific/EquityRibbonChart/EquityRibbonChart.d.ts +30 -0
- package/dist/components/specific/EquityRibbonChart/EquityRibbonChart.d.ts.map +1 -0
- package/dist/components/specific/EquityRibbonChart/FairmintRibbonMark.d.ts +23 -0
- package/dist/components/specific/EquityRibbonChart/FairmintRibbonMark.d.ts.map +1 -0
- package/dist/components/specific/EquityRibbonChart/index.d.ts +9 -0
- package/dist/components/specific/EquityRibbonChart/index.d.ts.map +1 -0
- package/dist/components/specific/EquityRibbonChart/ribbonGeometry.d.ts +55 -0
- package/dist/components/specific/EquityRibbonChart/ribbonGeometry.d.ts.map +1 -0
- package/dist/components/specific/EquityRibbonChart/ribbonTheme.d.ts +13 -0
- package/dist/components/specific/EquityRibbonChart/ribbonTheme.d.ts.map +1 -0
- package/dist/fairmint-ui.cjs +529 -0
- package/dist/fairmint-ui.cjs.map +1 -1
- package/dist/fairmint-ui.js +529 -0
- package/dist/fairmint-ui.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/styles.css +85 -0
- package/dist/theme/ribbonChartColors.d.ts +31 -0
- package/dist/theme/ribbonChartColors.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/fairmint-ui.js
CHANGED
|
@@ -44998,6 +44998,526 @@ function EquityGrantCard({
|
|
|
44998
44998
|
}
|
|
44999
44999
|
);
|
|
45000
45000
|
}
|
|
45001
|
+
const DEFAULT_RIBBON_CONFIG = {
|
|
45002
|
+
baseline: 0.82,
|
|
45003
|
+
xEndStagger: 9e-3,
|
|
45004
|
+
xEndDraw: [0.84, 0.849, 0.858, 0.867, 0.876],
|
|
45005
|
+
xEndCurve: 0.914,
|
|
45006
|
+
xStart: [0.05, 0.19, 0.34, 0.5, 0.66],
|
|
45007
|
+
kArr: [1.7, 2.4, 3.1, 3.9, 4.9],
|
|
45008
|
+
V: [0.082, 0.102, 0.132, 0.172, 0.21],
|
|
45009
|
+
vMin: [0.038, 0.04, 0.042, 0.044, 0.046],
|
|
45010
|
+
xStem: [0.05, 0.04, 0.035, 0.03, 0.025],
|
|
45011
|
+
labelX: [0.08, 0.24, 0.4, 0.56, 0.8],
|
|
45012
|
+
labelAboveGap: [0.034, 0.03, 0.028, 0.024],
|
|
45013
|
+
labelLeftGap: 0.055,
|
|
45014
|
+
labelLiquidityGap: 0.016,
|
|
45015
|
+
labelNudge: [
|
|
45016
|
+
[0, 0],
|
|
45017
|
+
[0, 0],
|
|
45018
|
+
[0, 0],
|
|
45019
|
+
[0, 0],
|
|
45020
|
+
[0, -0.012]
|
|
45021
|
+
],
|
|
45022
|
+
samples: 72
|
|
45023
|
+
};
|
|
45024
|
+
const MARK_RIBBON_RIGHT_EDGE = 0.936;
|
|
45025
|
+
const MARK_FIT_HORIZONTAL_COMPRESS = 0.78;
|
|
45026
|
+
const MARK_RIBBON_CONFIG = {
|
|
45027
|
+
...DEFAULT_RIBBON_CONFIG,
|
|
45028
|
+
baseline: 0.97,
|
|
45029
|
+
xEndDraw: [
|
|
45030
|
+
MARK_RIBBON_RIGHT_EDGE,
|
|
45031
|
+
MARK_RIBBON_RIGHT_EDGE,
|
|
45032
|
+
MARK_RIBBON_RIGHT_EDGE,
|
|
45033
|
+
MARK_RIBBON_RIGHT_EDGE,
|
|
45034
|
+
MARK_RIBBON_RIGHT_EDGE
|
|
45035
|
+
],
|
|
45036
|
+
xEndCurve: 0.94,
|
|
45037
|
+
xStart: [0.08, 0.2, 0.32, 0.44, 0.56],
|
|
45038
|
+
xStem: [0.028, 0.022, 0.018, 0.015, 0.012]
|
|
45039
|
+
};
|
|
45040
|
+
function labelGapAbove(i, config2) {
|
|
45041
|
+
const lastBand = config2.xStart.length - 1;
|
|
45042
|
+
if (i === lastBand) return config2.labelLiquidityGap;
|
|
45043
|
+
return config2.labelAboveGap[i] ?? config2.labelLiquidityGap;
|
|
45044
|
+
}
|
|
45045
|
+
function mergeBounds(a, b) {
|
|
45046
|
+
return {
|
|
45047
|
+
minX: Math.min(a.minX, b.minX),
|
|
45048
|
+
minY: Math.min(a.minY, b.minY),
|
|
45049
|
+
maxX: Math.max(a.maxX, b.maxX),
|
|
45050
|
+
maxY: Math.max(a.maxY, b.maxY)
|
|
45051
|
+
};
|
|
45052
|
+
}
|
|
45053
|
+
function transformPathD(d, scaleX, scaleY, tx, ty) {
|
|
45054
|
+
return d.replace(/(-?[\d.]+),(-?[\d.]+)/g, (_, x, y) => {
|
|
45055
|
+
const px2 = Number(x) * scaleX + tx;
|
|
45056
|
+
const py = Number(y) * scaleY + ty;
|
|
45057
|
+
return `${px2.toFixed(1)},${py.toFixed(1)}`;
|
|
45058
|
+
});
|
|
45059
|
+
}
|
|
45060
|
+
function computeMarkFitTransform(bounds, width, height, paddingRatio) {
|
|
45061
|
+
const pad = paddingRatio * Math.min(width, height);
|
|
45062
|
+
const bw = bounds.maxX - bounds.minX;
|
|
45063
|
+
const bh = bounds.maxY - bounds.minY;
|
|
45064
|
+
if (bw <= 0 || bh <= 0) {
|
|
45065
|
+
return { scaleX: 1, scaleY: 1, tx: 0, ty: 0 };
|
|
45066
|
+
}
|
|
45067
|
+
const scaleY = (height - pad * 2) / bh;
|
|
45068
|
+
let scaleX = scaleY * MARK_FIT_HORIZONTAL_COMPRESS;
|
|
45069
|
+
if (bw * scaleX > width - pad * 2) {
|
|
45070
|
+
scaleX = (width - pad * 2) / bw;
|
|
45071
|
+
}
|
|
45072
|
+
const tx = (width - bw * scaleX) / 2 - bounds.minX * scaleX;
|
|
45073
|
+
const ty = (height - bh * scaleY) / 2 - bounds.minY * scaleY;
|
|
45074
|
+
return { scaleX, scaleY, tx, ty };
|
|
45075
|
+
}
|
|
45076
|
+
function valAt(i, xf, config2) {
|
|
45077
|
+
const { xStart, xEndCurve, kArr, V, vMin, xStem } = config2;
|
|
45078
|
+
const xLo = xStart[i] - xStem[i];
|
|
45079
|
+
if (xf < xLo || xf > xEndCurve) return 0;
|
|
45080
|
+
if (xf < xStart[i]) return vMin[i];
|
|
45081
|
+
const u = (xf - xStart[i]) / (xEndCurve - xStart[i]);
|
|
45082
|
+
const grow = (Math.exp(kArr[i] * u) - 1) / (Math.exp(kArr[i]) - 1);
|
|
45083
|
+
return vMin[i] + (V[i] - vMin[i]) * grow;
|
|
45084
|
+
}
|
|
45085
|
+
function cumBelow(i, xf, config2) {
|
|
45086
|
+
let sum = 0;
|
|
45087
|
+
for (let j = 0; j < i; j++) sum += valAt(j, xf, config2);
|
|
45088
|
+
return sum;
|
|
45089
|
+
}
|
|
45090
|
+
function buildBandPath(i, width, height, config2) {
|
|
45091
|
+
const { xStart, xEndCurve, xStem, baseline } = config2;
|
|
45092
|
+
const samples = Math.max(1, Math.floor(config2.samples));
|
|
45093
|
+
const xLo = xStart[i] - xStem[i];
|
|
45094
|
+
const top = [];
|
|
45095
|
+
const bot = [];
|
|
45096
|
+
for (let s = 0; s <= samples; s++) {
|
|
45097
|
+
const xf = xLo + (xEndCurve - xLo) * (s / samples);
|
|
45098
|
+
const below = cumBelow(i, xf, config2);
|
|
45099
|
+
const v = valAt(i, xf, config2);
|
|
45100
|
+
const x = xf * width;
|
|
45101
|
+
top.push([x, (baseline - below - v) * height]);
|
|
45102
|
+
bot.push([x, (baseline - below) * height]);
|
|
45103
|
+
}
|
|
45104
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
45105
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
45106
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
45107
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
45108
|
+
for (const [x, y] of [...top, ...bot]) {
|
|
45109
|
+
minX = Math.min(minX, x);
|
|
45110
|
+
minY = Math.min(minY, y);
|
|
45111
|
+
maxX = Math.max(maxX, x);
|
|
45112
|
+
maxY = Math.max(maxY, y);
|
|
45113
|
+
}
|
|
45114
|
+
let d = `M${top[0][0].toFixed(1)},${top[0][1].toFixed(1)}`;
|
|
45115
|
+
for (let s = 1; s <= samples; s++) {
|
|
45116
|
+
d += ` L${top[s][0].toFixed(1)},${top[s][1].toFixed(1)}`;
|
|
45117
|
+
}
|
|
45118
|
+
d += ` L${bot[samples][0].toFixed(1)},${bot[samples][1].toFixed(1)}`;
|
|
45119
|
+
for (let s = samples - 1; s >= 0; s--) {
|
|
45120
|
+
d += ` L${bot[s][0].toFixed(1)},${bot[s][1].toFixed(1)}`;
|
|
45121
|
+
}
|
|
45122
|
+
return { d: `${d} Z`, bounds: { minX, minY, maxX, maxY } };
|
|
45123
|
+
}
|
|
45124
|
+
function buildLabel(i, text, _width, _height, config2, offsetXNorm) {
|
|
45125
|
+
const { baseline, xStart, xStem, labelNudge } = config2;
|
|
45126
|
+
const xf = xStart[i] - xStem[i] + offsetXNorm;
|
|
45127
|
+
const below = cumBelow(i, xf, config2);
|
|
45128
|
+
const v = valAt(i, xf, config2);
|
|
45129
|
+
const yTop = baseline - below - v;
|
|
45130
|
+
const [nudgeX, nudgeY] = labelNudge[i];
|
|
45131
|
+
return {
|
|
45132
|
+
index: i,
|
|
45133
|
+
text,
|
|
45134
|
+
leftPct: (xf + nudgeX) * 100,
|
|
45135
|
+
topPct: (yTop - labelGapAbove(i, config2) + nudgeY) * 100,
|
|
45136
|
+
placement: "start"
|
|
45137
|
+
};
|
|
45138
|
+
}
|
|
45139
|
+
function clampBandCount(count2, max2 = 5) {
|
|
45140
|
+
if (!Number.isFinite(count2)) return max2;
|
|
45141
|
+
return Math.min(max2, Math.max(1, Math.round(count2)));
|
|
45142
|
+
}
|
|
45143
|
+
function buildRibbonGeometry(width, height, labels, config2 = DEFAULT_RIBBON_CONFIG, bandCount = config2.xStart.length, layout = "hero") {
|
|
45144
|
+
const totalBands = config2.xStart.length;
|
|
45145
|
+
const visibleBands = clampBandCount(bandCount, totalBands);
|
|
45146
|
+
if (width <= 0 || height <= 0) {
|
|
45147
|
+
return null;
|
|
45148
|
+
}
|
|
45149
|
+
const paths = [];
|
|
45150
|
+
const clipWidthPx = [];
|
|
45151
|
+
let bounds = null;
|
|
45152
|
+
for (let i = 0; i < visibleBands; i++) {
|
|
45153
|
+
const band = buildBandPath(i, width, height, config2);
|
|
45154
|
+
paths.push(band.d);
|
|
45155
|
+
clipWidthPx.push(config2.xEndDraw[i] * width);
|
|
45156
|
+
bounds = bounds ? mergeBounds(bounds, band.bounds) : band.bounds;
|
|
45157
|
+
}
|
|
45158
|
+
let fitPaths = paths;
|
|
45159
|
+
let fitClips = clipWidthPx;
|
|
45160
|
+
let offsetXNorm = 0;
|
|
45161
|
+
if (bounds) {
|
|
45162
|
+
if (layout === "mark") {
|
|
45163
|
+
const { scaleX, scaleY, tx, ty } = computeMarkFitTransform(bounds, width, height, 0.05);
|
|
45164
|
+
fitPaths = paths.map((p) => transformPathD(p, scaleX, scaleY, tx, ty));
|
|
45165
|
+
const alignedClipRight = MARK_RIBBON_RIGHT_EDGE * width * scaleX + tx;
|
|
45166
|
+
fitClips = clipWidthPx.map(() => alignedClipRight);
|
|
45167
|
+
offsetXNorm = tx / width;
|
|
45168
|
+
} else if (layout === "hero") {
|
|
45169
|
+
const bw = bounds.maxX - bounds.minX;
|
|
45170
|
+
const tx = (width - bw) / 2 - bounds.minX;
|
|
45171
|
+
fitPaths = paths.map((p) => transformPathD(p, 1, 1, tx, 0));
|
|
45172
|
+
fitClips = clipWidthPx.map((w) => w + tx);
|
|
45173
|
+
offsetXNorm = tx / width;
|
|
45174
|
+
}
|
|
45175
|
+
}
|
|
45176
|
+
const paddedLabels = Array.from({ length: visibleBands }, (_, i) => labels[i] ?? "");
|
|
45177
|
+
const builtLabels = paddedLabels.map(
|
|
45178
|
+
(text, i) => buildLabel(i, text, width, height, config2, offsetXNorm)
|
|
45179
|
+
);
|
|
45180
|
+
return {
|
|
45181
|
+
paths: fitPaths,
|
|
45182
|
+
clipWidthPx: fitClips,
|
|
45183
|
+
labels: builtLabels,
|
|
45184
|
+
width,
|
|
45185
|
+
height,
|
|
45186
|
+
bandCount: visibleBands
|
|
45187
|
+
};
|
|
45188
|
+
}
|
|
45189
|
+
function easePower1InOut(t) {
|
|
45190
|
+
const p = Math.max(0, Math.min(1, t));
|
|
45191
|
+
return p < 0.5 ? 2 * p * p : 1 - (-2 * p + 2) ** 2 / 2;
|
|
45192
|
+
}
|
|
45193
|
+
function easePower2Out(t) {
|
|
45194
|
+
const p = Math.max(0, Math.min(1, t));
|
|
45195
|
+
return 1 - (1 - p) ** 2;
|
|
45196
|
+
}
|
|
45197
|
+
function ribbonLabelRevealTime(labelIndex, duration2, config2 = DEFAULT_RIBBON_CONFIG) {
|
|
45198
|
+
return Math.min(duration2, config2.labelX[labelIndex] * duration2 + 0.25);
|
|
45199
|
+
}
|
|
45200
|
+
const ribbonChartLabelDefault = "#FFFFFF";
|
|
45201
|
+
const ribbonChartSurface = {
|
|
45202
|
+
white: "#FFFFFF",
|
|
45203
|
+
black: "#0D1023"
|
|
45204
|
+
};
|
|
45205
|
+
const ribbonBandGradientStops = [
|
|
45206
|
+
{ idSuffix: "0", start: "#33198C", end: "#5B2BF0" },
|
|
45207
|
+
{ idSuffix: "1", start: "#4A22C8", end: "#7A3DF5" },
|
|
45208
|
+
{ idSuffix: "2", start: "#6A32E8", end: "#9A6BFF" },
|
|
45209
|
+
{ idSuffix: "3", start: "#8A52F5", end: "#BD84FF" },
|
|
45210
|
+
{ idSuffix: "4", start: "#A86BFF", end: "#E6ABFF" }
|
|
45211
|
+
];
|
|
45212
|
+
const RIBBON_BACKGROUND_CLASS = {
|
|
45213
|
+
white: "fairmint-equity-ribbon--bg-white",
|
|
45214
|
+
black: "fairmint-equity-ribbon--bg-black",
|
|
45215
|
+
transparent: "fairmint-equity-ribbon--bg-transparent"
|
|
45216
|
+
};
|
|
45217
|
+
const DEFAULT_RIBBON_LABELS = [
|
|
45218
|
+
"Cap Table",
|
|
45219
|
+
"Fundraising",
|
|
45220
|
+
"Grants",
|
|
45221
|
+
"Secondaries",
|
|
45222
|
+
"Liquidity"
|
|
45223
|
+
];
|
|
45224
|
+
const RIBBON_BAND_GRADIENTS = ribbonBandGradientStops;
|
|
45225
|
+
const RIBBON_SURFACE_CSS_VARS = {
|
|
45226
|
+
"--fairmint-ribbon-surface-white": ribbonChartSurface.white,
|
|
45227
|
+
"--fairmint-ribbon-surface-black": ribbonChartSurface.black
|
|
45228
|
+
};
|
|
45229
|
+
const REVEAL_DURATION_MS = 2300;
|
|
45230
|
+
const REVEAL_DELAY_MS = 420;
|
|
45231
|
+
function labelAnchorTransform(_placement, yOffsetPx) {
|
|
45232
|
+
return `translate(0, calc(-100% + ${yOffsetPx}px))`;
|
|
45233
|
+
}
|
|
45234
|
+
function labelClassName(_placement) {
|
|
45235
|
+
return "fairmint-equity-ribbon__label fairmint-equity-ribbon__label--start";
|
|
45236
|
+
}
|
|
45237
|
+
function resolveGradients(gradients, bandCount) {
|
|
45238
|
+
const source = gradients ?? RIBBON_BAND_GRADIENTS;
|
|
45239
|
+
return Array.from({ length: bandCount }, (_, i) => {
|
|
45240
|
+
const fallback = RIBBON_BAND_GRADIENTS[i] ?? RIBBON_BAND_GRADIENTS[RIBBON_BAND_GRADIENTS.length - 1];
|
|
45241
|
+
const g = source[i] ?? fallback;
|
|
45242
|
+
return {
|
|
45243
|
+
idSuffix: String(i),
|
|
45244
|
+
start: g.start,
|
|
45245
|
+
end: g.end
|
|
45246
|
+
};
|
|
45247
|
+
});
|
|
45248
|
+
}
|
|
45249
|
+
function EquityRibbonChart({
|
|
45250
|
+
labels = DEFAULT_RIBBON_LABELS,
|
|
45251
|
+
bandCount: bandCountProp = 5,
|
|
45252
|
+
gradients,
|
|
45253
|
+
animated = true,
|
|
45254
|
+
hideLabels = false,
|
|
45255
|
+
background = "transparent",
|
|
45256
|
+
layout = "hero",
|
|
45257
|
+
labelColor = ribbonChartLabelDefault,
|
|
45258
|
+
className,
|
|
45259
|
+
height,
|
|
45260
|
+
style
|
|
45261
|
+
}) {
|
|
45262
|
+
const bandCount = clampBandCount(bandCountProp);
|
|
45263
|
+
const labelsKey = labels.join("");
|
|
45264
|
+
const labelsRef = useRef(labels);
|
|
45265
|
+
labelsRef.current = labels;
|
|
45266
|
+
const bandGradients = resolveGradients(gradients, bandCount);
|
|
45267
|
+
const uid = useId$2().replace(/:/g, "");
|
|
45268
|
+
const rootRef = useRef(null);
|
|
45269
|
+
const playedRef = useRef(false);
|
|
45270
|
+
const rafRef = useRef(null);
|
|
45271
|
+
const revealGenerationRef = useRef(0);
|
|
45272
|
+
const revealScheduleRef = useRef(0);
|
|
45273
|
+
const cancelRevealAnimation = useCallback(() => {
|
|
45274
|
+
revealGenerationRef.current += 1;
|
|
45275
|
+
if (rafRef.current !== null) {
|
|
45276
|
+
cancelAnimationFrame(rafRef.current);
|
|
45277
|
+
rafRef.current = null;
|
|
45278
|
+
}
|
|
45279
|
+
}, []);
|
|
45280
|
+
const [geometry, setGeometry] = useState(null);
|
|
45281
|
+
const [revealWidth, setRevealWidth] = useState(0);
|
|
45282
|
+
const [labelStyles, setLabelStyles] = useState(
|
|
45283
|
+
() => labels.slice(0, bandCount).map(() => ({ opacity: 0, transform: "translateY(6px)" }))
|
|
45284
|
+
);
|
|
45285
|
+
const rebuild = useCallback(() => {
|
|
45286
|
+
cancelRevealAnimation();
|
|
45287
|
+
const el = rootRef.current;
|
|
45288
|
+
if (!el) return;
|
|
45289
|
+
const width = el.clientWidth;
|
|
45290
|
+
const heightPx = el.clientHeight;
|
|
45291
|
+
const config2 = layout === "mark" ? MARK_RIBBON_CONFIG : void 0;
|
|
45292
|
+
const built = buildRibbonGeometry(
|
|
45293
|
+
width,
|
|
45294
|
+
heightPx,
|
|
45295
|
+
labelsRef.current,
|
|
45296
|
+
config2,
|
|
45297
|
+
bandCount,
|
|
45298
|
+
layout
|
|
45299
|
+
);
|
|
45300
|
+
setGeometry(built);
|
|
45301
|
+
if (built && (playedRef.current || !animated)) {
|
|
45302
|
+
setRevealWidth(built.width);
|
|
45303
|
+
setLabelStyles(
|
|
45304
|
+
built.labels.map((lbl) => ({
|
|
45305
|
+
opacity: 1,
|
|
45306
|
+
transform: labelAnchorTransform(lbl.placement, 0)
|
|
45307
|
+
}))
|
|
45308
|
+
);
|
|
45309
|
+
}
|
|
45310
|
+
}, [animated, bandCount, cancelRevealAnimation, labelsKey, layout]);
|
|
45311
|
+
useLayoutEffect(() => {
|
|
45312
|
+
playedRef.current = false;
|
|
45313
|
+
revealScheduleRef.current = 0;
|
|
45314
|
+
cancelRevealAnimation();
|
|
45315
|
+
if (animated) {
|
|
45316
|
+
setRevealWidth(0);
|
|
45317
|
+
setLabelStyles(
|
|
45318
|
+
labelsRef.current.slice(0, bandCount).map(() => ({
|
|
45319
|
+
opacity: 0,
|
|
45320
|
+
transform: "translateY(6px)"
|
|
45321
|
+
}))
|
|
45322
|
+
);
|
|
45323
|
+
}
|
|
45324
|
+
rebuild();
|
|
45325
|
+
}, [animated, bandCount, cancelRevealAnimation, rebuild]);
|
|
45326
|
+
useEffect(() => () => cancelRevealAnimation(), [cancelRevealAnimation]);
|
|
45327
|
+
useEffect(() => {
|
|
45328
|
+
const el = rootRef.current;
|
|
45329
|
+
if (!el) return;
|
|
45330
|
+
if (typeof ResizeObserver === "undefined") {
|
|
45331
|
+
rebuild();
|
|
45332
|
+
return;
|
|
45333
|
+
}
|
|
45334
|
+
const ro = new ResizeObserver(() => {
|
|
45335
|
+
rebuild();
|
|
45336
|
+
});
|
|
45337
|
+
ro.observe(el);
|
|
45338
|
+
return () => ro.disconnect();
|
|
45339
|
+
}, [rebuild]);
|
|
45340
|
+
const runReveal = useCallback(() => {
|
|
45341
|
+
if (!geometry || playedRef.current) return;
|
|
45342
|
+
if (!animated) {
|
|
45343
|
+
playedRef.current = true;
|
|
45344
|
+
setRevealWidth(geometry.width);
|
|
45345
|
+
setLabelStyles(
|
|
45346
|
+
geometry.labels.map((lbl) => ({
|
|
45347
|
+
opacity: 1,
|
|
45348
|
+
transform: labelAnchorTransform(lbl.placement, 0)
|
|
45349
|
+
}))
|
|
45350
|
+
);
|
|
45351
|
+
return;
|
|
45352
|
+
}
|
|
45353
|
+
const reduceMotion = typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
45354
|
+
if (reduceMotion) {
|
|
45355
|
+
playedRef.current = true;
|
|
45356
|
+
setRevealWidth(geometry.width);
|
|
45357
|
+
setLabelStyles(
|
|
45358
|
+
geometry.labels.map((lbl) => ({
|
|
45359
|
+
opacity: 1,
|
|
45360
|
+
transform: labelAnchorTransform(lbl.placement, 0)
|
|
45361
|
+
}))
|
|
45362
|
+
);
|
|
45363
|
+
return;
|
|
45364
|
+
}
|
|
45365
|
+
playedRef.current = true;
|
|
45366
|
+
setRevealWidth(0);
|
|
45367
|
+
setLabelStyles(
|
|
45368
|
+
geometry.labels.map((lbl) => ({
|
|
45369
|
+
opacity: 0,
|
|
45370
|
+
transform: labelAnchorTransform(lbl.placement, 6)
|
|
45371
|
+
}))
|
|
45372
|
+
);
|
|
45373
|
+
const generation = revealGenerationRef.current;
|
|
45374
|
+
const start = performance.now();
|
|
45375
|
+
const tick = (now) => {
|
|
45376
|
+
if (generation !== revealGenerationRef.current) return;
|
|
45377
|
+
const elapsed = now - start;
|
|
45378
|
+
const t = Math.min(1, elapsed / REVEAL_DURATION_MS);
|
|
45379
|
+
const eased = easePower1InOut(t);
|
|
45380
|
+
setRevealWidth(geometry.width * eased);
|
|
45381
|
+
setLabelStyles(
|
|
45382
|
+
geometry.labels.map((lbl, i) => {
|
|
45383
|
+
const labelStart = ribbonLabelRevealTime(i, REVEAL_DURATION_MS / 1e3) * 1e3;
|
|
45384
|
+
const labelDur = 550;
|
|
45385
|
+
const lt2 = Math.min(1, Math.max(0, (elapsed - labelStart) / labelDur));
|
|
45386
|
+
const lo = easePower2Out(lt2);
|
|
45387
|
+
const y = 6 * (1 - lo);
|
|
45388
|
+
return { opacity: lo, transform: labelAnchorTransform(lbl.placement, y) };
|
|
45389
|
+
})
|
|
45390
|
+
);
|
|
45391
|
+
if (t < 1) {
|
|
45392
|
+
rafRef.current = requestAnimationFrame(tick);
|
|
45393
|
+
} else {
|
|
45394
|
+
setRevealWidth(geometry.width);
|
|
45395
|
+
setLabelStyles(
|
|
45396
|
+
geometry.labels.map((lbl) => ({
|
|
45397
|
+
opacity: 1,
|
|
45398
|
+
transform: labelAnchorTransform(lbl.placement, 0)
|
|
45399
|
+
}))
|
|
45400
|
+
);
|
|
45401
|
+
}
|
|
45402
|
+
};
|
|
45403
|
+
rafRef.current = requestAnimationFrame(tick);
|
|
45404
|
+
}, [animated, geometry]);
|
|
45405
|
+
useEffect(() => {
|
|
45406
|
+
if (!geometry || playedRef.current) return;
|
|
45407
|
+
const scheduleId = ++revealScheduleRef.current;
|
|
45408
|
+
const delay = scheduleId === 1 ? REVEAL_DELAY_MS : 0;
|
|
45409
|
+
const timer = window.setTimeout(() => {
|
|
45410
|
+
if (scheduleId !== revealScheduleRef.current) return;
|
|
45411
|
+
runReveal();
|
|
45412
|
+
}, delay);
|
|
45413
|
+
return () => window.clearTimeout(timer);
|
|
45414
|
+
}, [geometry, runReveal]);
|
|
45415
|
+
const suppressLabels = hideLabels || layout === "mark";
|
|
45416
|
+
const activeGeometry = geometry && geometry.bandCount === bandCount ? geometry : null;
|
|
45417
|
+
const rootClass = [
|
|
45418
|
+
"fairmint-equity-ribbon",
|
|
45419
|
+
RIBBON_BACKGROUND_CLASS[background],
|
|
45420
|
+
layout === "mark" ? "fairmint-equity-ribbon--layout-mark" : "",
|
|
45421
|
+
suppressLabels ? "fairmint-equity-ribbon--hidden-labels" : "",
|
|
45422
|
+
className ?? ""
|
|
45423
|
+
].filter(Boolean).join(" ");
|
|
45424
|
+
const rootStyle = {
|
|
45425
|
+
...RIBBON_SURFACE_CSS_VARS,
|
|
45426
|
+
...style,
|
|
45427
|
+
...height ? { height } : {}
|
|
45428
|
+
};
|
|
45429
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: rootClass, style: rootStyle, children: [
|
|
45430
|
+
/* @__PURE__ */ jsxs(
|
|
45431
|
+
"svg",
|
|
45432
|
+
{
|
|
45433
|
+
className: "fairmint-equity-ribbon__svg",
|
|
45434
|
+
preserveAspectRatio: "none",
|
|
45435
|
+
"aria-hidden": "true",
|
|
45436
|
+
viewBox: activeGeometry ? `0 0 ${activeGeometry.width} ${activeGeometry.height}` : "0 0 1 1",
|
|
45437
|
+
children: [
|
|
45438
|
+
/* @__PURE__ */ jsxs("defs", { children: [
|
|
45439
|
+
bandGradients.map((g) => /* @__PURE__ */ jsxs(
|
|
45440
|
+
"linearGradient",
|
|
45441
|
+
{
|
|
45442
|
+
id: `${uid}-bg${g.idSuffix}`,
|
|
45443
|
+
x1: "0",
|
|
45444
|
+
y1: "1",
|
|
45445
|
+
x2: "1",
|
|
45446
|
+
y2: "0",
|
|
45447
|
+
children: [
|
|
45448
|
+
/* @__PURE__ */ jsx("stop", { offset: "0", stopColor: g.start }),
|
|
45449
|
+
/* @__PURE__ */ jsx("stop", { offset: "1", stopColor: g.end })
|
|
45450
|
+
]
|
|
45451
|
+
},
|
|
45452
|
+
g.idSuffix
|
|
45453
|
+
)),
|
|
45454
|
+
/* @__PURE__ */ jsx("clipPath", { id: `${uid}-revealclip`, children: /* @__PURE__ */ jsx("rect", { x: 0, y: -1, width: revealWidth, height: (activeGeometry?.height ?? 1) + 2 }) }),
|
|
45455
|
+
activeGeometry ? activeGeometry.paths.map((_, i) => /* @__PURE__ */ jsx("clipPath", { id: `${uid}-bandclip${i}`, children: /* @__PURE__ */ jsx(
|
|
45456
|
+
"rect",
|
|
45457
|
+
{
|
|
45458
|
+
x: 0,
|
|
45459
|
+
y: -1,
|
|
45460
|
+
width: activeGeometry.clipWidthPx[i],
|
|
45461
|
+
height: activeGeometry.height + 2
|
|
45462
|
+
}
|
|
45463
|
+
) }, `bandclip-${bandGradients[i].idSuffix}`)) : null
|
|
45464
|
+
] }),
|
|
45465
|
+
/* @__PURE__ */ jsx("g", { clipPath: `url(#${uid}-revealclip)`, children: activeGeometry?.paths.map((d, i) => /* @__PURE__ */ jsx(
|
|
45466
|
+
"path",
|
|
45467
|
+
{
|
|
45468
|
+
className: "fairmint-equity-ribbon__band",
|
|
45469
|
+
fill: `url(#${uid}-bg${bandGradients[i].idSuffix})`,
|
|
45470
|
+
clipPath: `url(#${uid}-bandclip${i})`,
|
|
45471
|
+
d
|
|
45472
|
+
},
|
|
45473
|
+
bandGradients[i].idSuffix
|
|
45474
|
+
)) })
|
|
45475
|
+
]
|
|
45476
|
+
}
|
|
45477
|
+
),
|
|
45478
|
+
!suppressLabels && activeGeometry?.labels.map((lbl, i) => /* @__PURE__ */ jsx(
|
|
45479
|
+
"div",
|
|
45480
|
+
{
|
|
45481
|
+
className: labelClassName(lbl.placement),
|
|
45482
|
+
style: {
|
|
45483
|
+
left: `${lbl.leftPct}%`,
|
|
45484
|
+
top: `${lbl.topPct}%`,
|
|
45485
|
+
color: labelColor,
|
|
45486
|
+
opacity: labelStyles[i]?.opacity ?? 0,
|
|
45487
|
+
transform: labelStyles[i]?.transform
|
|
45488
|
+
},
|
|
45489
|
+
children: lbl.text
|
|
45490
|
+
},
|
|
45491
|
+
`${lbl.text}-${lbl.index}`
|
|
45492
|
+
))
|
|
45493
|
+
] });
|
|
45494
|
+
}
|
|
45495
|
+
function FairmintRibbonMark({
|
|
45496
|
+
size: size2 = 64,
|
|
45497
|
+
bandCount = 5,
|
|
45498
|
+
gradients,
|
|
45499
|
+
background = "black",
|
|
45500
|
+
labelColor,
|
|
45501
|
+
className,
|
|
45502
|
+
style
|
|
45503
|
+
}) {
|
|
45504
|
+
const dimension = `${size2}px`;
|
|
45505
|
+
return /* @__PURE__ */ jsx(
|
|
45506
|
+
EquityRibbonChart,
|
|
45507
|
+
{
|
|
45508
|
+
bandCount,
|
|
45509
|
+
gradients,
|
|
45510
|
+
background,
|
|
45511
|
+
labelColor,
|
|
45512
|
+
layout: "mark",
|
|
45513
|
+
animated: false,
|
|
45514
|
+
hideLabels: true,
|
|
45515
|
+
className: ["fairmint-ribbon-mark", className].filter(Boolean).join(" "),
|
|
45516
|
+
height: dimension,
|
|
45517
|
+
style: { width: dimension, height: dimension, ...style }
|
|
45518
|
+
}
|
|
45519
|
+
);
|
|
45520
|
+
}
|
|
45001
45521
|
function InvestmentCard({
|
|
45002
45522
|
companyName,
|
|
45003
45523
|
logoUrl,
|
|
@@ -45768,6 +46288,8 @@ export {
|
|
|
45768
46288
|
ConfirmDialog,
|
|
45769
46289
|
Container,
|
|
45770
46290
|
Currency,
|
|
46291
|
+
DEFAULT_RIBBON_CONFIG,
|
|
46292
|
+
DEFAULT_RIBBON_LABELS,
|
|
45771
46293
|
DataRow,
|
|
45772
46294
|
DataTable,
|
|
45773
46295
|
DateDisplay,
|
|
@@ -45780,12 +46302,14 @@ export {
|
|
|
45780
46302
|
EmailField,
|
|
45781
46303
|
EmptyState,
|
|
45782
46304
|
EquityGrantCard,
|
|
46305
|
+
EquityRibbonChart,
|
|
45783
46306
|
ErrorFallback,
|
|
45784
46307
|
ErrorPage,
|
|
45785
46308
|
EthereumAddressField,
|
|
45786
46309
|
Eyebrow,
|
|
45787
46310
|
FairmintLogo,
|
|
45788
46311
|
FairmintProvider,
|
|
46312
|
+
FairmintRibbonMark,
|
|
45789
46313
|
Flex,
|
|
45790
46314
|
Form,
|
|
45791
46315
|
FormField,
|
|
@@ -45796,6 +46320,8 @@ export {
|
|
|
45796
46320
|
ListRow,
|
|
45797
46321
|
Loader,
|
|
45798
46322
|
LoadingSpinner,
|
|
46323
|
+
MARK_RIBBON_CONFIG,
|
|
46324
|
+
MARK_RIBBON_RIGHT_EDGE,
|
|
45799
46325
|
MOBILE_BREAKPOINT,
|
|
45800
46326
|
Menu,
|
|
45801
46327
|
Modal,
|
|
@@ -45815,6 +46341,8 @@ export {
|
|
|
45815
46341
|
PhotoCropModal,
|
|
45816
46342
|
PinInput,
|
|
45817
46343
|
Progress,
|
|
46344
|
+
RIBBON_BACKGROUND_CLASS,
|
|
46345
|
+
RIBBON_BAND_GRADIENTS,
|
|
45818
46346
|
RadioCard,
|
|
45819
46347
|
RedactedValue,
|
|
45820
46348
|
ScrollArea,
|
|
@@ -45848,6 +46376,7 @@ export {
|
|
|
45848
46376
|
ZERO_ETHEREUM_ADDRESS,
|
|
45849
46377
|
ZipField,
|
|
45850
46378
|
brandColors,
|
|
46379
|
+
clampBandCount,
|
|
45851
46380
|
colors,
|
|
45852
46381
|
createFairmintMantineProviderProps,
|
|
45853
46382
|
createZipSchema,
|