@shohojdhara/atomix 0.6.4 → 0.6.5
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/atomix.css +117 -38
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +1 -1
- package/dist/atomix.min.css.map +1 -1
- package/dist/atomix.umd.js +1 -1
- package/dist/atomix.umd.js.map +1 -1
- package/dist/atomix.umd.min.js +1 -1
- package/dist/charts.d.ts +30 -1
- package/dist/charts.js +566 -597
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +30 -1
- package/dist/core.js +600 -624
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +30 -1
- package/dist/forms.js +1122 -1163
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +31 -89
- package/dist/heavy.js +1015 -1045
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +378 -104
- package/dist/index.esm.js +10959 -10837
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +10935 -10812
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Accordion/Accordion.tsx +2 -5
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +14 -16
- package/src/components/AtomixGlass/AtomixGlass.tsx +137 -355
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +32 -249
- package/src/components/AtomixGlass/GlassFilter.tsx +62 -68
- package/src/components/AtomixGlass/README.md +2 -1
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +19 -18
- package/src/components/AtomixGlass/glass-border-styles.test.ts +58 -0
- package/src/components/AtomixGlass/glass-border-styles.ts +136 -0
- package/src/components/AtomixGlass/glass-utils.ts +411 -6
- package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +158 -537
- package/src/components/AtomixGlass/stories/Border.stories.tsx +149 -0
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +229 -89
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +29 -340
- package/src/components/AtomixGlass/stories/argTypes.ts +30 -13
- package/src/components/AtomixGlass/stories/premium-presets.ts +206 -0
- package/src/components/AtomixGlass/stories/shared-components.tsx +52 -8
- package/src/components/Badge/Badge.tsx +4 -4
- package/src/components/Button/Button.tsx +2 -6
- package/src/components/Callout/Callout.test.tsx +4 -3
- package/src/components/Callout/Callout.tsx +2 -5
- package/src/components/Dropdown/Dropdown.tsx +3 -7
- package/src/components/Form/Checkbox.tsx +2 -8
- package/src/components/Form/Input.tsx +2 -9
- package/src/components/Form/Radio.tsx +2 -9
- package/src/components/Form/Select.tsx +2 -7
- package/src/components/Form/Textarea.tsx +2 -9
- package/src/components/Messages/Messages.tsx +2 -8
- package/src/components/Modal/Modal.tsx +4 -5
- package/src/components/Navigation/Nav/Nav.tsx +2 -6
- package/src/components/Navigation/Navbar/Navbar.tsx +2 -9
- package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -6
- package/src/components/Pagination/Pagination.tsx +2 -10
- package/src/components/Popover/Popover.tsx +2 -9
- package/src/components/Progress/Progress.tsx +2 -7
- package/src/components/Rating/Rating.tsx +2 -10
- package/src/components/Spinner/Spinner.tsx +2 -7
- package/src/components/Steps/Steps.tsx +2 -10
- package/src/components/Tabs/Tabs.tsx +2 -9
- package/src/components/Toggle/Toggle.tsx +2 -10
- package/src/components/Tooltip/Tooltip.tsx +2 -5
- package/src/lib/composables/useAtomixGlass.ts +41 -10
- package/src/lib/composables/useAtomixGlassStyles.ts +59 -75
- package/src/lib/composables/usePerformanceMonitor.ts +5 -0
- package/src/lib/constants/components.ts +358 -46
- package/src/lib/types/components.ts +33 -1
- package/src/styles/01-settings/_settings.atomix-glass.scss +66 -28
- package/src/styles/02-tools/_tools.glass.scss +45 -3
- package/src/styles/06-components/_components.atomix-glass.scss +114 -77
- package/src/components/AtomixGlass/deprecated/AtomixGlass.deprecated.tsx +0 -390
|
@@ -4,11 +4,11 @@ exports[`AtomixGlass Visual Regression > matches snapshot with default props 1`]
|
|
|
4
4
|
<div>
|
|
5
5
|
<div
|
|
6
6
|
class="c-atomix-glass"
|
|
7
|
-
style="--atomix-glass-radius: 16px; --atomix-glass-transform: translate(0px, 0px)
|
|
7
|
+
style="--atomix-glass-radius: 16px; --atomix-glass-transform: translate(0px, 0px) scaleX(1) scaleY(1); --atomix-glass-container-position: absolute; --atomix-glass-position: absolute; --atomix-glass-top: 0px; --atomix-glass-left: 0px; --atomix-glass-right: auto; --atomix-glass-bottom: auto; --atomix-glass-width: 100%; --atomix-glass-height: 100%; --atomix-glass-container-width: 100%; --atomix-glass-container-height: 100%; --atomix-glass-border-width: 0.5px; --atomix-glass-blend-mode: overlay; --atomix-glass-child-parallax: translate(0px, 0px); --atomix-glass-contrast: 1.02; --atomix-glass-brightness: 1.02; --atomix-glass-border-gradient-1: linear-gradient(136.5deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.027999999999999997) 33%, rgba(255, 255, 255, 0.09324) 66%, rgba(255, 255, 255, 0) 100%); --atomix-glass-border-gradient-2: linear-gradient(133.5deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.07448) 33%, rgba(255, 255, 255, 0.13999999999999999) 66%, rgba(255, 255, 255, 0) 100%); --atomix-glass-hover-1-gradient: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0) 50%); --atomix-glass-hover-2-gradient: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 80%); --atomix-glass-hover-3-gradient: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%); --atomix-glass-base-gradient: linear-gradient(180deg, rgba(0, 0, 0, 0.42) 0%, rgba(0, 0, 0, 0.22) 55%, rgba(0, 0, 0, 0.12) 100%); --atomix-glass-overlay-gradient: radial-gradient(120% 80% at 50% 0%, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0) 55%); --atomix-glass-hover-1-opacity: 0; --atomix-glass-hover-2-opacity: 0; --atomix-glass-hover-3-opacity: 0; --atomix-glass-base-opacity: 0.14; --atomix-glass-overlay-opacity: 0.1; --atomix-glass-overlay-highlight-opacity: 0.04900000000000001;"
|
|
8
8
|
>
|
|
9
9
|
<div
|
|
10
|
-
class="c-atomix-glass__container
|
|
11
|
-
style="--atomix-glass-container-radius: 16px; --atomix-glass-container-backdrop: blur(
|
|
10
|
+
class="c-atomix-glass__container"
|
|
11
|
+
style="--atomix-glass-container-radius: 16px; --atomix-glass-container-backdrop: blur(20.16px) saturate(250%) contrast(1.02) brightness(1.02); --atomix-glass-container-shadow: inset 0 0.5px 0 rgba(255, 255, 255, 0.32), inset 0 1px 2px rgba(255, 255, 255, 0.06), 0 8px 32px rgba(0, 0, 0, 0.28), 0 2px 8px rgba(0, 0, 0, 0.16); --atomix-glass-container-shadow-opacity: 1; --atomix-glass-container-bg: none; --atomix-glass-container-text-shadow: 0px 2px 12px rgba(0, 0, 0, 0.4); --atomix-glass-container-box-shadow: 0 8px 32px rgba(0, 0, 0, 0.32), 0 2px 8px rgba(0, 0, 0, 0.18);"
|
|
12
12
|
>
|
|
13
13
|
<div
|
|
14
14
|
class="c-atomix-glass__inner"
|
|
@@ -33,7 +33,7 @@ exports[`AtomixGlass Visual Regression > matches snapshot with default props 1`]
|
|
|
33
33
|
stop-opacity="0"
|
|
34
34
|
/>
|
|
35
35
|
<stop
|
|
36
|
-
offset="
|
|
36
|
+
offset="78.88%"
|
|
37
37
|
stop-color="black"
|
|
38
38
|
stop-opacity="0"
|
|
39
39
|
/>
|
|
@@ -75,7 +75,7 @@ exports[`AtomixGlass Visual Regression > matches snapshot with default props 1`]
|
|
|
75
75
|
result="EDGE_MASK"
|
|
76
76
|
>
|
|
77
77
|
<fefunca
|
|
78
|
-
tableValues="0 0.
|
|
78
|
+
tableValues="0 0.028000000000000004 1"
|
|
79
79
|
type="discrete"
|
|
80
80
|
/>
|
|
81
81
|
</fecomponenttransfer>
|
|
@@ -89,7 +89,7 @@ exports[`AtomixGlass Visual Regression > matches snapshot with default props 1`]
|
|
|
89
89
|
in="SourceGraphic"
|
|
90
90
|
in2="DISPLACEMENT_MAP"
|
|
91
91
|
result="RED_DISPLACED"
|
|
92
|
-
scale="-
|
|
92
|
+
scale="-28"
|
|
93
93
|
xChannelSelector="R"
|
|
94
94
|
yChannelSelector="B"
|
|
95
95
|
/>
|
|
@@ -98,15 +98,15 @@ exports[`AtomixGlass Visual Regression > matches snapshot with default props 1`]
|
|
|
98
98
|
result="RED_CHANNEL"
|
|
99
99
|
type="matrix"
|
|
100
100
|
values="1 0 0 0 0
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
0 0 0 0 0
|
|
102
|
+
0 0 0 0 0
|
|
103
|
+
0 0 0 1 0"
|
|
104
104
|
/>
|
|
105
105
|
<fedisplacementmap
|
|
106
106
|
in="SourceGraphic"
|
|
107
107
|
in2="DISPLACEMENT_MAP"
|
|
108
108
|
result="GREEN_DISPLACED"
|
|
109
|
-
scale="-
|
|
109
|
+
scale="-28.3136"
|
|
110
110
|
xChannelSelector="R"
|
|
111
111
|
yChannelSelector="B"
|
|
112
112
|
/>
|
|
@@ -115,15 +115,15 @@ exports[`AtomixGlass Visual Regression > matches snapshot with default props 1`]
|
|
|
115
115
|
result="GREEN_CHANNEL"
|
|
116
116
|
type="matrix"
|
|
117
117
|
values="0 0 0 0 0
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
0 1 0 0 0
|
|
119
|
+
0 0 0 0 0
|
|
120
|
+
0 0 0 1 0"
|
|
121
121
|
/>
|
|
122
122
|
<fedisplacementmap
|
|
123
123
|
in="SourceGraphic"
|
|
124
124
|
in2="DISPLACEMENT_MAP"
|
|
125
125
|
result="BLUE_DISPLACED"
|
|
126
|
-
scale="-
|
|
126
|
+
scale="-28.470399999999998"
|
|
127
127
|
xChannelSelector="R"
|
|
128
128
|
yChannelSelector="B"
|
|
129
129
|
/>
|
|
@@ -132,9 +132,9 @@ exports[`AtomixGlass Visual Regression > matches snapshot with default props 1`]
|
|
|
132
132
|
result="BLUE_CHANNEL"
|
|
133
133
|
type="matrix"
|
|
134
134
|
values="0 0 0 0 0
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
135
|
+
0 0 0 0 0
|
|
136
|
+
0 0 1 0 0
|
|
137
|
+
0 0 0 1 0"
|
|
138
138
|
/>
|
|
139
139
|
<feblend
|
|
140
140
|
in="GREEN_CHANNEL"
|
|
@@ -151,7 +151,7 @@ exports[`AtomixGlass Visual Regression > matches snapshot with default props 1`]
|
|
|
151
151
|
<fegaussianblur
|
|
152
152
|
in="RGB_COMBINED"
|
|
153
153
|
result="ABERRATED_BLURRED"
|
|
154
|
-
stdDeviation="0"
|
|
154
|
+
stdDeviation="0.5644800000000001"
|
|
155
155
|
/>
|
|
156
156
|
<fecomposite
|
|
157
157
|
in="ABERRATED_BLURRED"
|
|
@@ -192,6 +192,7 @@ exports[`AtomixGlass Visual Regression > matches snapshot with default props 1`]
|
|
|
192
192
|
</div>
|
|
193
193
|
<div
|
|
194
194
|
class="c-atomix-glass__content"
|
|
195
|
+
style="transform: var(--atomix-glass-child-parallax, none);"
|
|
195
196
|
>
|
|
196
197
|
<div>
|
|
197
198
|
Default Glass
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { ATOMIX_GLASS } from '../../lib/constants/components';
|
|
3
|
+
import {
|
|
4
|
+
buildGlassBorderCssVars,
|
|
5
|
+
formatGlassBorderWidth,
|
|
6
|
+
normalizeBorderConfig,
|
|
7
|
+
} from './glass-border-styles';
|
|
8
|
+
|
|
9
|
+
describe('normalizeBorderConfig', () => {
|
|
10
|
+
it('defaults to enabled when border and withBorder are omitted', () => {
|
|
11
|
+
expect(normalizeBorderConfig()).toEqual({
|
|
12
|
+
enabled: true,
|
|
13
|
+
width: '0.5px',
|
|
14
|
+
opacityMultiplier: 1,
|
|
15
|
+
animated: true,
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('respects legacy withBorder=false', () => {
|
|
20
|
+
expect(normalizeBorderConfig(undefined, false).enabled).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('border object overrides withBorder', () => {
|
|
24
|
+
expect(
|
|
25
|
+
normalizeBorderConfig({ enabled: true, width: 1, opacity: 0.5, animated: false }, false)
|
|
26
|
+
).toEqual({
|
|
27
|
+
enabled: true,
|
|
28
|
+
width: '1px',
|
|
29
|
+
opacityMultiplier: 0.5,
|
|
30
|
+
animated: false,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('formatGlassBorderWidth', () => {
|
|
36
|
+
it('formats numbers as px', () => {
|
|
37
|
+
expect(formatGlassBorderWidth(2)).toBe('2px');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('buildGlassBorderCssVars', () => {
|
|
42
|
+
it('returns static gradients at zero mouse offset', () => {
|
|
43
|
+
const vars = buildGlassBorderCssVars({
|
|
44
|
+
mouseOffset: { x: 0, y: 0 },
|
|
45
|
+
mouseVelocity: { x: 0, y: 0 },
|
|
46
|
+
elasticVelocity: { x: 0, y: 0 },
|
|
47
|
+
borderOpacity: ATOMIX_GLASS.BORDER.DARK.opacity,
|
|
48
|
+
opacityMultiplier: 1,
|
|
49
|
+
tensionFactor: 0,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(vars[ATOMIX_GLASS.BORDER.GRADIENT_CSS_VARS.GRADIENT_1]).toContain('linear-gradient');
|
|
53
|
+
expect(vars[ATOMIX_GLASS.BORDER.GRADIENT_CSS_VARS.GRADIENT_2]).toContain('linear-gradient');
|
|
54
|
+
expect(vars[ATOMIX_GLASS.BORDER.GRADIENT_CSS_VARS.GRADIENT_1]).toContain(
|
|
55
|
+
`${ATOMIX_GLASS.BORDER.GRADIENT.BASE_ANGLE + ATOMIX_GLASS.BORDER.GRADIENT.CHROMATIC_OFFSET}deg`
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { ATOMIX_GLASS } from '../../lib/constants/components';
|
|
2
|
+
import { smoothstep } from './glass-utils';
|
|
3
|
+
import type { GlassBorderConfig } from '../../lib/types/components';
|
|
4
|
+
import type { MousePosition } from '../../lib/types/components';
|
|
5
|
+
|
|
6
|
+
const { BORDER, CONSTANTS } = ATOMIX_GLASS;
|
|
7
|
+
const BORDER_GRADIENT = BORDER.GRADIENT;
|
|
8
|
+
const WHITE = CONSTANTS.PALETTE.WHITE;
|
|
9
|
+
|
|
10
|
+
/** Resolved border configuration after normalizing props. */
|
|
11
|
+
export interface ResolvedGlassBorderConfig {
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
width: string;
|
|
14
|
+
opacityMultiplier: number;
|
|
15
|
+
animated: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Formats border width for CSS custom properties.
|
|
20
|
+
*/
|
|
21
|
+
export function formatGlassBorderWidth(value: string | number | undefined): string {
|
|
22
|
+
if (value === undefined) {
|
|
23
|
+
return BORDER.DEFAULT_WIDTH;
|
|
24
|
+
}
|
|
25
|
+
return typeof value === 'number' ? `${value}px` : value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Resolves `border` and legacy `withBorder` into a single configuration object.
|
|
30
|
+
*/
|
|
31
|
+
export function normalizeBorderConfig(
|
|
32
|
+
border?: boolean | GlassBorderConfig,
|
|
33
|
+
withBorder?: boolean
|
|
34
|
+
): ResolvedGlassBorderConfig {
|
|
35
|
+
const legacyDefault = withBorder ?? true;
|
|
36
|
+
|
|
37
|
+
if (border === undefined) {
|
|
38
|
+
return {
|
|
39
|
+
enabled: legacyDefault,
|
|
40
|
+
width: BORDER.DEFAULT_WIDTH,
|
|
41
|
+
opacityMultiplier: 1,
|
|
42
|
+
animated: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (typeof border === 'boolean') {
|
|
47
|
+
return {
|
|
48
|
+
enabled: border,
|
|
49
|
+
width: BORDER.DEFAULT_WIDTH,
|
|
50
|
+
opacityMultiplier: 1,
|
|
51
|
+
animated: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
enabled: border.enabled ?? legacyDefault,
|
|
57
|
+
width: formatGlassBorderWidth(border.width),
|
|
58
|
+
opacityMultiplier: border.opacity ?? 1,
|
|
59
|
+
animated: border.animated !== false,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface BuildGlassBorderCssVarsParams {
|
|
64
|
+
mouseOffset: MousePosition;
|
|
65
|
+
mouseVelocity: MousePosition;
|
|
66
|
+
elasticVelocity: MousePosition;
|
|
67
|
+
borderOpacity: number;
|
|
68
|
+
opacityMultiplier?: number;
|
|
69
|
+
tensionFactor?: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Builds animated chromatic rim CSS variables for border layers 1 and 2.
|
|
74
|
+
* When empty, SCSS static conic/linear fallbacks apply.
|
|
75
|
+
*/
|
|
76
|
+
export function buildGlassBorderCssVars(
|
|
77
|
+
params: BuildGlassBorderCssVarsParams
|
|
78
|
+
): Record<string, string> {
|
|
79
|
+
const {
|
|
80
|
+
mouseOffset,
|
|
81
|
+
mouseVelocity,
|
|
82
|
+
elasticVelocity,
|
|
83
|
+
borderOpacity,
|
|
84
|
+
opacityMultiplier = 1,
|
|
85
|
+
tensionFactor = 0,
|
|
86
|
+
} = params;
|
|
87
|
+
|
|
88
|
+
const mx = mouseOffset.x;
|
|
89
|
+
const my = mouseOffset.y;
|
|
90
|
+
const absMx = Math.abs(mx);
|
|
91
|
+
|
|
92
|
+
const velocityRotation =
|
|
93
|
+
(mouseVelocity.x + elasticVelocity.x) * BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER;
|
|
94
|
+
const borderGradientAngle =
|
|
95
|
+
BORDER_GRADIENT.BASE_ANGLE + mx * BORDER_GRADIENT.ANGLE_MULTIPLIER + velocityRotation;
|
|
96
|
+
|
|
97
|
+
const chromaticOffset = BORDER_GRADIENT.CHROMATIC_OFFSET;
|
|
98
|
+
const angleR = borderGradientAngle - chromaticOffset;
|
|
99
|
+
const angleB = borderGradientAngle + chromaticOffset;
|
|
100
|
+
|
|
101
|
+
const borderStop1 = Math.max(
|
|
102
|
+
BORDER_GRADIENT.STOP_1.MIN,
|
|
103
|
+
BORDER_GRADIENT.STOP_1.BASE + my * BORDER_GRADIENT.STOP_1.MULTIPLIER
|
|
104
|
+
);
|
|
105
|
+
const borderStop2 = Math.min(
|
|
106
|
+
BORDER_GRADIENT.STOP_2.MAX,
|
|
107
|
+
BORDER_GRADIENT.STOP_2.BASE + my * BORDER_GRADIENT.STOP_2.MULTIPLIER
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const tensionGlow = 1 + tensionFactor * 0.5;
|
|
111
|
+
const opacities = BORDER_GRADIENT.OPACITY;
|
|
112
|
+
const borderOpacities = [
|
|
113
|
+
(opacities.BASE_1 + absMx * opacities.MULTIPLIER_LOW) * tensionGlow,
|
|
114
|
+
(opacities.BASE_2 + absMx * opacities.MULTIPLIER_HIGH) * tensionGlow,
|
|
115
|
+
(opacities.BASE_3 + absMx * opacities.MULTIPLIER_LOW) * tensionGlow,
|
|
116
|
+
(opacities.BASE_4 + absMx * opacities.MULTIPLIER_HIGH) * tensionGlow,
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
const configBorderOpacity = borderOpacity * opacityMultiplier;
|
|
120
|
+
|
|
121
|
+
const gradient1 = `linear-gradient(${angleB}deg, rgba(${WHITE}, 0) 0%, rgba(${WHITE}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${WHITE}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${WHITE}, 0) 100%)`;
|
|
122
|
+
const gradient2 = `linear-gradient(${angleR}deg, rgba(${WHITE}, 0) 0%, rgba(${WHITE}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${WHITE}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${WHITE}, 0) 100%)`;
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
[BORDER.GRADIENT_CSS_VARS.GRADIENT_1]: gradient1,
|
|
126
|
+
[BORDER.GRADIENT_CSS_VARS.GRADIENT_2]: gradient2,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Computes tension factor from elastic translation magnitude (0–1).
|
|
132
|
+
*/
|
|
133
|
+
export function computeBorderTensionFactor(elasticTranslation: MousePosition): number {
|
|
134
|
+
const magnitude = Math.hypot(elasticTranslation.x, elasticTranslation.y);
|
|
135
|
+
return smoothstep(magnitude / 80);
|
|
136
|
+
}
|