Skip to content

Commit f76da5d

Browse files
More stuff
1 parent 0194021 commit f76da5d

File tree

12 files changed

+219
-17
lines changed

12 files changed

+219
-17
lines changed

.changeset/six-lions-wonder.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@star4/react": patch
3+
---
4+
5+
- added disabled button and radio button styles
6+
- added Material Symbol icon component
7+
- dialog styling changes

examples/react/src/app.tsx

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Dialog, FocusRing, Ripple, Button, Radio } from "@star4/react";
1+
import { Dialog, FocusRing, Ripple, Button, Radio, MaterialSymbol } from "@star4/react";
22
import { forwardRef, useRef, useState, type FC } from "react";
33

44
export const App: FC = () => {
@@ -10,12 +10,13 @@ export const App: FC = () => {
1010
<div>
1111
<Button
1212
variant="filled"
13-
onClick={() => setOpen(true)} disabled={open}
13+
onClick={() => setOpen(true)}
14+
disabled={open}
1415
label="Open" />
1516
<Dialog
1617
open={open}
1718
onCancel={() => setOpen(false)}
18-
icon={"Delete"}
19+
icon={<MaterialSymbol name="delete" />}
1920
headline="Permanently delete?"
2021
content="Deleting the selected photos will also remove them from all synced devices."
2122
actions={
@@ -35,6 +36,12 @@ export const App: FC = () => {
3536
<Radio groupValue={value} value={2} onChange={setValue as any} />
3637
<Radio groupValue={value} value={3} onChange={setValue as any} />
3738
<Radio groupValue={value} value={4} onChange={setValue as any} />
39+
40+
<Radio disabled groupValue={value} value={0} />
41+
<Radio disabled groupValue={value} value={1} />
42+
<Radio disabled groupValue={value} value={2} />
43+
<Radio disabled groupValue={value} value={3} />
44+
<Radio disabled groupValue={value} value={4} />
3845
</div>
3946
);
4047
}

packages/react/src/button/button.css.ts

+60-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const container = recipe({
2323
background: "transparent",
2424
border: "none",
2525
outline: "none",
26+
userSelect: "none",
2627

2728
position: "relative",
2829
minWidth: 64,
@@ -42,6 +43,11 @@ const container = recipe({
4243
transitionDuration: "280ms",
4344
transitionTimingFunction: THEME.motion.easing.emphasized,
4445

46+
vars: {
47+
[THEME.component.icon.size]: "18px",
48+
[THEME.component.materialSymbol.opticalSize]: "18",
49+
},
50+
4551
// Touch target
4652
"::before": {
4753
content: "",
@@ -136,6 +142,59 @@ const container = recipe({
136142
},
137143
},
138144
},
145+
compoundVariants: [
146+
{
147+
variants: {
148+
variant: "elevated",
149+
disabled: true,
150+
},
151+
style: {
152+
backgroundColor: `color-mix(in srgb, transparent, ${THEME.color.onSurface} 12%)`,
153+
color: `color-mix(in srgb, transparent, ${THEME.color.onSurface} 38%)`,
154+
155+
},
156+
},
157+
{
158+
variants: {
159+
variant: "filled",
160+
disabled: true,
161+
},
162+
style: {
163+
backgroundColor: `color-mix(in srgb, transparent, ${THEME.color.onSurface} 12%)`,
164+
color: `color-mix(in srgb, transparent, ${THEME.color.onSurface} 38%)`,
165+
166+
},
167+
},
168+
{
169+
variants: {
170+
variant: "filledTonal",
171+
disabled: true,
172+
},
173+
style: {
174+
backgroundColor: `color-mix(in srgb, transparent, ${THEME.color.onSurface} 12%)`,
175+
color: `color-mix(in srgb, transparent, ${THEME.color.onSurface} 38%)`,
176+
177+
},
178+
},
179+
{
180+
variants: {
181+
variant: "outlined",
182+
disabled: true,
183+
},
184+
style: {
185+
color: `color-mix(in srgb, transparent, ${THEME.color.onSurface} 38%)`,
186+
},
187+
},
188+
{
189+
variants: {
190+
variant: "text",
191+
disabled: true,
192+
},
193+
style: {
194+
color: `color-mix(in srgb, transparent, ${THEME.color.onSurface} 38%)`,
195+
},
196+
},
197+
],
139198
defaultVariants: {
140199
disabled: false,
141200
},
@@ -151,7 +210,7 @@ const outline = recipe({
151210
},
152211
variants: {
153212
disabled: {
154-
213+
borderColor: `color-mix(in srgb, transparent, ${THEME.color.onSurface} 12%)`,
155214
},
156215
},
157216
});

packages/react/src/button/button.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export const Button = forwardRef<Button.Element, Button.Props>(
4444
className={clsx(
4545
styles.container({
4646
variant,
47+
disabled,
4748
}),
4849
className,
4950
)}

packages/react/src/dialog/dialog.css.ts

+39-4
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,23 @@ const enter = keyframes({
1515
transform: "translateY(-50px)",
1616
clipPath: `inset(0 0 100% 0 round ${THEME.shape.corner.extraLarge})`,
1717
},
18+
to: {
19+
clipPath: `inset(0 0 0 0 round ${THEME.shape.corner.extraLarge})`,
20+
},
1821
});
1922
const exit = keyframes({
23+
from: {
24+
clipPath: `inset(0 0 0 0 round ${THEME.shape.corner.extraLarge})`,
25+
},
2026
to: {
2127
transform: "translateY(-50px)",
2228
clipPath: `inset(0 0 65% 0 round ${THEME.shape.corner.extraLarge})`,
2329
},
2430
});
2531
const fadeIn = keyframes({
2632
from: { opacity: 0 },
27-
// to: { opacity: 1 },
2833
});
2934
const fadeOut = keyframes({
30-
// from: { opacity: 1 },
3135
to: { opacity: 0 },
3236
});
3337

@@ -36,6 +40,24 @@ const scrim = recipe({
3640
backgroundColor: THEME.color.scrim,
3741
opacity: 0.32,
3842
},
43+
variants: {
44+
entering: {
45+
true: {
46+
animationName: fadeIn,
47+
animationDuration: THEME.motion.duration.long2,
48+
animationTimingFunction: THEME.motion.easing.linear,
49+
animationFillMode: "both",
50+
},
51+
},
52+
exiting: {
53+
true: {
54+
animationName: fadeOut,
55+
animationDuration: THEME.motion.duration.short3,
56+
animationTimingFunction: THEME.motion.easing.linear,
57+
animationFillMode: "forwards",
58+
},
59+
},
60+
},
3961
});
4062

4163
const container = recipe({
@@ -53,9 +75,10 @@ const container = recipe({
5375
flexDirection: "column",
5476
overflow: "hidden",
5577

78+
borderRadius: THEME.shape.corner.extraLarge,
5679
backgroundColor: THEME.color.surfaceContainerHighest,
5780

58-
clipPath: `inset(0 0 0 0 round ${THEME.shape.corner.extraLarge})`,
81+
// clipPath: `inset(0 0 0 0 round ${THEME.shape.corner.extraLarge})`,
5982

6083
// TODO: doesn't work because of clip-path
6184
// boxShadow: `
@@ -93,6 +116,7 @@ const headline = recipe({
93116
display: "flex",
94117
flexDirection: "column",
95118
alignItems: "center",
119+
paddingBlockEnd: 16,
96120

97121
...THEME.typescale.headline.small,
98122
color: THEME.color.onSurface,
@@ -147,8 +171,19 @@ const headlineText = style({
147171

148172
const content = recipe({
149173
base: {
174+
position: "relative",
175+
height: "min-content",
176+
flex: 1,
177+
178+
paddingInline: 24,
179+
150180
...THEME.typescale.body.medium,
151181
color: THEME.color.onSurfaceVariant,
182+
183+
184+
// flex: 1;
185+
// height: min-content; // Needed for Safari
186+
// position: relative;
152187
},
153188
variants: {
154189
entering: {
@@ -192,7 +227,7 @@ const actions = recipe({
192227
gap: 8,
193228

194229
paddingInline: 24,
195-
paddingBlock: "16px 24px",
230+
paddingBlock: 24,
196231
},
197232
variants: {
198233
entering: {

packages/react/src/dialog/dialog.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export const Dialog: FC<Dialog.Props> = ({
3838

3939
return (
4040
<Modal open={isMounted} onCancel={onCancel} className={styles.modal()}>
41-
<Modal.Backdrop className={styles.scrim()} />
41+
<Modal.Backdrop className={styles.scrim({ entering, exiting })} />
4242
<div
4343
className={
4444
styles.container({ entering, exiting })
@@ -51,14 +51,14 @@ export const Dialog: FC<Dialog.Props> = ({
5151
{headline && (
5252
<h2 className={styles.headlineText}>{headline}</h2>
5353
)}
54-
<Divider />
54+
{/* <Divider /> */}
5555
</div>
5656
<div className={styles.content({ entering, exiting })}>
5757
{content}
5858
</div>
5959
{actions && (
6060
<div className={styles.actions({ entering, exiting })}>
61-
<Divider />
61+
{/* <Divider /> */}
6262
{actions}
6363
</div>
6464
)}

packages/react/src/icon/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./material-symbol";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { THEME } from "@star4/vanilla-extract";
2+
import { createThemeContract, fallbackVar, style } from "@vanilla-extract/css";
3+
4+
const fontVariationSettings = (values: Record<string, string | number>) => {
5+
return Object.entries(values)
6+
.map(([axis, value]) => `"${axis}" ${value}`)
7+
.join(",");
8+
}
9+
10+
const icon = style({
11+
fontFamily: fallbackVar(THEME.component.materialSymbol.font, `"Material Symbols Outlined"`),
12+
fontSize: fallbackVar(THEME.component.icon.size, "24px"),
13+
14+
fontWeight: "normal",
15+
fontStyle: "normal",
16+
lineHeight: 1,
17+
letterSpacing: "normal",
18+
textTransform: "none",
19+
display: "inline-block",
20+
whiteSpace: "nowrap",
21+
wordWrap: "normal",
22+
direction: "ltr",
23+
WebkitFontSmoothing: "antialiased",
24+
fontFeatureSettings: `"liga"`,
25+
26+
fontOpticalSizing: "auto",
27+
28+
color: "currentcolor",
29+
30+
inlineSize: fallbackVar(THEME.component.icon.size, "24px"),
31+
blockSize: fallbackVar(THEME.component.icon.size, "24px"),
32+
userSelect: "none",
33+
34+
transitionProperty: "font-variation-settings",
35+
transitionDuration: "inherit",
36+
transitionDelay: "inherit",
37+
transitionTimingFunction: "inherit",
38+
39+
fontVariationSettings: fontVariationSettings({
40+
FILL: fallbackVar(THEME.component.materialSymbol.fill, "0"),
41+
wght: fallbackVar(THEME.component.materialSymbol.weight, "400"),
42+
GRAD: fallbackVar(THEME.component.materialSymbol.grade, "0"),
43+
// opsz: fallbackVar(THEME.component.materialSymbol.opticalSize, "24"),
44+
}),
45+
});
46+
47+
export const styles = {
48+
icon,
49+
} as const;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { forwardRef, type HTMLAttributes } from "react";
2+
import clsx from "clsx/lite";
3+
import { styles } from "./material-symbol.css";
4+
5+
export namespace MaterialSymbol {
6+
export type Props =
7+
& Omit<
8+
HTMLAttributes<HTMLElement>,
9+
"children"
10+
>
11+
& {
12+
name: string;
13+
};
14+
export interface Element extends HTMLElement {}
15+
}
16+
17+
export const MaterialSymbol = forwardRef<MaterialSymbol.Element, MaterialSymbol.Props>(
18+
({ name, className, ...rest }, forwardedRef) => {
19+
return (
20+
<span
21+
ref={forwardedRef}
22+
className={clsx(styles.icon, className)}
23+
{...rest}
24+
children={name} />
25+
)
26+
},
27+
);

packages/react/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export * from "./radio";
55
export * from "./dialog";
66
export * from "./focus";
77
export * from "./ripple";
8+
export * from "./icon";
89

910
// Utility components
1011
export * from "./modal";

0 commit comments

Comments
 (0)