@fairmint/ui 0.2.31 → 0.2.33
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 +41 -0
- package/dist/components/specific/EquityRibbonChart/EquityRibbonChart.d.ts.map +1 -0
- package/dist/components/specific/EquityRibbonChart/FairmintRibbonMark.d.ts +25 -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 +73 -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 +582 -0
- package/dist/fairmint-ui.cjs.map +1 -1
- package/dist/fairmint-ui.js +582 -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 +79 -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.cjs
CHANGED
|
@@ -45016,6 +45016,579 @@ function EquityGrantCard({
|
|
|
45016
45016
|
}
|
|
45017
45017
|
);
|
|
45018
45018
|
}
|
|
45019
|
+
const DEFAULT_RIBBON_CONFIG = {
|
|
45020
|
+
baseline: 0.82,
|
|
45021
|
+
xEndStagger: 9e-3,
|
|
45022
|
+
xEndDraw: [0.84, 0.849, 0.858, 0.867, 0.876],
|
|
45023
|
+
xEndCurve: 0.914,
|
|
45024
|
+
xStart: [0.05, 0.19, 0.34, 0.5, 0.66],
|
|
45025
|
+
kArr: [1.7, 2.4, 3.1, 3.9, 4.9],
|
|
45026
|
+
V: [0.082, 0.102, 0.132, 0.172, 0.21],
|
|
45027
|
+
vMin: [0.038, 0.04, 0.042, 0.044, 0.046],
|
|
45028
|
+
xStem: [0.05, 0.04, 0.035, 0.03, 0.025],
|
|
45029
|
+
labelX: [0.08, 0.24, 0.4, 0.56, 0.8],
|
|
45030
|
+
labelAboveGap: [0.034, 0.03, 0.028, 0.024],
|
|
45031
|
+
labelLeftGap: 0.055,
|
|
45032
|
+
labelLiquidityGap: 0.016,
|
|
45033
|
+
labelNudge: [
|
|
45034
|
+
[0, 0],
|
|
45035
|
+
[0, 0],
|
|
45036
|
+
[0, 0],
|
|
45037
|
+
[0, 0],
|
|
45038
|
+
[0, -0.012]
|
|
45039
|
+
],
|
|
45040
|
+
samples: 72
|
|
45041
|
+
};
|
|
45042
|
+
const MARK_RIBBON_RIGHT_EDGE = 0.936;
|
|
45043
|
+
const HERO_WIDE_TOP_END = DEFAULT_RIBBON_CONFIG.xEndDraw[DEFAULT_RIBBON_CONFIG.xEndDraw.length - 1];
|
|
45044
|
+
const RIBBON_END_STAGGER_X = DEFAULT_RIBBON_CONFIG.xEndStagger * 1e3 / (1e3 - 500);
|
|
45045
|
+
const MARK_FIT_HORIZONTAL_COMPRESS = 0.78;
|
|
45046
|
+
const MARK_RIBBON_CONFIG = {
|
|
45047
|
+
...DEFAULT_RIBBON_CONFIG,
|
|
45048
|
+
baseline: 0.97,
|
|
45049
|
+
xEndDraw: [
|
|
45050
|
+
MARK_RIBBON_RIGHT_EDGE,
|
|
45051
|
+
MARK_RIBBON_RIGHT_EDGE,
|
|
45052
|
+
MARK_RIBBON_RIGHT_EDGE,
|
|
45053
|
+
MARK_RIBBON_RIGHT_EDGE,
|
|
45054
|
+
MARK_RIBBON_RIGHT_EDGE
|
|
45055
|
+
],
|
|
45056
|
+
xEndCurve: 0.94,
|
|
45057
|
+
xStart: [0.08, 0.2, 0.32, 0.44, 0.56],
|
|
45058
|
+
xStem: [0.028, 0.022, 0.018, 0.015, 0.012]
|
|
45059
|
+
};
|
|
45060
|
+
function labelGapAbove(i, config2) {
|
|
45061
|
+
const lastBand = config2.xStart.length - 1;
|
|
45062
|
+
if (i === lastBand) return config2.labelLiquidityGap;
|
|
45063
|
+
return config2.labelAboveGap[i] ?? config2.labelLiquidityGap;
|
|
45064
|
+
}
|
|
45065
|
+
function mergeBounds(a, b) {
|
|
45066
|
+
return {
|
|
45067
|
+
minX: Math.min(a.minX, b.minX),
|
|
45068
|
+
minY: Math.min(a.minY, b.minY),
|
|
45069
|
+
maxX: Math.max(a.maxX, b.maxX),
|
|
45070
|
+
maxY: Math.max(a.maxY, b.maxY)
|
|
45071
|
+
};
|
|
45072
|
+
}
|
|
45073
|
+
function transformPathD(d, scaleX, scaleY, tx, ty) {
|
|
45074
|
+
return d.replace(/(-?[\d.]+),(-?[\d.]+)/g, (_, x, y) => {
|
|
45075
|
+
const px2 = Number(x) * scaleX + tx;
|
|
45076
|
+
const py = Number(y) * scaleY + ty;
|
|
45077
|
+
return `${px2.toFixed(1)},${py.toFixed(1)}`;
|
|
45078
|
+
});
|
|
45079
|
+
}
|
|
45080
|
+
function computeMarkFitTransform(bounds, width, height, paddingRatio) {
|
|
45081
|
+
const pad = paddingRatio * Math.min(width, height);
|
|
45082
|
+
const bw = bounds.maxX - bounds.minX;
|
|
45083
|
+
const bh = bounds.maxY - bounds.minY;
|
|
45084
|
+
if (bw <= 0 || bh <= 0) {
|
|
45085
|
+
return { scaleX: 1, scaleY: 1, tx: 0, ty: 0 };
|
|
45086
|
+
}
|
|
45087
|
+
const scaleY = (height - pad * 2) / bh;
|
|
45088
|
+
let scaleX = scaleY * MARK_FIT_HORIZONTAL_COMPRESS;
|
|
45089
|
+
if (bw * scaleX > width - pad * 2) {
|
|
45090
|
+
scaleX = (width - pad * 2) / bw;
|
|
45091
|
+
}
|
|
45092
|
+
const tx = (width - bw * scaleX) / 2 - bounds.minX * scaleX;
|
|
45093
|
+
const ty = (height - bh * scaleY) / 2 - bounds.minY * scaleY;
|
|
45094
|
+
return { scaleX, scaleY, tx, ty };
|
|
45095
|
+
}
|
|
45096
|
+
function valAt(i, xf, config2) {
|
|
45097
|
+
const { xStart, xEndCurve, kArr, V, vMin, xStem } = config2;
|
|
45098
|
+
const xLo = xStart[i] - xStem[i];
|
|
45099
|
+
if (xf < xLo || xf > xEndCurve) return 0;
|
|
45100
|
+
if (xf < xStart[i]) return vMin[i];
|
|
45101
|
+
const u = (xf - xStart[i]) / (xEndCurve - xStart[i]);
|
|
45102
|
+
const grow = (Math.exp(kArr[i] * u) - 1) / (Math.exp(kArr[i]) - 1);
|
|
45103
|
+
return vMin[i] + (V[i] - vMin[i]) * grow;
|
|
45104
|
+
}
|
|
45105
|
+
function cumBelow(i, xf, config2) {
|
|
45106
|
+
let sum = 0;
|
|
45107
|
+
for (let j = 0; j < i; j++) sum += valAt(j, xf, config2);
|
|
45108
|
+
return sum;
|
|
45109
|
+
}
|
|
45110
|
+
function buildBandPath(i, width, height, config2) {
|
|
45111
|
+
const { xStart, xEndCurve, xStem, baseline } = config2;
|
|
45112
|
+
const samples = Math.max(1, Math.floor(config2.samples));
|
|
45113
|
+
const xLo = xStart[i] - xStem[i];
|
|
45114
|
+
const top = [];
|
|
45115
|
+
const bot = [];
|
|
45116
|
+
for (let s = 0; s <= samples; s++) {
|
|
45117
|
+
const xf = xLo + (xEndCurve - xLo) * (s / samples);
|
|
45118
|
+
const below = cumBelow(i, xf, config2);
|
|
45119
|
+
const v = valAt(i, xf, config2);
|
|
45120
|
+
const x = xf * width;
|
|
45121
|
+
top.push([x, (baseline - below - v) * height]);
|
|
45122
|
+
bot.push([x, (baseline - below) * height]);
|
|
45123
|
+
}
|
|
45124
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
45125
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
45126
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
45127
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
45128
|
+
for (const [x, y] of [...top, ...bot]) {
|
|
45129
|
+
minX = Math.min(minX, x);
|
|
45130
|
+
minY = Math.min(minY, y);
|
|
45131
|
+
maxX = Math.max(maxX, x);
|
|
45132
|
+
maxY = Math.max(maxY, y);
|
|
45133
|
+
}
|
|
45134
|
+
let d = `M${top[0][0].toFixed(1)},${top[0][1].toFixed(1)}`;
|
|
45135
|
+
for (let s = 1; s <= samples; s++) {
|
|
45136
|
+
d += ` L${top[s][0].toFixed(1)},${top[s][1].toFixed(1)}`;
|
|
45137
|
+
}
|
|
45138
|
+
d += ` L${bot[samples][0].toFixed(1)},${bot[samples][1].toFixed(1)}`;
|
|
45139
|
+
for (let s = samples - 1; s >= 0; s--) {
|
|
45140
|
+
d += ` L${bot[s][0].toFixed(1)},${bot[s][1].toFixed(1)}`;
|
|
45141
|
+
}
|
|
45142
|
+
return { d: `${d} Z`, bounds: { minX, minY, maxX, maxY } };
|
|
45143
|
+
}
|
|
45144
|
+
function buildLabel(i, text, _width, _height, config2, offsetXNorm) {
|
|
45145
|
+
const { baseline, xStart, xStem, labelNudge } = config2;
|
|
45146
|
+
const xf = xStart[i] - xStem[i] + offsetXNorm;
|
|
45147
|
+
const below = cumBelow(i, xf, config2);
|
|
45148
|
+
const v = valAt(i, xf, config2);
|
|
45149
|
+
const yTop = baseline - below - v;
|
|
45150
|
+
const [nudgeX, nudgeY] = labelNudge[i];
|
|
45151
|
+
return {
|
|
45152
|
+
index: i,
|
|
45153
|
+
text,
|
|
45154
|
+
leftPct: (xf + nudgeX) * 100,
|
|
45155
|
+
topPct: (yTop - labelGapAbove(i, config2) + nudgeY) * 100,
|
|
45156
|
+
placement: "start"
|
|
45157
|
+
};
|
|
45158
|
+
}
|
|
45159
|
+
function clampBandCount(count2, max2 = 5) {
|
|
45160
|
+
if (!Number.isFinite(count2)) return max2;
|
|
45161
|
+
return Math.min(max2, Math.max(1, Math.round(count2)));
|
|
45162
|
+
}
|
|
45163
|
+
function resolveChartGeometryWidth(containerWidth, containerHeight, chartWidth) {
|
|
45164
|
+
const layoutWidth = Number.isFinite(containerWidth) && containerWidth > 0 ? containerWidth : 0;
|
|
45165
|
+
const layoutHeight = Number.isFinite(containerHeight) && containerHeight > 0 ? containerHeight : 0;
|
|
45166
|
+
if (chartWidth != null && Number.isFinite(chartWidth) && chartWidth > 0) {
|
|
45167
|
+
const nominal = Math.max(chartWidth, layoutHeight);
|
|
45168
|
+
if (layoutWidth > 0) {
|
|
45169
|
+
return Math.min(nominal, layoutWidth);
|
|
45170
|
+
}
|
|
45171
|
+
return nominal;
|
|
45172
|
+
}
|
|
45173
|
+
if (layoutWidth > 0) {
|
|
45174
|
+
return layoutWidth;
|
|
45175
|
+
}
|
|
45176
|
+
return layoutHeight;
|
|
45177
|
+
}
|
|
45178
|
+
function nominalChartWidthPx(chartWidth, renderedHeightPx) {
|
|
45179
|
+
const heightPx = Number.isFinite(renderedHeightPx) && renderedHeightPx > 0 ? renderedHeightPx : 0;
|
|
45180
|
+
return Math.max(chartWidth, heightPx);
|
|
45181
|
+
}
|
|
45182
|
+
function ribbonEndStaggerNorm(chartWidth, height) {
|
|
45183
|
+
const w = Math.max(chartWidth, height);
|
|
45184
|
+
if (w <= height) return 0;
|
|
45185
|
+
const intPx = (w - height) * RIBBON_END_STAGGER_X;
|
|
45186
|
+
return intPx / w;
|
|
45187
|
+
}
|
|
45188
|
+
function buildStaggeredEndDraw(bandCount, chartWidth, height) {
|
|
45189
|
+
const validBandCount = clampBandCount(bandCount);
|
|
45190
|
+
const intNorm = ribbonEndStaggerNorm(chartWidth, height);
|
|
45191
|
+
const t = DEFAULT_RIBBON_CONFIG.xEndStagger > 0 ? Math.min(1, intNorm / DEFAULT_RIBBON_CONFIG.xEndStagger) : 0;
|
|
45192
|
+
const rightAnchor = MARK_RIBBON_RIGHT_EDGE - t * (MARK_RIBBON_RIGHT_EDGE - HERO_WIDE_TOP_END);
|
|
45193
|
+
const last = validBandCount - 1;
|
|
45194
|
+
return Array.from({ length: validBandCount }, (_, i) => rightAnchor - (last - i) * intNorm);
|
|
45195
|
+
}
|
|
45196
|
+
function configWithChartDimensions(base, chartWidth, height) {
|
|
45197
|
+
return {
|
|
45198
|
+
...base,
|
|
45199
|
+
xEndDraw: buildStaggeredEndDraw(base.xStart.length, chartWidth, height)
|
|
45200
|
+
};
|
|
45201
|
+
}
|
|
45202
|
+
function buildRibbonGeometry(width, height, labels, config2 = DEFAULT_RIBBON_CONFIG, bandCount = config2.xStart.length, layout = "hero") {
|
|
45203
|
+
const totalBands = config2.xStart.length;
|
|
45204
|
+
const visibleBands = clampBandCount(bandCount, totalBands);
|
|
45205
|
+
if (width <= 0 || height <= 0) {
|
|
45206
|
+
return null;
|
|
45207
|
+
}
|
|
45208
|
+
const paths = [];
|
|
45209
|
+
const clipWidthPx = [];
|
|
45210
|
+
let bounds = null;
|
|
45211
|
+
for (let i = 0; i < visibleBands; i++) {
|
|
45212
|
+
const band = buildBandPath(i, width, height, config2);
|
|
45213
|
+
paths.push(band.d);
|
|
45214
|
+
clipWidthPx.push(config2.xEndDraw[i] * width);
|
|
45215
|
+
bounds = bounds ? mergeBounds(bounds, band.bounds) : band.bounds;
|
|
45216
|
+
}
|
|
45217
|
+
let fitPaths = paths;
|
|
45218
|
+
let fitClips = clipWidthPx;
|
|
45219
|
+
let offsetXNorm = 0;
|
|
45220
|
+
if (bounds) {
|
|
45221
|
+
if (layout === "mark") {
|
|
45222
|
+
const { scaleX, scaleY, tx, ty } = computeMarkFitTransform(bounds, width, height, 0.05);
|
|
45223
|
+
fitPaths = paths.map((p) => transformPathD(p, scaleX, scaleY, tx, ty));
|
|
45224
|
+
const alignedClipRight = MARK_RIBBON_RIGHT_EDGE * width * scaleX + tx;
|
|
45225
|
+
fitClips = clipWidthPx.map(() => alignedClipRight);
|
|
45226
|
+
offsetXNorm = tx / width;
|
|
45227
|
+
} else if (layout === "hero") {
|
|
45228
|
+
const bw = bounds.maxX - bounds.minX;
|
|
45229
|
+
const tx = (width - bw) / 2 - bounds.minX;
|
|
45230
|
+
fitPaths = paths.map((p) => transformPathD(p, 1, 1, tx, 0));
|
|
45231
|
+
fitClips = clipWidthPx.map((w) => w + tx);
|
|
45232
|
+
offsetXNorm = tx / width;
|
|
45233
|
+
}
|
|
45234
|
+
}
|
|
45235
|
+
const paddedLabels = Array.from({ length: visibleBands }, (_, i) => labels[i] ?? "");
|
|
45236
|
+
const builtLabels = paddedLabels.map(
|
|
45237
|
+
(text, i) => buildLabel(i, text, width, height, config2, offsetXNorm)
|
|
45238
|
+
);
|
|
45239
|
+
return {
|
|
45240
|
+
paths: fitPaths,
|
|
45241
|
+
clipWidthPx: fitClips,
|
|
45242
|
+
labels: builtLabels,
|
|
45243
|
+
width,
|
|
45244
|
+
height,
|
|
45245
|
+
bandCount: visibleBands
|
|
45246
|
+
};
|
|
45247
|
+
}
|
|
45248
|
+
function easePower1InOut(t) {
|
|
45249
|
+
const p = Math.max(0, Math.min(1, t));
|
|
45250
|
+
return p < 0.5 ? 2 * p * p : 1 - (-2 * p + 2) ** 2 / 2;
|
|
45251
|
+
}
|
|
45252
|
+
function easePower2Out(t) {
|
|
45253
|
+
const p = Math.max(0, Math.min(1, t));
|
|
45254
|
+
return 1 - (1 - p) ** 2;
|
|
45255
|
+
}
|
|
45256
|
+
function ribbonLabelRevealTime(labelIndex, duration2, config2 = DEFAULT_RIBBON_CONFIG) {
|
|
45257
|
+
return Math.min(duration2, config2.labelX[labelIndex] * duration2 + 0.25);
|
|
45258
|
+
}
|
|
45259
|
+
const ribbonChartLabelDefault = "#FFFFFF";
|
|
45260
|
+
const ribbonChartSurface = {
|
|
45261
|
+
white: "#FFFFFF",
|
|
45262
|
+
black: "#0D1023"
|
|
45263
|
+
};
|
|
45264
|
+
const ribbonBandGradientStops = [
|
|
45265
|
+
{ idSuffix: "0", start: "#33198C", end: "#5B2BF0" },
|
|
45266
|
+
{ idSuffix: "1", start: "#4A22C8", end: "#7A3DF5" },
|
|
45267
|
+
{ idSuffix: "2", start: "#6A32E8", end: "#9A6BFF" },
|
|
45268
|
+
{ idSuffix: "3", start: "#8A52F5", end: "#BD84FF" },
|
|
45269
|
+
{ idSuffix: "4", start: "#A86BFF", end: "#E6ABFF" }
|
|
45270
|
+
];
|
|
45271
|
+
const RIBBON_BACKGROUND_CLASS = {
|
|
45272
|
+
white: "fairmint-equity-ribbon--bg-white",
|
|
45273
|
+
black: "fairmint-equity-ribbon--bg-black",
|
|
45274
|
+
transparent: "fairmint-equity-ribbon--bg-transparent"
|
|
45275
|
+
};
|
|
45276
|
+
const DEFAULT_RIBBON_LABELS = [
|
|
45277
|
+
"Cap Table",
|
|
45278
|
+
"Fundraising",
|
|
45279
|
+
"Grants",
|
|
45280
|
+
"Secondaries",
|
|
45281
|
+
"Liquidity"
|
|
45282
|
+
];
|
|
45283
|
+
const RIBBON_BAND_GRADIENTS = ribbonBandGradientStops;
|
|
45284
|
+
const RIBBON_SURFACE_CSS_VARS = {
|
|
45285
|
+
"--fairmint-ribbon-surface-white": ribbonChartSurface.white,
|
|
45286
|
+
"--fairmint-ribbon-surface-black": ribbonChartSurface.black
|
|
45287
|
+
};
|
|
45288
|
+
const REVEAL_DURATION_MS = 2300;
|
|
45289
|
+
const REVEAL_DELAY_MS = 420;
|
|
45290
|
+
function labelAnchorTransform(_placement, yOffsetPx) {
|
|
45291
|
+
return `translate(0, calc(-100% + ${yOffsetPx}px))`;
|
|
45292
|
+
}
|
|
45293
|
+
function labelClassName(_placement) {
|
|
45294
|
+
return "fairmint-equity-ribbon__label fairmint-equity-ribbon__label--start";
|
|
45295
|
+
}
|
|
45296
|
+
function resolveGradients(gradients, bandCount) {
|
|
45297
|
+
const source = gradients ?? RIBBON_BAND_GRADIENTS;
|
|
45298
|
+
return Array.from({ length: bandCount }, (_, i) => {
|
|
45299
|
+
const fallback = RIBBON_BAND_GRADIENTS[i] ?? RIBBON_BAND_GRADIENTS[RIBBON_BAND_GRADIENTS.length - 1];
|
|
45300
|
+
const g = source[i] ?? fallback;
|
|
45301
|
+
return {
|
|
45302
|
+
idSuffix: String(i),
|
|
45303
|
+
start: g.start,
|
|
45304
|
+
end: g.end
|
|
45305
|
+
};
|
|
45306
|
+
});
|
|
45307
|
+
}
|
|
45308
|
+
function EquityRibbonChart({
|
|
45309
|
+
labels = DEFAULT_RIBBON_LABELS,
|
|
45310
|
+
bandCount: bandCountProp = 5,
|
|
45311
|
+
gradients,
|
|
45312
|
+
animated = true,
|
|
45313
|
+
hideLabels = false,
|
|
45314
|
+
background = "transparent",
|
|
45315
|
+
gapColor,
|
|
45316
|
+
layout = "hero",
|
|
45317
|
+
labelColor = ribbonChartLabelDefault,
|
|
45318
|
+
className,
|
|
45319
|
+
height,
|
|
45320
|
+
chartWidth,
|
|
45321
|
+
style
|
|
45322
|
+
}) {
|
|
45323
|
+
const bandCount = clampBandCount(bandCountProp);
|
|
45324
|
+
const labelsKey = labels.join("");
|
|
45325
|
+
const labelsRef = React.useRef(labels);
|
|
45326
|
+
labelsRef.current = labels;
|
|
45327
|
+
const bandGradients = resolveGradients(gradients, bandCount);
|
|
45328
|
+
const uid = React.useId().replace(/:/g, "");
|
|
45329
|
+
const rootRef = React.useRef(null);
|
|
45330
|
+
const playedRef = React.useRef(false);
|
|
45331
|
+
const rafRef = React.useRef(null);
|
|
45332
|
+
const revealGenerationRef = React.useRef(0);
|
|
45333
|
+
const revealScheduleRef = React.useRef(0);
|
|
45334
|
+
const cancelRevealAnimation = React.useCallback(() => {
|
|
45335
|
+
revealGenerationRef.current += 1;
|
|
45336
|
+
if (rafRef.current !== null) {
|
|
45337
|
+
cancelAnimationFrame(rafRef.current);
|
|
45338
|
+
rafRef.current = null;
|
|
45339
|
+
}
|
|
45340
|
+
}, []);
|
|
45341
|
+
const [geometry, setGeometry] = React.useState(null);
|
|
45342
|
+
const [revealWidth, setRevealWidth] = React.useState(0);
|
|
45343
|
+
const [labelStyles, setLabelStyles] = React.useState(
|
|
45344
|
+
() => labels.slice(0, bandCount).map(() => ({ opacity: 0, transform: "translateY(6px)" }))
|
|
45345
|
+
);
|
|
45346
|
+
const rebuild = React.useCallback(() => {
|
|
45347
|
+
cancelRevealAnimation();
|
|
45348
|
+
const el = rootRef.current;
|
|
45349
|
+
if (!el) return;
|
|
45350
|
+
const containerWidth = el.clientWidth;
|
|
45351
|
+
const heightPx = el.clientHeight;
|
|
45352
|
+
const geometryWidth = resolveChartGeometryWidth(containerWidth, heightPx, chartWidth);
|
|
45353
|
+
const baseConfig = layout === "mark" ? MARK_RIBBON_CONFIG : DEFAULT_RIBBON_CONFIG;
|
|
45354
|
+
const config2 = configWithChartDimensions(baseConfig, geometryWidth, heightPx);
|
|
45355
|
+
const built = buildRibbonGeometry(
|
|
45356
|
+
geometryWidth,
|
|
45357
|
+
heightPx,
|
|
45358
|
+
labelsRef.current,
|
|
45359
|
+
config2,
|
|
45360
|
+
bandCount,
|
|
45361
|
+
layout
|
|
45362
|
+
);
|
|
45363
|
+
setGeometry(built);
|
|
45364
|
+
if (built && (playedRef.current || !animated)) {
|
|
45365
|
+
setRevealWidth(built.width);
|
|
45366
|
+
setLabelStyles(
|
|
45367
|
+
built.labels.map((lbl) => ({
|
|
45368
|
+
opacity: 1,
|
|
45369
|
+
transform: labelAnchorTransform(lbl.placement, 0)
|
|
45370
|
+
}))
|
|
45371
|
+
);
|
|
45372
|
+
}
|
|
45373
|
+
}, [animated, bandCount, cancelRevealAnimation, chartWidth, labelsKey, layout]);
|
|
45374
|
+
React.useLayoutEffect(() => {
|
|
45375
|
+
playedRef.current = false;
|
|
45376
|
+
revealScheduleRef.current = 0;
|
|
45377
|
+
cancelRevealAnimation();
|
|
45378
|
+
if (animated) {
|
|
45379
|
+
setRevealWidth(0);
|
|
45380
|
+
setLabelStyles(
|
|
45381
|
+
labelsRef.current.slice(0, bandCount).map(() => ({
|
|
45382
|
+
opacity: 0,
|
|
45383
|
+
transform: "translateY(6px)"
|
|
45384
|
+
}))
|
|
45385
|
+
);
|
|
45386
|
+
}
|
|
45387
|
+
rebuild();
|
|
45388
|
+
}, [animated, bandCount, cancelRevealAnimation, rebuild]);
|
|
45389
|
+
React.useEffect(() => () => cancelRevealAnimation(), [cancelRevealAnimation]);
|
|
45390
|
+
React.useEffect(() => {
|
|
45391
|
+
const el = rootRef.current;
|
|
45392
|
+
if (!el) return;
|
|
45393
|
+
if (typeof ResizeObserver === "undefined") {
|
|
45394
|
+
rebuild();
|
|
45395
|
+
return;
|
|
45396
|
+
}
|
|
45397
|
+
const ro = new ResizeObserver(() => {
|
|
45398
|
+
rebuild();
|
|
45399
|
+
});
|
|
45400
|
+
ro.observe(el);
|
|
45401
|
+
return () => ro.disconnect();
|
|
45402
|
+
}, [rebuild]);
|
|
45403
|
+
const runReveal = React.useCallback(() => {
|
|
45404
|
+
if (!geometry || playedRef.current) return;
|
|
45405
|
+
if (!animated) {
|
|
45406
|
+
playedRef.current = true;
|
|
45407
|
+
setRevealWidth(geometry.width);
|
|
45408
|
+
setLabelStyles(
|
|
45409
|
+
geometry.labels.map((lbl) => ({
|
|
45410
|
+
opacity: 1,
|
|
45411
|
+
transform: labelAnchorTransform(lbl.placement, 0)
|
|
45412
|
+
}))
|
|
45413
|
+
);
|
|
45414
|
+
return;
|
|
45415
|
+
}
|
|
45416
|
+
const reduceMotion = typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
45417
|
+
if (reduceMotion) {
|
|
45418
|
+
playedRef.current = true;
|
|
45419
|
+
setRevealWidth(geometry.width);
|
|
45420
|
+
setLabelStyles(
|
|
45421
|
+
geometry.labels.map((lbl) => ({
|
|
45422
|
+
opacity: 1,
|
|
45423
|
+
transform: labelAnchorTransform(lbl.placement, 0)
|
|
45424
|
+
}))
|
|
45425
|
+
);
|
|
45426
|
+
return;
|
|
45427
|
+
}
|
|
45428
|
+
playedRef.current = true;
|
|
45429
|
+
setRevealWidth(0);
|
|
45430
|
+
setLabelStyles(
|
|
45431
|
+
geometry.labels.map((lbl) => ({
|
|
45432
|
+
opacity: 0,
|
|
45433
|
+
transform: labelAnchorTransform(lbl.placement, 6)
|
|
45434
|
+
}))
|
|
45435
|
+
);
|
|
45436
|
+
const generation = revealGenerationRef.current;
|
|
45437
|
+
const start = performance.now();
|
|
45438
|
+
const tick = (now) => {
|
|
45439
|
+
if (generation !== revealGenerationRef.current) return;
|
|
45440
|
+
const elapsed = now - start;
|
|
45441
|
+
const t = Math.min(1, elapsed / REVEAL_DURATION_MS);
|
|
45442
|
+
const eased = easePower1InOut(t);
|
|
45443
|
+
setRevealWidth(geometry.width * eased);
|
|
45444
|
+
setLabelStyles(
|
|
45445
|
+
geometry.labels.map((lbl, i) => {
|
|
45446
|
+
const labelStart = ribbonLabelRevealTime(i, REVEAL_DURATION_MS / 1e3) * 1e3;
|
|
45447
|
+
const labelDur = 550;
|
|
45448
|
+
const lt2 = Math.min(1, Math.max(0, (elapsed - labelStart) / labelDur));
|
|
45449
|
+
const lo = easePower2Out(lt2);
|
|
45450
|
+
const y = 6 * (1 - lo);
|
|
45451
|
+
return { opacity: lo, transform: labelAnchorTransform(lbl.placement, y) };
|
|
45452
|
+
})
|
|
45453
|
+
);
|
|
45454
|
+
if (t < 1) {
|
|
45455
|
+
rafRef.current = requestAnimationFrame(tick);
|
|
45456
|
+
} else {
|
|
45457
|
+
setRevealWidth(geometry.width);
|
|
45458
|
+
setLabelStyles(
|
|
45459
|
+
geometry.labels.map((lbl) => ({
|
|
45460
|
+
opacity: 1,
|
|
45461
|
+
transform: labelAnchorTransform(lbl.placement, 0)
|
|
45462
|
+
}))
|
|
45463
|
+
);
|
|
45464
|
+
}
|
|
45465
|
+
};
|
|
45466
|
+
rafRef.current = requestAnimationFrame(tick);
|
|
45467
|
+
}, [animated, geometry]);
|
|
45468
|
+
React.useEffect(() => {
|
|
45469
|
+
if (!geometry || playedRef.current) return;
|
|
45470
|
+
const scheduleId = ++revealScheduleRef.current;
|
|
45471
|
+
const delay = scheduleId === 1 ? REVEAL_DELAY_MS : 0;
|
|
45472
|
+
const timer = window.setTimeout(() => {
|
|
45473
|
+
if (scheduleId !== revealScheduleRef.current) return;
|
|
45474
|
+
runReveal();
|
|
45475
|
+
}, delay);
|
|
45476
|
+
return () => window.clearTimeout(timer);
|
|
45477
|
+
}, [geometry, runReveal]);
|
|
45478
|
+
const suppressLabels = hideLabels || layout === "mark";
|
|
45479
|
+
const activeGeometry = geometry && geometry.bandCount === bandCount ? geometry : null;
|
|
45480
|
+
const hasExplicitWidth = chartWidth != null && Number.isFinite(chartWidth) && chartWidth > 0;
|
|
45481
|
+
const rootClass = [
|
|
45482
|
+
"fairmint-equity-ribbon",
|
|
45483
|
+
RIBBON_BACKGROUND_CLASS[background],
|
|
45484
|
+
layout === "mark" ? "fairmint-equity-ribbon--layout-mark" : "",
|
|
45485
|
+
hasExplicitWidth ? "fairmint-equity-ribbon--has-chart-width" : "",
|
|
45486
|
+
suppressLabels ? "fairmint-equity-ribbon--hidden-labels" : "",
|
|
45487
|
+
className ?? ""
|
|
45488
|
+
].filter(Boolean).join(" ");
|
|
45489
|
+
const resolvedGapColor = gapColor ?? (background === "white" ? ribbonChartSurface.white : background === "black" ? ribbonChartSurface.black : ribbonChartSurface.black);
|
|
45490
|
+
const nominalWidthPx = hasExplicitWidth && chartWidth ? nominalChartWidthPx(chartWidth, activeGeometry?.height ?? 0) : null;
|
|
45491
|
+
const rootStyle = {
|
|
45492
|
+
...RIBBON_SURFACE_CSS_VARS,
|
|
45493
|
+
"--fairmint-ribbon-gap-color": resolvedGapColor,
|
|
45494
|
+
...style,
|
|
45495
|
+
...height ? { height } : {},
|
|
45496
|
+
...nominalWidthPx != null ? { "--fairmint-ribbon-nominal-width": `${nominalWidthPx}px` } : {}
|
|
45497
|
+
};
|
|
45498
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: rootClass, style: rootStyle, children: [
|
|
45499
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
45500
|
+
"svg",
|
|
45501
|
+
{
|
|
45502
|
+
className: "fairmint-equity-ribbon__svg",
|
|
45503
|
+
preserveAspectRatio: "none",
|
|
45504
|
+
"aria-hidden": "true",
|
|
45505
|
+
viewBox: activeGeometry ? `0 0 ${activeGeometry.width} ${activeGeometry.height}` : "0 0 1 1",
|
|
45506
|
+
children: [
|
|
45507
|
+
/* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
|
|
45508
|
+
bandGradients.map((g) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
45509
|
+
"linearGradient",
|
|
45510
|
+
{
|
|
45511
|
+
id: `${uid}-bg${g.idSuffix}`,
|
|
45512
|
+
x1: "0",
|
|
45513
|
+
y1: "1",
|
|
45514
|
+
x2: "1",
|
|
45515
|
+
y2: "0",
|
|
45516
|
+
children: [
|
|
45517
|
+
/* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0", stopColor: g.start }),
|
|
45518
|
+
/* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "1", stopColor: g.end })
|
|
45519
|
+
]
|
|
45520
|
+
},
|
|
45521
|
+
g.idSuffix
|
|
45522
|
+
)),
|
|
45523
|
+
/* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: `${uid}-revealclip`, children: /* @__PURE__ */ jsxRuntime.jsx("rect", { x: 0, y: -1, width: revealWidth, height: (activeGeometry?.height ?? 1) + 2 }) }),
|
|
45524
|
+
activeGeometry ? activeGeometry.paths.map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: `${uid}-bandclip${i}`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
45525
|
+
"rect",
|
|
45526
|
+
{
|
|
45527
|
+
x: 0,
|
|
45528
|
+
y: -1,
|
|
45529
|
+
width: activeGeometry.clipWidthPx[i],
|
|
45530
|
+
height: activeGeometry.height + 2
|
|
45531
|
+
}
|
|
45532
|
+
) }, `bandclip-${bandGradients[i].idSuffix}`)) : null
|
|
45533
|
+
] }),
|
|
45534
|
+
/* @__PURE__ */ jsxRuntime.jsx("g", { clipPath: `url(#${uid}-revealclip)`, children: activeGeometry?.paths.map((d, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
45535
|
+
"path",
|
|
45536
|
+
{
|
|
45537
|
+
className: "fairmint-equity-ribbon__band",
|
|
45538
|
+
fill: `url(#${uid}-bg${bandGradients[i].idSuffix})`,
|
|
45539
|
+
clipPath: `url(#${uid}-bandclip${i})`,
|
|
45540
|
+
d
|
|
45541
|
+
},
|
|
45542
|
+
bandGradients[i].idSuffix
|
|
45543
|
+
)) })
|
|
45544
|
+
]
|
|
45545
|
+
}
|
|
45546
|
+
),
|
|
45547
|
+
!suppressLabels && activeGeometry?.labels.map((lbl, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
45548
|
+
"div",
|
|
45549
|
+
{
|
|
45550
|
+
className: labelClassName(lbl.placement),
|
|
45551
|
+
style: {
|
|
45552
|
+
left: `${lbl.leftPct}%`,
|
|
45553
|
+
top: `${lbl.topPct}%`,
|
|
45554
|
+
color: labelColor,
|
|
45555
|
+
opacity: labelStyles[i]?.opacity ?? 0,
|
|
45556
|
+
transform: labelStyles[i]?.transform
|
|
45557
|
+
},
|
|
45558
|
+
children: lbl.text
|
|
45559
|
+
},
|
|
45560
|
+
`${lbl.text}-${lbl.index}`
|
|
45561
|
+
))
|
|
45562
|
+
] });
|
|
45563
|
+
}
|
|
45564
|
+
function FairmintRibbonMark({
|
|
45565
|
+
size: size2 = 64,
|
|
45566
|
+
bandCount = 5,
|
|
45567
|
+
gradients,
|
|
45568
|
+
background = "black",
|
|
45569
|
+
gapColor,
|
|
45570
|
+
labelColor,
|
|
45571
|
+
className,
|
|
45572
|
+
style
|
|
45573
|
+
}) {
|
|
45574
|
+
const dimension = `${size2}px`;
|
|
45575
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
45576
|
+
EquityRibbonChart,
|
|
45577
|
+
{
|
|
45578
|
+
bandCount,
|
|
45579
|
+
gradients,
|
|
45580
|
+
background,
|
|
45581
|
+
gapColor,
|
|
45582
|
+
labelColor,
|
|
45583
|
+
layout: "mark",
|
|
45584
|
+
animated: false,
|
|
45585
|
+
hideLabels: true,
|
|
45586
|
+
className: ["fairmint-ribbon-mark", className].filter(Boolean).join(" "),
|
|
45587
|
+
height: dimension,
|
|
45588
|
+
style: { width: dimension, height: dimension, ...style }
|
|
45589
|
+
}
|
|
45590
|
+
);
|
|
45591
|
+
}
|
|
45019
45592
|
function InvestmentCard({
|
|
45020
45593
|
companyName,
|
|
45021
45594
|
logoUrl,
|
|
@@ -45785,6 +46358,8 @@ exports.ConfidentialityBanner = ConfidentialityBanner;
|
|
|
45785
46358
|
exports.ConfirmDialog = ConfirmDialog;
|
|
45786
46359
|
exports.Container = Container;
|
|
45787
46360
|
exports.Currency = Currency;
|
|
46361
|
+
exports.DEFAULT_RIBBON_CONFIG = DEFAULT_RIBBON_CONFIG;
|
|
46362
|
+
exports.DEFAULT_RIBBON_LABELS = DEFAULT_RIBBON_LABELS;
|
|
45788
46363
|
exports.DataRow = DataRow;
|
|
45789
46364
|
exports.DataTable = DataTable;
|
|
45790
46365
|
exports.DateDisplay = DateDisplay;
|
|
@@ -45797,12 +46372,14 @@ exports.EditableSection = EditableSection;
|
|
|
45797
46372
|
exports.EmailField = EmailField;
|
|
45798
46373
|
exports.EmptyState = EmptyState;
|
|
45799
46374
|
exports.EquityGrantCard = EquityGrantCard;
|
|
46375
|
+
exports.EquityRibbonChart = EquityRibbonChart;
|
|
45800
46376
|
exports.ErrorFallback = ErrorFallback;
|
|
45801
46377
|
exports.ErrorPage = ErrorPage;
|
|
45802
46378
|
exports.EthereumAddressField = EthereumAddressField;
|
|
45803
46379
|
exports.Eyebrow = Eyebrow;
|
|
45804
46380
|
exports.FairmintLogo = FairmintLogo;
|
|
45805
46381
|
exports.FairmintProvider = FairmintProvider;
|
|
46382
|
+
exports.FairmintRibbonMark = FairmintRibbonMark;
|
|
45806
46383
|
exports.Flex = Flex;
|
|
45807
46384
|
exports.Form = Form;
|
|
45808
46385
|
exports.FormField = FormField;
|
|
@@ -45813,6 +46390,8 @@ exports.InvestorProfileCard = InvestorProfileCard;
|
|
|
45813
46390
|
exports.ListRow = ListRow;
|
|
45814
46391
|
exports.Loader = Loader;
|
|
45815
46392
|
exports.LoadingSpinner = LoadingSpinner;
|
|
46393
|
+
exports.MARK_RIBBON_CONFIG = MARK_RIBBON_CONFIG;
|
|
46394
|
+
exports.MARK_RIBBON_RIGHT_EDGE = MARK_RIBBON_RIGHT_EDGE;
|
|
45816
46395
|
exports.MOBILE_BREAKPOINT = MOBILE_BREAKPOINT;
|
|
45817
46396
|
exports.Menu = Menu;
|
|
45818
46397
|
exports.Modal = Modal;
|
|
@@ -45832,6 +46411,8 @@ exports.PhoneField = PhoneField;
|
|
|
45832
46411
|
exports.PhotoCropModal = PhotoCropModal;
|
|
45833
46412
|
exports.PinInput = PinInput;
|
|
45834
46413
|
exports.Progress = Progress;
|
|
46414
|
+
exports.RIBBON_BACKGROUND_CLASS = RIBBON_BACKGROUND_CLASS;
|
|
46415
|
+
exports.RIBBON_BAND_GRADIENTS = RIBBON_BAND_GRADIENTS;
|
|
45835
46416
|
exports.RadioCard = RadioCard;
|
|
45836
46417
|
exports.RedactedValue = RedactedValue;
|
|
45837
46418
|
exports.ScrollArea = ScrollArea;
|
|
@@ -45865,6 +46446,7 @@ exports.WalletList = WalletList;
|
|
|
45865
46446
|
exports.ZERO_ETHEREUM_ADDRESS = ZERO_ETHEREUM_ADDRESS;
|
|
45866
46447
|
exports.ZipField = ZipField;
|
|
45867
46448
|
exports.brandColors = brandColors;
|
|
46449
|
+
exports.clampBandCount = clampBandCount;
|
|
45868
46450
|
exports.colors = colors;
|
|
45869
46451
|
exports.createFairmintMantineProviderProps = createFairmintMantineProviderProps;
|
|
45870
46452
|
exports.createZipSchema = createZipSchema;
|