Skip to content

Commit cd579ef

Browse files
committed
release: ship useGlassHighlightEffect in @protohiro/effects@0.3.0
1 parent d971e88 commit cd579ef

14 files changed

Lines changed: 323 additions & 6 deletions

File tree

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Protohiro Effects
22

3-
Protohiro Effects is a zero-wrapper React library for hard CSS effects like gradient borders, glow rings, noise overlays, and spotlight overlays.
3+
Protohiro Effects is a zero-wrapper React library for hard CSS effects like gradient borders, glass highlights, glow rings, noise overlays, and spotlight overlays.
44

55
## Live demo
66

@@ -40,6 +40,20 @@ Options:
4040
- `angle?: string | number`
4141
- `disabled?: boolean`
4242

43+
### `useGlassHighlightEffect(options)`
44+
45+
Options:
46+
- `color?: string`
47+
- `edgeOpacity?: number`
48+
- `sheenOpacity?: number`
49+
- `tintOpacity?: number`
50+
- `angle?: string | number`
51+
- `blur?: string | number`
52+
- `radius?: string | number`
53+
- `inset?: string | number`
54+
- `saturate?: number`
55+
- `disabled?: boolean`
56+
4357
### `useGlowEffect(options)`
4458

4559
Options:

apps/demo/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# @protohiro/effects-demo
22

3+
## 0.1.3
4+
5+
### Patch Changes
6+
7+
- Updated dependencies
8+
- @protohiro/effects@0.3.0
9+
310
## 0.1.2
411

512
### Patch Changes

