@varialkit/segmentcontrol 0.1.1 → 0.1.3
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/docs.md +16 -0
- package/examples.tsx +16 -7
- package/package.json +2 -2
- package/src/SegmentControl.scss +31 -9
- package/src/SegmentControl.tsx +19 -4
- package/src/SegmentControl.types.ts +7 -1
package/docs.md
CHANGED
|
@@ -26,6 +26,22 @@ export function ViewSwitcher() {
|
|
|
26
26
|
- Use `fullWidth` when the control should span its container.
|
|
27
27
|
- Prefer 2-5 segments to keep labels readable.
|
|
28
28
|
- By default, segments size to their content for stable label alignment; `fullWidth` stretches them evenly.
|
|
29
|
+
- Active segments keep the same typography as inactive ones; selection emphasis comes from color, background, and a subtle border instead of a font-weight or shadow change.
|
|
30
|
+
- Use the `radius` prop with `sm`, `md`, `lg`, or `full` to control segment cell rounding; the outer container stays slightly rounder than the cells where the token scale allows it.
|
|
31
|
+
|
|
32
|
+
## Control Props
|
|
33
|
+
|
|
34
|
+
`SegmentControl` accepts the following core props:
|
|
35
|
+
|
|
36
|
+
| Prop | Type | Description |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `value` | `string` | Currently selected segment value. |
|
|
39
|
+
| `onChange` | `(value: string) => void` | Called when selection changes. |
|
|
40
|
+
| `size` | `"small" | "medium" | "large" | "sm" | "md" | "lg"` | Controls control height, spacing, and typography scale. |
|
|
41
|
+
| `radius` | `"sm" | "md" | "lg" | "full"` | Controls segment cell radius using shared radius tokens. |
|
|
42
|
+
| `fullWidth` | `boolean` | Stretches segments evenly across the container. |
|
|
43
|
+
| `movingBackground` | `boolean` | Uses a single animated background indicator that follows hover/focus. |
|
|
44
|
+
| `surfaceStyle` | `"solid" | "translucent" | "glass" | { ... }` | Applies surface material treatment without changing layout tokens. |
|
|
29
45
|
|
|
30
46
|
## Segment Props
|
|
31
47
|
|
package/examples.tsx
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { iconNames } from "@
|
|
3
|
-
import type { SolaraIconName } from "@
|
|
2
|
+
import { iconNames } from "@varialkit/icons";
|
|
3
|
+
import type { SolaraIconName } from "@varialkit/icons";
|
|
4
4
|
import { SegmentControl } from "./src/SegmentControl";
|
|
5
|
-
import type { SegmentControlSize } from "./src/SegmentControl.types";
|
|
5
|
+
import type { SegmentControlRadius, SegmentControlSize } from "./src/SegmentControl.types";
|
|
6
6
|
|
|
7
7
|
type PlaygroundProps = {
|
|
8
8
|
size: SegmentControlSize;
|
|
9
|
+
radius: SegmentControlRadius;
|
|
9
10
|
fullWidth: boolean;
|
|
10
11
|
withIcons: boolean;
|
|
11
12
|
movingBackground: boolean;
|
|
@@ -15,6 +16,7 @@ type PlaygroundProps = {
|
|
|
15
16
|
|
|
16
17
|
const SegmentControlPlayground = ({
|
|
17
18
|
size,
|
|
19
|
+
radius,
|
|
18
20
|
fullWidth,
|
|
19
21
|
withIcons,
|
|
20
22
|
movingBackground,
|
|
@@ -42,6 +44,7 @@ const SegmentControlPlayground = ({
|
|
|
42
44
|
value={value}
|
|
43
45
|
onChange={setValue}
|
|
44
46
|
size={size}
|
|
47
|
+
radius={radius}
|
|
45
48
|
fullWidth={fullWidth}
|
|
46
49
|
movingBackground={movingBackground}
|
|
47
50
|
>
|
|
@@ -62,7 +65,7 @@ const SegmentControlPlayground = ({
|
|
|
62
65
|
export const stories = {
|
|
63
66
|
playground: {
|
|
64
67
|
title: "Playground",
|
|
65
|
-
description: "Explore size, width, and disabled segment states.",
|
|
68
|
+
description: "Explore size, radius, width, and disabled segment states.",
|
|
66
69
|
render: (props: PlaygroundProps) => <SegmentControlPlayground {...props} />,
|
|
67
70
|
controls: [
|
|
68
71
|
{
|
|
@@ -70,6 +73,11 @@ export const stories = {
|
|
|
70
73
|
type: "select",
|
|
71
74
|
options: ["small", "medium", "large"],
|
|
72
75
|
},
|
|
76
|
+
{
|
|
77
|
+
name: "radius",
|
|
78
|
+
type: "select",
|
|
79
|
+
options: ["sm", "md", "lg", "full"],
|
|
80
|
+
},
|
|
73
81
|
{
|
|
74
82
|
name: "fullWidth",
|
|
75
83
|
type: "boolean",
|
|
@@ -100,6 +108,7 @@ export const stories = {
|
|
|
100
108
|
],
|
|
101
109
|
initialProps: {
|
|
102
110
|
size: "medium",
|
|
111
|
+
radius: "full",
|
|
103
112
|
fullWidth: false,
|
|
104
113
|
withIcons: false,
|
|
105
114
|
movingBackground: false,
|
|
@@ -130,7 +139,7 @@ export const stories = {
|
|
|
130
139
|
</SegmentControl>
|
|
131
140
|
</div>
|
|
132
141
|
),
|
|
133
|
-
code: `import { SegmentControl } from "@
|
|
142
|
+
code: `import { SegmentControl } from "@varialkit/segmentcontrol";
|
|
134
143
|
|
|
135
144
|
export function Example() {
|
|
136
145
|
return (
|
|
@@ -166,7 +175,7 @@ export function Example() {
|
|
|
166
175
|
<SegmentControl.Segment value="settings" ariaLabel="Settings" icon="arrow_swap_16" />
|
|
167
176
|
</SegmentControl>
|
|
168
177
|
),
|
|
169
|
-
code: `import { SegmentControl } from "@
|
|
178
|
+
code: `import { SegmentControl } from "@varialkit/segmentcontrol";
|
|
170
179
|
|
|
171
180
|
export function Example() {
|
|
172
181
|
return (
|
|
@@ -196,7 +205,7 @@ export function Example() {
|
|
|
196
205
|
</SegmentControl.Segment>
|
|
197
206
|
</SegmentControl>
|
|
198
207
|
),
|
|
199
|
-
code: `import { SegmentControl } from "@
|
|
208
|
+
code: `import { SegmentControl } from "@varialkit/segmentcontrol";
|
|
200
209
|
|
|
201
210
|
export function Example() {
|
|
202
211
|
return (
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@varialkit/segmentcontrol",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"./examples": "./examples.tsx"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@varialkit/icons": "0.1.
|
|
12
|
+
"@varialkit/icons": "0.1.3"
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"src",
|
package/src/SegmentControl.scss
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
--segment-control-surface-color-rgb: var(--color-surface-100-rgb);
|
|
5
5
|
--surface-border-color: var(--color-divider-secondary);
|
|
6
6
|
--surface-border-color-rgb: var(--color-divider-secondary-rgb);
|
|
7
|
+
--segment-control-selected-ring-rgb: var(--color-divider-primary-rgb);
|
|
7
8
|
--surface-opacity: 1;
|
|
8
9
|
--surface-blur: 0px;
|
|
9
10
|
--surface-shadow: var(--elevation-1);
|
|
@@ -14,6 +15,7 @@
|
|
|
14
15
|
--segment-control-bg-active: var(--color-surface-0);
|
|
15
16
|
--segment-control-bg-hover: var(--color-surface-200);
|
|
16
17
|
--segment-control-bg-indicator: var(--segment-control-bg-active);
|
|
18
|
+
--segment-control-selected-ring: rgba(var(--segment-control-selected-ring-rgb), 0.5);
|
|
17
19
|
--segment-control-shadow: var(--elevation-1);
|
|
18
20
|
--segment-padding-y: var(--space-2);
|
|
19
21
|
--segment-padding-x: var(--space-4);
|
|
@@ -22,12 +24,14 @@
|
|
|
22
24
|
--segment-icon-size: 16px;
|
|
23
25
|
--segment-gap: var(--space-2);
|
|
24
26
|
--segment-height: var(--space-9);
|
|
27
|
+
--segment-cell-radius: var(--radius-pill);
|
|
28
|
+
--segment-container-radius: var(--radius-pill);
|
|
25
29
|
|
|
26
30
|
position: relative;
|
|
27
31
|
display: inline-flex;
|
|
28
32
|
align-items: center;
|
|
29
33
|
gap: calc(var(--space-1) * var(--spacing-multiplier));
|
|
30
|
-
border-radius: var(--radius-
|
|
34
|
+
border-radius: calc(var(--segment-container-radius) * var(--radius-multiplier));
|
|
31
35
|
background-color: rgba(var(--segment-control-surface-color-rgb), var(--surface-opacity));
|
|
32
36
|
padding: calc(var(--space-1) * var(--spacing-multiplier));
|
|
33
37
|
box-shadow: transparent;
|
|
@@ -50,18 +54,37 @@
|
|
|
50
54
|
var(--segment-indicator-top, 0px)
|
|
51
55
|
);
|
|
52
56
|
background-color: var(--segment-control-bg-indicator);
|
|
53
|
-
border-radius: var(--radius-
|
|
54
|
-
|
|
57
|
+
border-radius: calc(var(--segment-cell-radius) * var(--radius-multiplier));
|
|
58
|
+
border: 1px solid var(--segment-control-selected-ring);
|
|
55
59
|
opacity: var(--segment-indicator-opacity, 0);
|
|
56
60
|
transition: transform 0.2s ease, width 0.2s ease, height 0.2s ease, opacity 0.2s ease;
|
|
57
61
|
pointer-events: none;
|
|
58
62
|
z-index: 0;
|
|
59
63
|
}
|
|
60
64
|
|
|
65
|
+
.solara-segment-control--radius-sm {
|
|
66
|
+
--segment-cell-radius: var(--radius-sm);
|
|
67
|
+
--segment-container-radius: var(--radius-md);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.solara-segment-control--radius-md {
|
|
71
|
+
--segment-cell-radius: var(--radius-md);
|
|
72
|
+
--segment-container-radius: var(--radius-3);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.solara-segment-control--radius-lg {
|
|
76
|
+
--segment-cell-radius: var(--radius-3);
|
|
77
|
+
--segment-container-radius: var(--radius-lg);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.solara-segment-control--radius-full {
|
|
81
|
+
--segment-cell-radius: var(--radius-full);
|
|
82
|
+
--segment-container-radius: var(--radius-full);
|
|
83
|
+
}
|
|
84
|
+
|
|
61
85
|
.solara-segment-control--moving-bg {
|
|
62
86
|
.solara-segment-control__segment {
|
|
63
87
|
background-color: transparent;
|
|
64
|
-
box-shadow: none;
|
|
65
88
|
position: relative;
|
|
66
89
|
z-index: 1;
|
|
67
90
|
}
|
|
@@ -72,7 +95,7 @@
|
|
|
72
95
|
|
|
73
96
|
.solara-segment-control__segment[data-state="active"] {
|
|
74
97
|
background-color: transparent;
|
|
75
|
-
|
|
98
|
+
border-color: transparent;
|
|
76
99
|
}
|
|
77
100
|
}
|
|
78
101
|
|
|
@@ -113,8 +136,8 @@
|
|
|
113
136
|
line-height: var(--segment-line-height);
|
|
114
137
|
color: var(--segment-control-text);
|
|
115
138
|
background-color: transparent;
|
|
116
|
-
border:
|
|
117
|
-
border-radius: var(--radius-
|
|
139
|
+
border: 1px solid transparent;
|
|
140
|
+
border-radius: calc(var(--segment-cell-radius) * var(--radius-multiplier));
|
|
118
141
|
cursor: pointer;
|
|
119
142
|
transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
|
|
120
143
|
white-space: nowrap;
|
|
@@ -145,8 +168,7 @@
|
|
|
145
168
|
.solara-segment-control__segment[data-state="active"] {
|
|
146
169
|
color: var(--segment-control-text-active);
|
|
147
170
|
background-color: var(--segment-control-bg-active);
|
|
148
|
-
|
|
149
|
-
font-weight: 600;
|
|
171
|
+
border-color: var(--segment-control-selected-ring);
|
|
150
172
|
}
|
|
151
173
|
|
|
152
174
|
.solara-segment-control__segment:disabled,
|
package/src/SegmentControl.tsx
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import React, { Children, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
-
import { Icon } from "@
|
|
3
|
-
import type { IconProps } from "@
|
|
4
|
-
import type {
|
|
2
|
+
import { Icon } from "@varialkit/icons";
|
|
3
|
+
import type { IconProps } from "@varialkit/icons";
|
|
4
|
+
import type {
|
|
5
|
+
SegmentControlProps,
|
|
6
|
+
SegmentControlRadius,
|
|
7
|
+
SegmentControlSize,
|
|
8
|
+
SegmentProps,
|
|
9
|
+
} from "./SegmentControl.types";
|
|
5
10
|
import "./SegmentControl.scss";
|
|
6
11
|
|
|
7
12
|
const sizeAliasMap: Record<SegmentControlSize, "small" | "medium" | "large"> = {
|
|
@@ -13,6 +18,13 @@ const sizeAliasMap: Record<SegmentControlSize, "small" | "medium" | "large"> = {
|
|
|
13
18
|
large: "large",
|
|
14
19
|
};
|
|
15
20
|
|
|
21
|
+
const radiusAliasMap: Record<SegmentControlRadius, "sm" | "md" | "lg" | "full"> = {
|
|
22
|
+
sm: "sm",
|
|
23
|
+
md: "md",
|
|
24
|
+
lg: "lg",
|
|
25
|
+
full: "full",
|
|
26
|
+
};
|
|
27
|
+
|
|
16
28
|
const classNames = (...classes: Array<string | undefined | false | null>) =>
|
|
17
29
|
classes.filter(Boolean).join(" ");
|
|
18
30
|
|
|
@@ -60,6 +72,7 @@ export const SegmentControl: SegmentControlComponent = ({
|
|
|
60
72
|
onChange,
|
|
61
73
|
fullWidth = false,
|
|
62
74
|
size = "medium",
|
|
75
|
+
radius = "full",
|
|
63
76
|
movingBackground = false,
|
|
64
77
|
surfaceStyle,
|
|
65
78
|
children,
|
|
@@ -68,6 +81,7 @@ export const SegmentControl: SegmentControlComponent = ({
|
|
|
68
81
|
...props
|
|
69
82
|
}: SegmentControlProps) => {
|
|
70
83
|
const resolvedSize = sizeAliasMap[size];
|
|
84
|
+
const resolvedRadius = radiusAliasMap[radius];
|
|
71
85
|
// Container ref is used to compute relative offsets for the moving indicator.
|
|
72
86
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
73
87
|
// Each segment stores its DOM node so we can measure width/position on demand.
|
|
@@ -170,7 +184,7 @@ export const SegmentControl: SegmentControlComponent = ({
|
|
|
170
184
|
|
|
171
185
|
// Surface styling is applied via data attributes so theme defaults remain centralized.
|
|
172
186
|
const surfaceAttributes: Record<string, string | undefined> = {};
|
|
173
|
-
const surfaceStyleVars: React.CSSProperties = {};
|
|
187
|
+
const surfaceStyleVars: React.CSSProperties & Record<string, string> = {};
|
|
174
188
|
|
|
175
189
|
if (surfaceStyle) {
|
|
176
190
|
if (typeof surfaceStyle === "string") {
|
|
@@ -198,6 +212,7 @@ export const SegmentControl: SegmentControlComponent = ({
|
|
|
198
212
|
className={classNames(
|
|
199
213
|
"solara-segment-control",
|
|
200
214
|
`solara-segment-control--size-${resolvedSize}`,
|
|
215
|
+
`solara-segment-control--radius-${resolvedRadius}`,
|
|
201
216
|
fullWidth ? "solara-segment-control--full-width" : null,
|
|
202
217
|
movingBackground ? "solara-segment-control--moving-bg" : null,
|
|
203
218
|
className
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import type { IconProps } from "@
|
|
2
|
+
import type { IconProps } from "@varialkit/icons";
|
|
3
3
|
|
|
4
4
|
export type SegmentControlSize = "small" | "medium" | "large" | "sm" | "md" | "lg";
|
|
5
5
|
|
|
6
|
+
export type SegmentControlRadius = "sm" | "md" | "lg" | "full";
|
|
7
|
+
|
|
6
8
|
export type SegmentControlSurfaceStyle =
|
|
7
9
|
| "solid"
|
|
8
10
|
| "translucent"
|
|
@@ -32,6 +34,10 @@ export interface SegmentControlProps
|
|
|
32
34
|
* Size of the segment control.
|
|
33
35
|
*/
|
|
34
36
|
size?: SegmentControlSize;
|
|
37
|
+
/**
|
|
38
|
+
* Controls the rounding of segment cells, with the container rendered slightly rounder when possible.
|
|
39
|
+
*/
|
|
40
|
+
radius?: SegmentControlRadius;
|
|
35
41
|
/**
|
|
36
42
|
* Controls surface material treatment without changing layout tokens.
|
|
37
43
|
*/
|