apps/demo/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@protohiro/effects-demo",
3-
"version": "0.1.2",
3+
"version": "0.1.3",
44
"private": true,
55
"type": "module",
66
"scripts": {

apps/demo/src/App.tsx

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
useGlassHighlightEffect,
23
useGlowEffect,
34
useGradientBorderEffect,
45
useNoiseEffect,
@@ -45,6 +46,10 @@ function useGlowStoryHook(options: DemoOptions): RefCallback<HTMLElement> {
4546
return useGlowEffect(options);
4647
}
4748

49+
function useGlassHighlightStoryHook(options: DemoOptions): RefCallback<HTMLElement> {
50+
return useGlassHighlightEffect(options);
51+
}
52+
4853
function useNoiseStoryHook(options: DemoOptions): RefCallback<HTMLElement> {
4954
return useNoiseEffect(options);
5055
}
@@ -104,6 +109,45 @@ const STORIES: EffectStory[] = [
104109
{ key: 'disabled', label: 'Disabled', type: 'checkbox' },
105110
],
106111
},
112+
{
113+
id: 'glass-highlight',
114+
title: 'Glass Highlight',
115+
description: 'Glassy edge light and sheen overlay for premium surfaces.',
116+
hookName: 'useGlassHighlightEffect',
117+
componentName: 'GlassHighlightCard',
118+
previewText: 'Glass Highlight Surface',
119+
previewElement: 'article',
120+
previewStyle: {
121+
background:
122+
'linear-gradient(145deg, rgba(15, 23, 42, 0.96) 0%, rgba(30, 41, 59, 0.92) 52%, rgba(15, 23, 42, 0.98) 100%)',
123+
color: '#e2e8f0',
124+
border: '1px solid rgba(148, 163, 184, 0.22)',
125+
boxShadow:
126+
'0 18px 48px rgba(15, 23, 42, 0.34), inset 0 1px 0 rgba(255, 255, 255, 0.04)',
127+
} as CSSProperties,
128+
hook: useGlassHighlightStoryHook,
129+
defaults: {
130+
color: '#a855f7',
131+
edgeOpacity: 0.3,
132+
sheenOpacity: 0.44,
133+
tintOpacity: 0.56,
134+
angle: '132deg',
135+
blur: 0,
136+
inset: 0,
137+
saturate: 1.85,
138+
},
139+
controls: [
140+
{ key: 'color', label: 'Color', type: 'color' },
141+
{ key: 'edgeOpacity', label: 'Edge opacity', type: 'range', min: 0, max: 1, step: 0.01 },
142+
{ key: 'sheenOpacity', label: 'Sheen opacity', type: 'range', min: 0, max: 1, step: 0.01 },
143+
{ key: 'tintOpacity', label: 'Tint opacity', type: 'range', min: 0, max: 1, step: 0.01 },
144+
{ key: 'angle', label: 'Angle', type: 'text' },
145+
{ key: 'blur', label: 'Blur', type: 'number', min: 0, max: 40, step: 1 },
146+
{ key: 'inset', label: 'Inset', type: 'number', min: -8, max: 24, step: 1 },
147+
{ key: 'saturate', label: 'Saturate', type: 'range', min: 0, max: 2, step: 0.01 },
148+
{ key: 'disabled', label: 'Disabled', type: 'checkbox' },
149+
],
150+
},
107151
{
108152
id: 'noise',
109153
title: 'Noise',
@@ -299,7 +343,7 @@ function EffectPlayground({ story }: { story: EffectStory }) {
299343
</header>
300344
<div className="demo-preview">
301345
<PreviewTag ref={ref} className={previewClassName} style={story.previewStyle}>
302-
{story.previewText}
346+
<span className="demo-card-content">{story.previewText}</span>
303347
</PreviewTag>
304348
</div>
305349
</div>

apps/demo/src/styles.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ h1 {
147147
font-weight: 600;
148148
}
149149

150+
.demo-card-content {
151+
position: relative;
152+
z-index: 1;
153+
display: inline-block;
154+
text-shadow: 0 2px 12px rgba(2, 6, 23, 0.42);
155+
}
156+
150157
.demo-card-spotlight {
151158
min-height: 136px;
152159
display: flex;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
{
5151
"name": "@protohiro/effects",
5252
"path": "packages/react/dist/index.js",
53-
"limit": "5.5 kB"
53+
"limit": "5.6 kB"
5454
}
5555
]
5656
}

packages/react/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# @protohiro/effects
22

3+
## 0.3.0
4+
5+
### Minor Changes
6+
7+
- Add a new `useGlassHighlightEffect` hook for premium glass-sheen surfaces.
8+
9+
Highlights:
10+
- Adds a new glass highlight effect with configurable edge, sheen, tint, blur, inset, and saturation options.
11+
- Extends the shared effect stylesheet and demo coverage for the new effect.
12+
- Updates public docs and exports for the expanded hook surface.
13+
314
## 0.2.0
415

516
### Minor Changes

packages/react/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,25 @@ export function Button() {
2222
## Hooks
2323

2424
- `useGradientBorderEffect`
25+
- `useGlassHighlightEffect`
2526
- `useGlowEffect`
2627
- `useNoiseEffect`
2728
- `useSpotlightEffect`
2829

30+
### `useGlassHighlightEffect(options)`
31+
32+
Options:
33+
- `color?: string`
34+
- `edgeOpacity?: number`
35+
- `sheenOpacity?: number`
36+
- `tintOpacity?: number`
37+
- `angle?: string | number`
38+
- `blur?: string | number`
39+
- `radius?: string | number`
40+
- `inset?: string | number`
41+
- `saturate?: number`
42+
- `disabled?: boolean`
43+
2944
Live demo:
3045
https://libs.protohiro.com/effects/
3146

packages/react/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@protohiro/effects",
3-
"version": "0.2.0",
3+
"version": "0.3.0",
44
"description": "Zero-wrapper React hooks for composable CSS effects.",
55
"license": "MIT",
66
"type": "module",
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { toCssAngle, toCssLength, toCssNumber } from '@protohiro/effects-core';
2+
import { useMemo } from 'react';
3+
4+
import type { GlassHighlightOptions } from '../types';
5+
import { EFFECT_STYLES } from '../shared/effectStyles';
6+
import { useCssEffect } from '../shared/useCssEffect';
7+
8+
const STYLE_ID = 'protohiro-effects-base';
9+
10+
function clampUnit(value: number | undefined): number | undefined {
11+
if (value === undefined || Number.isNaN(value)) {
12+
return undefined;
13+
}
14+
15+
return Math.max(0, Math.min(1, value));
16+
}
17+
18+
export function useGlassHighlightEffect<T extends HTMLElement = HTMLElement>(
19+
options: GlassHighlightOptions = {},
20+
) {
21+
const edgeOpacity = clampUnit(options.edgeOpacity);
22+
const sheenOpacity = clampUnit(options.sheenOpacity);
23+
const tintOpacity = clampUnit(options.tintOpacity);
24+
const saturate =
25+
options.saturate === undefined || Number.isNaN(options.saturate)
26+
? undefined
27+
: Math.max(0, options.saturate);
28+
29+
const vars = useMemo(
30+
() => ({
31+
'--pe-gh-color': options.color,
32+
'--pe-gh-edge-opacity': toCssNumber(edgeOpacity),
33+
'--pe-gh-sheen-opacity': toCssNumber(sheenOpacity),
34+
'--pe-gh-tint-opacity': toCssNumber(tintOpacity),
35+
'--pe-gh-angle': toCssAngle(options.angle),
36+
'--pe-gh-blur': toCssLength(options.blur),
37+
'--pe-gh-radius': toCssLength(options.radius),
38+
'--pe-gh-inset': toCssLength(options.inset),
39+
'--pe-gh-saturate': toCssNumber(saturate),
40+
}),
41+
[
42+
options.color,
43+
edgeOpacity,
44+
sheenOpacity,
45+
tintOpacity,
46+
options.angle,
47+
options.blur,
48+
options.radius,
49+
options.inset,
50+
saturate,
51+
],
52+
);
53+
54+
return useCssEffect<T>({
55+
className: 'pe-glass-highlight',
56+
userClassName: options.className,
57+
vars,
58+
disabled: options.disabled,
59+
styleId: STYLE_ID,
60+
styleText: EFFECT_STYLES,
61+
});
62+
}

0 commit comments

Comments
 (0)