@domicile-desktop/component-library 0.0.0-alpha-7a29c8f7f7ea → 0.0.0-alpha-63728a988cfd

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/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "dependencies": {
3
3
  "@base-ui/react": "^1.8.0",
4
4
  "@cprussin/option-result": "^2.0.1",
5
- "@domicile-desktop/sdk": "0.0.0-alpha-7a29c8f7f7ea",
6
- "@domicile-desktop/system-apps": "0.0.0-alpha-7a29c8f7f7ea",
5
+ "@domicile-desktop/sdk": "0.0.0-alpha-63728a988cfd",
6
+ "@domicile-desktop/system-apps": "0.0.0-alpha-63728a988cfd",
7
7
  "@pandacss/dev": "^1.12.1",
8
8
  "@phosphor-icons/react": "^2.1.10"
9
9
  },
@@ -36,13 +36,24 @@
36
36
  "./Accordion": "./src/Accordion/Accordion.tsx",
37
37
  "./AnimatedBellIcon": "./src/AnimatedBellIcon/AnimatedBellIcon.tsx",
38
38
  "./AnimatedBluetoothIcon": "./src/AnimatedBluetoothIcon/AnimatedBluetoothIcon.tsx",
39
+ "./AnimatedCaretIcon": "./src/AnimatedCaretIcon/AnimatedCaretIcon.tsx",
39
40
  "./AnimatedChatIcon": "./src/AnimatedChatIcon/AnimatedChatIcon.tsx",
40
41
  "./AnimatedCheckIcon": "./src/AnimatedCheckIcon/AnimatedCheckIcon.tsx",
42
+ "./AnimatedCloseIcon": "./src/AnimatedCloseIcon/AnimatedCloseIcon.tsx",
43
+ "./AnimatedDownloadIcon": "./src/AnimatedDownloadIcon/AnimatedDownloadIcon.tsx",
41
44
  "./AnimatedEyeIcon": "./src/AnimatedEyeIcon/AnimatedEyeIcon.tsx",
45
+ "./AnimatedFloatIcon": "./src/AnimatedFloatIcon/AnimatedFloatIcon.tsx",
42
46
  "./AnimatedGearIcon": "./src/AnimatedGearIcon/AnimatedGearIcon.tsx",
43
47
  "./AnimatedKeyboardIcon": "./src/AnimatedKeyboardIcon/AnimatedKeyboardIcon.tsx",
48
+ "./AnimatedLayoutIcon": "./src/AnimatedLayoutIcon/AnimatedLayoutIcon.tsx",
44
49
  "./AnimatedLightningIcon": "./src/AnimatedLightningIcon/AnimatedLightningIcon.tsx",
50
+ "./AnimatedLockIcon": "./src/AnimatedLockIcon/AnimatedLockIcon.tsx",
51
+ "./AnimatedMaximizeIcon": "./src/AnimatedMaximizeIcon/AnimatedMaximizeIcon.tsx",
45
52
  "./AnimatedMicrophoneIcon": "./src/AnimatedMicrophoneIcon/AnimatedMicrophoneIcon.tsx",
53
+ "./AnimatedMinusIcon": "./src/AnimatedMinusIcon/AnimatedMinusIcon.tsx",
54
+ "./AnimatedPlusIcon": "./src/AnimatedPlusIcon/AnimatedPlusIcon.tsx",
55
+ "./AnimatedReloadIcon": "./src/AnimatedReloadIcon/AnimatedReloadIcon.tsx",
56
+ "./AnimatedSlidersIcon": "./src/AnimatedSlidersIcon/AnimatedSlidersIcon.tsx",
46
57
  "./AnimatedSpeakerIcon": "./src/AnimatedSpeakerIcon/AnimatedSpeakerIcon.tsx",
47
58
  "./AnimatedSquaresIcon": "./src/AnimatedSquaresIcon/AnimatedSquaresIcon.tsx",
48
59
  "./AnimatedThemeIcon": "./src/AnimatedThemeIcon/AnimatedThemeIcon.tsx",
@@ -146,5 +157,5 @@
146
157
  "test:unit": "bun test"
147
158
  },
148
159
  "type": "module",
149
- "version": "0.0.0-alpha-7a29c8f7f7ea"
160
+ "version": "0.0.0-alpha-63728a988cfd"
150
161
  }
@@ -0,0 +1,74 @@
1
+ import type { CSSProperties } from "react";
2
+
3
+ import { css } from "../../styled-system/css";
4
+ import { IconFrame } from "../_icon/IconFrame";
5
+ import { IconPart } from "../_icon/IconPart";
6
+ import { CARET_REGULAR } from "../_icon/redrawn-parts";
7
+
8
+ /** Which way the caret points. */
9
+ export type CaretPointing = keyof typeof CARET_REGULAR;
10
+
11
+ /** The way each pointing darts. Physical, since the icon does not mirror. */
12
+ const DARTS: Record<CaretPointing, readonly [number, number]> = {
13
+ down: [0, 1],
14
+ left: [-1, 0],
15
+ right: [1, 0],
16
+ up: [0, -1],
17
+ };
18
+
19
+ /** Each arm turns toward the other, sharpening the point. */
20
+ const SWINGS = [
21
+ [1, 0],
22
+ [-1, 0],
23
+ ] as const;
24
+
25
+ type Props = {
26
+ /** Names the icon; without one it is decorative. */
27
+ label?: string | undefined;
28
+ pointing: CaretPointing;
29
+ size: number;
30
+ };
31
+
32
+ /**
33
+ * Phosphor's regular carets. While the control it is in is pointed at, its
34
+ * point sharpens and darts the way it points.
35
+ */
36
+ export const AnimatedCaretIcon = ({ label, pointing, size }: Props) => {
37
+ const { arms, tip } = CARET_REGULAR[pointing];
38
+ const [x, y] = DARTS[pointing];
39
+ return (
40
+ <IconFrame label={label} size={size}>
41
+ <g
42
+ className={dartStyles}
43
+ style={{ "--part-x": x, "--part-y": y } as CSSProperties}
44
+ >
45
+ {arms.map((d, index) => (
46
+ <IconPart
47
+ d={d}
48
+ direction={SWINGS[index]}
49
+ hoverStyles={sharpenStyles}
50
+ key={d}
51
+ name="arm"
52
+ order={index}
53
+ origin={tip}
54
+ />
55
+ ))}
56
+ </g>
57
+ </IconFrame>
58
+ );
59
+ };
60
+
61
+ const dartStyles = css({
62
+ _controlHover: {
63
+ animation: "iconPartSpread {durations.slower} {easings.in-out}",
64
+ },
65
+ "--spread": "10px",
66
+ "[data-reduced-motion] &": { animationName: "none !important" },
67
+ });
68
+
69
+ const sharpenStyles = css({
70
+ _controlHover: {
71
+ animation: "iconArmSwing {durations.slower} {easings.in-out}",
72
+ },
73
+ "--swing": "9deg",
74
+ });
@@ -0,0 +1,49 @@
1
+ import { css } from "../../styled-system/css";
2
+ import { IconFrame } from "../_icon/IconFrame";
3
+ import { IconPart } from "../_icon/IconPart";
4
+ import { X_BOLD, X_REGULAR } from "../_icon/redrawn-parts";
5
+
6
+ /** Which way each stroke swings as the X snips. */
7
+ const SWINGS = [
8
+ [-1, 0],
9
+ [1, 0],
10
+ ] as const;
11
+
12
+ const ARMS = { bold: X_BOLD.arms, regular: X_REGULAR.arms };
13
+
14
+ type Props = {
15
+ /** Names the icon; without one it is decorative. */
16
+ label?: string | undefined;
17
+ size: number;
18
+ weight?: keyof typeof ARMS | undefined;
19
+ };
20
+
21
+ /**
22
+ * Phosphor's `X`. Its two strokes snip, like scissors, while the control it
23
+ * is in is pointed at.
24
+ */
25
+ export const AnimatedCloseIcon = ({
26
+ label,
27
+ size,
28
+ weight = "regular",
29
+ }: Props) => (
30
+ <IconFrame label={label} size={size}>
31
+ {ARMS[weight].map((d, index) => (
32
+ <IconPart
33
+ d={d}
34
+ direction={SWINGS[index]}
35
+ hoverStyles={snipStyles}
36
+ key={d}
37
+ name="arm"
38
+ order={index}
39
+ />
40
+ ))}
41
+ </IconFrame>
42
+ );
43
+
44
+ const snipStyles = css({
45
+ _controlHover: {
46
+ animation: "iconArmSwing {durations.slower} {easings.in-out}",
47
+ },
48
+ "--swing": "14deg",
49
+ });
@@ -0,0 +1,50 @@
1
+ import { css } from "../../styled-system/css";
2
+ import { IconFrame } from "../_icon/IconFrame";
3
+ import { IconPart } from "../_icon/IconPart";
4
+ import { DOWNLOAD_REGULAR } from "../_icon/phosphor-parts";
5
+ import { useCue } from "../_icon/useCue";
6
+
7
+ /** The tray's floor, which it gives toward. */
8
+ const FLOOR = [128, 216] as const;
9
+
10
+ type Props = {
11
+ /** Drops the arrow again each time it changes, such as for a new download. */
12
+ cue?: unknown;
13
+ /** Names the icon; without one it is decorative. */
14
+ label?: string | undefined;
15
+ size: number;
16
+ };
17
+
18
+ /**
19
+ * Phosphor's regular `DownloadSimple`. Its arrow drops into the tray when it
20
+ * appears and on each cue, and the tray gives under it.
21
+ */
22
+ export const AnimatedDownloadIcon = ({ cue, label, size }: Props) => {
23
+ const cued = useCue(cue);
24
+ return (
25
+ <IconFrame label={label} size={size}>
26
+ <IconPart
27
+ cue={cued}
28
+ cueStyles={giveStyles}
29
+ d={DOWNLOAD_REGULAR.tray}
30
+ name="tray"
31
+ origin={FLOOR}
32
+ />
33
+ <IconPart
34
+ cue={cued}
35
+ cueStyles={dropStyles}
36
+ d={DOWNLOAD_REGULAR.arrow}
37
+ name="arrow"
38
+ />
39
+ </IconFrame>
40
+ );
41
+ };
42
+
43
+ // Not keyed on `data-cued`: the drop also plays when the icon appears.
44
+ const dropStyles = css({
45
+ animation: "iconDownloadDrop {durations.slowest} {easings.out}",
46
+ });
47
+
48
+ const giveStyles = css({
49
+ animation: "iconTrayGive {durations.slowest} {easings.out}",
50
+ });
@@ -0,0 +1,171 @@
1
+ import { useId } from "react";
2
+
3
+ import { css } from "../../styled-system/css";
4
+ import { DIAGONALS } from "../_icon/diagonals";
5
+ import { IconFrame } from "../_icon/IconFrame";
6
+ import { IconPart } from "../_icon/IconPart";
7
+ import { SQUARES_REGULAR } from "../_icon/phosphor-parts";
8
+ import { BROWSERS_REGULAR } from "../_icon/redrawn-parts";
9
+
10
+ /** The centers of the squares, which they shrink about. */
11
+ const SQUARE_CENTERS = [
12
+ [80, 80],
13
+ [176, 80],
14
+ [80, 176],
15
+ [176, 176],
16
+ ] as const;
17
+
18
+ /** The center of the window in front. */
19
+ const FRONT_CENTER = [112, 144] as const;
20
+
21
+ /** The way the window in front lifts, and the one behind the other way. */
22
+ const FRONT_LIFT = [-1, 1] as const;
23
+ const BACK_LIFT = [1, -1] as const;
24
+
25
+ type Props = {
26
+ /** Whether the window floats: the icon then offers to tile it. */
27
+ floating: boolean;
28
+ /** Names the icon; without one it is decorative. */
29
+ label?: string | undefined;
30
+ size: number;
31
+ };
32
+
33
+ /**
34
+ * Phosphor's regular `Browsers` while a window is tiled, to float it, and
35
+ * its `SquaresFour` while it floats, to tile it. Pointed at, the windows
36
+ * lift apart or the squares part. On a change the windows gather into the
37
+ * squares, or the window behind slides out from the one in front.
38
+ */
39
+ export const AnimatedFloatIcon = ({ floating, label, size }: Props) => {
40
+ const maskId = useId();
41
+ const windows = floating ? "hidden" : "shown";
42
+ const squares = floating ? "shown" : "hidden";
43
+ return (
44
+ <IconFrame label={label} size={size}>
45
+ <defs>
46
+ {/* Hides the window behind where the one in front covers it. */}
47
+ <mask
48
+ height="320"
49
+ id={maskId}
50
+ maskUnits="userSpaceOnUse"
51
+ width="320"
52
+ x="-32"
53
+ y="-32"
54
+ >
55
+ <rect fill="white" height="320" width="320" x="-32" y="-32" />
56
+ <g fill="black">
57
+ <IconPart
58
+ d={BROWSERS_REGULAR.frontOutline}
59
+ direction={FRONT_LIFT}
60
+ hoverStyles={floating ? undefined : frontLiftStyles}
61
+ name="front-outline"
62
+ />
63
+ </g>
64
+ </mask>
65
+ </defs>
66
+ <g mask={`url(#${maskId})`}>
67
+ <IconPart
68
+ d={BROWSERS_REGULAR.back}
69
+ direction={BACK_LIFT}
70
+ hoverStyles={floating ? undefined : backLiftStyles}
71
+ name="back"
72
+ state={windows}
73
+ stateStyles={backStyles}
74
+ />
75
+ </g>
76
+ <IconPart
77
+ d={BROWSERS_REGULAR.front}
78
+ direction={FRONT_LIFT}
79
+ hoverStyles={floating ? undefined : frontLiftStyles}
80
+ name="front"
81
+ origin={FRONT_CENTER}
82
+ state={windows}
83
+ stateStyles={frontStyles}
84
+ />
85
+ {SQUARES_REGULAR.squares.map((d, index) => (
86
+ <IconPart
87
+ d={d}
88
+ direction={DIAGONALS[index]}
89
+ hoverStyles={floating ? squareSpreadStyles : undefined}
90
+ key={d}
91
+ name="square"
92
+ order={index}
93
+ origin={SQUARE_CENTERS[index]}
94
+ state={squares}
95
+ stateStyles={squareStyles}
96
+ />
97
+ ))}
98
+ </IconFrame>
99
+ );
100
+ };
101
+
102
+ // The window behind tucks under the one in front before either goes, and
103
+ // slides back out once the one in front is back.
104
+ const backStyles = css({
105
+ "&[data-state=hidden]": {
106
+ opacity: 0,
107
+ transform: "translate(-32px, 32px)",
108
+ transition:
109
+ "opacity {durations.fastest} {easings.linear} {durations.normal}, transform {durations.normal} {easings.in}",
110
+ },
111
+ "&[data-state=shown]": {
112
+ opacity: 1,
113
+ transform: "none",
114
+ transition:
115
+ "opacity {durations.fastest} {easings.linear} {durations.slow}, transform {durations.slower} {easings.outBack} {durations.slow}",
116
+ },
117
+ });
118
+
119
+ const frontStyles = css({
120
+ "&[data-state=hidden]": {
121
+ opacity: 0,
122
+ transform: "scale(0.8)",
123
+ transition:
124
+ "opacity {durations.normal} {easings.in} {durations.fast}, transform {durations.normal} {easings.in} {durations.fast}",
125
+ },
126
+ "&[data-state=shown]": {
127
+ opacity: 1,
128
+ transform: "none",
129
+ transition:
130
+ "opacity {durations.normal} {easings.out} {durations.fast}, transform {durations.slow} {easings.out} {durations.fast}",
131
+ },
132
+ });
133
+
134
+ // The squares gather into the middle as they go, and come out of it.
135
+ const squareStyles = css({
136
+ "&[data-state=hidden]": {
137
+ opacity: 0,
138
+ transform:
139
+ "translate(calc(var(--part-x) * -30px), calc(var(--part-y) * -30px)) scale(0.6)",
140
+ transition:
141
+ "opacity {durations.fast} {easings.in}, transform {durations.fast} {easings.in}",
142
+ },
143
+ "&[data-state=shown]": {
144
+ opacity: 1,
145
+ transform: "none",
146
+ transition:
147
+ "opacity {durations.normal} {easings.out} calc({durations.fast} + var(--part-order) * {durations.fastest}), transform {durations.slower} {easings.outBack} calc({durations.fast} + var(--part-order) * {durations.fastest})",
148
+ },
149
+ });
150
+
151
+ const backLiftStyles = css({
152
+ _controlHover: {
153
+ animation: "iconPartSpread {durations.slowest} {easings.in-out}",
154
+ },
155
+ "--spread": "12px",
156
+ });
157
+
158
+ const frontLiftStyles = css({
159
+ _controlHover: {
160
+ animation: "iconPartSpread {durations.slowest} {easings.in-out}",
161
+ },
162
+ "--spread": "8px",
163
+ });
164
+
165
+ const squareSpreadStyles = css({
166
+ _controlHover: {
167
+ animation:
168
+ "iconPartSpread {durations.slowest} {easings.in-out} calc(var(--part-order) * {durations.fastest} / 2)",
169
+ },
170
+ "--spread": "9px",
171
+ });
@@ -0,0 +1,142 @@
1
+ import { css } from "../../styled-system/css";
2
+ import { IconFrame } from "../_icon/IconFrame";
3
+ import { IconPart } from "../_icon/IconPart";
4
+ import { ROWS_REGULAR, TABS_REGULAR } from "../_icon/phosphor-parts";
5
+ import { SQUARE_SPLIT_REGULAR } from "../_icon/redrawn-parts";
6
+
7
+ /** How a group lays out its windows. */
8
+ export type GroupLayout = "column" | "row" | "stack" | "tabs";
9
+
10
+ /** Where the tabs stand, which they rise from. */
11
+ const TABS_BASE = [128, 176] as const;
12
+
13
+ type Props = {
14
+ /** Names the icon; without one it is decorative. */
15
+ label?: string | undefined;
16
+ layout: GroupLayout;
17
+ size: number;
18
+ };
19
+
20
+ const shownIf = (shown: boolean) => (shown ? "shown" : "hidden");
21
+
22
+ /**
23
+ * A group's layout, in Phosphor's regular icons: `SquareSplitHorizontal`
24
+ * for a row, `SquareSplitVertical` for a column, `Rows` for a stack and
25
+ * `Tabs` for tabs. When the layout changes the new one builds in: the divider draws
26
+ * across, the rows drop in, the tabs rise.
27
+ */
28
+ export const AnimatedLayoutIcon = ({ label, layout, size }: Props) => {
29
+ const split = layout === "row" || layout === "column";
30
+ return (
31
+ <IconFrame label={label} size={size}>
32
+ <IconPart
33
+ d={SQUARE_SPLIT_REGULAR.frame}
34
+ name="frame"
35
+ state={shownIf(split)}
36
+ stateStyles={fadeStyles}
37
+ />
38
+ <IconPart
39
+ d={SQUARE_SPLIT_REGULAR.horizontal}
40
+ name="divider"
41
+ state={shownIf(layout === "row")}
42
+ stateStyles={columnDividerStyles}
43
+ />
44
+ <IconPart
45
+ d={SQUARE_SPLIT_REGULAR.vertical}
46
+ name="divider"
47
+ state={shownIf(layout === "column")}
48
+ stateStyles={rowDividerStyles}
49
+ />
50
+ {ROWS_REGULAR.rows.map((d, index) => (
51
+ <IconPart
52
+ d={d}
53
+ key={d}
54
+ name="row"
55
+ order={index}
56
+ state={shownIf(layout === "stack")}
57
+ stateStyles={rowStyles}
58
+ />
59
+ ))}
60
+ <IconPart
61
+ d={TABS_REGULAR.tabs}
62
+ name="tabs"
63
+ origin={TABS_BASE}
64
+ state={shownIf(layout === "tabs")}
65
+ stateStyles={tabsStyles}
66
+ />
67
+ </IconFrame>
68
+ );
69
+ };
70
+
71
+ const fadeStyles = css({
72
+ "&[data-state=hidden]": {
73
+ opacity: 0,
74
+ transition: "opacity {durations.fast} {easings.in}",
75
+ },
76
+ "&[data-state=shown]": {
77
+ opacity: 1,
78
+ transition: "opacity {durations.normal} {easings.out}",
79
+ },
80
+ });
81
+
82
+ // Draws down from the middle, across the frame.
83
+ const columnDividerStyles = css({
84
+ "&[data-state=hidden]": {
85
+ opacity: 0,
86
+ transform: "scaleY(0)",
87
+ transition:
88
+ "opacity {durations.fast} {easings.in}, transform {durations.fast} {easings.in}",
89
+ },
90
+ "&[data-state=shown]": {
91
+ opacity: 1,
92
+ transform: "none",
93
+ transition:
94
+ "opacity {durations.fast} {easings.out} {durations.faster}, transform {durations.slow} {easings.out} {durations.faster}",
95
+ },
96
+ });
97
+
98
+ const rowDividerStyles = css({
99
+ "&[data-state=hidden]": {
100
+ opacity: 0,
101
+ transform: "scaleX(0)",
102
+ transition:
103
+ "opacity {durations.fast} {easings.in}, transform {durations.fast} {easings.in}",
104
+ },
105
+ "&[data-state=shown]": {
106
+ opacity: 1,
107
+ transform: "none",
108
+ transition:
109
+ "opacity {durations.fast} {easings.out} {durations.faster}, transform {durations.slow} {easings.out} {durations.faster}",
110
+ },
111
+ });
112
+
113
+ // Each row drops in after the one above it.
114
+ const rowStyles = css({
115
+ "&[data-state=hidden]": {
116
+ opacity: 0,
117
+ transform: "translateY(-28px)",
118
+ transition:
119
+ "opacity {durations.fast} {easings.in}, transform {durations.fast} {easings.in}",
120
+ },
121
+ "&[data-state=shown]": {
122
+ opacity: 1,
123
+ transform: "none",
124
+ transition:
125
+ "opacity {durations.normal} {easings.out} calc({durations.faster} + var(--part-order) * {durations.faster}), transform {durations.slower} {easings.outBack} calc({durations.faster} + var(--part-order) * {durations.faster})",
126
+ },
127
+ });
128
+
129
+ const tabsStyles = css({
130
+ "&[data-state=hidden]": {
131
+ opacity: 0,
132
+ transform: "scaleY(0.4)",
133
+ transition:
134
+ "opacity {durations.fast} {easings.in}, transform {durations.fast} {easings.in}",
135
+ },
136
+ "&[data-state=shown]": {
137
+ opacity: 1,
138
+ transform: "none",
139
+ transition:
140
+ "opacity {durations.normal} {easings.out} {durations.faster}, transform {durations.slow} {easings.outBack} {durations.faster}",
141
+ },
142
+ });
@@ -0,0 +1,51 @@
1
+ import { css } from "../../styled-system/css";
2
+ import { IconFrame } from "../_icon/IconFrame";
3
+ import { IconPart } from "../_icon/IconPart";
4
+ import { LOCK_REGULAR } from "../_icon/redrawn-parts";
5
+
6
+ /** The keyhole's middle, which it swells about. */
7
+ const KEYHOLE = [128, 152] as const;
8
+
9
+ type Props = {
10
+ /** Names the icon; without one it is decorative. */
11
+ label?: string | undefined;
12
+ size: number;
13
+ };
14
+
15
+ /**
16
+ * Phosphor's regular `Lock`. Its shackle snaps shut when it appears, such as
17
+ * when a page turns out to be secure, and lifts a little while the control
18
+ * it is in is pointed at.
19
+ */
20
+ export const AnimatedLockIcon = ({ label, size }: Props) => (
21
+ <IconFrame label={label} size={size}>
22
+ <IconPart d={LOCK_REGULAR.body} name="body" />
23
+ <IconPart
24
+ d={LOCK_REGULAR.shackle}
25
+ hoverStyles={liftStyles}
26
+ name="shackle"
27
+ stateStyles={shutStyles}
28
+ />
29
+ <IconPart
30
+ d={LOCK_REGULAR.keyhole}
31
+ name="keyhole"
32
+ origin={KEYHOLE}
33
+ stateStyles={pulseStyles}
34
+ />
35
+ </IconFrame>
36
+ );
37
+
38
+ const shutStyles = css({
39
+ animation: "iconShackleShut {durations.slower} {easings.out}",
40
+ });
41
+
42
+ const pulseStyles = css({
43
+ animation:
44
+ "iconKeyholePulse {durations.slow} {easings.in-out} {durations.normal} both",
45
+ });
46
+
47
+ const liftStyles = css({
48
+ _controlHover: {
49
+ animation: "iconShackleLift {durations.slowest} {easings.in-out}",
50
+ },
51
+ });
@@ -0,0 +1,97 @@
1
+ import { css } from "../../styled-system/css";
2
+ import { DIAGONALS } from "../_icon/diagonals";
3
+ import { IconFrame } from "../_icon/IconFrame";
4
+ import { IconPart } from "../_icon/IconPart";
5
+ import {
6
+ CORNERS_IN_REGULAR,
7
+ CORNERS_OUT_REGULAR,
8
+ } from "../_icon/phosphor-parts";
9
+
10
+ type Props = {
11
+ /** Names the icon; without one it is decorative. */
12
+ label?: string | undefined;
13
+ /** Whether the window is maximized: the icon then offers to restore it. */
14
+ maximized: boolean;
15
+ size: number;
16
+ };
17
+
18
+ /**
19
+ * Phosphor's regular `CornersOut` while a window is not maximized, and its
20
+ * `CornersIn` while it is. Pointed at, the corners push out or pull in. On a
21
+ * change they travel that way into the other icon: out to maximize, in to
22
+ * restore.
23
+ */
24
+ export const AnimatedMaximizeIcon = ({ label, maximized, size }: Props) => (
25
+ <IconFrame label={label} size={size}>
26
+ {CORNERS_OUT_REGULAR.corners.map((d, index) => (
27
+ <IconPart
28
+ d={d}
29
+ direction={DIAGONALS[index]}
30
+ hoverStyles={maximized ? undefined : pushStyles}
31
+ key={d}
32
+ name="corner-out"
33
+ state={maximized ? "hidden" : "shown"}
34
+ stateStyles={outStyles}
35
+ />
36
+ ))}
37
+ {CORNERS_IN_REGULAR.corners.map((d, index) => (
38
+ <IconPart
39
+ d={d}
40
+ direction={DIAGONALS[index]}
41
+ hoverStyles={maximized ? pullStyles : undefined}
42
+ key={d}
43
+ name="corner-in"
44
+ state={maximized ? "shown" : "hidden"}
45
+ stateStyles={inStyles}
46
+ />
47
+ ))}
48
+ </IconFrame>
49
+ );
50
+
51
+ // Pointing out, they sit further out while hidden.
52
+ const outStyles = css({
53
+ "&[data-state=hidden]": {
54
+ opacity: 0,
55
+ transform:
56
+ "translate(calc(var(--part-x) * 28px), calc(var(--part-y) * 28px))",
57
+ transition:
58
+ "opacity {durations.normal} {easings.in}, transform {durations.normal} {easings.in}",
59
+ },
60
+ "&[data-state=shown]": {
61
+ opacity: 1,
62
+ transform: "none",
63
+ transition:
64
+ "opacity {durations.normal} {easings.out} {durations.faster}, transform {durations.slower} {easings.outBack} {durations.faster}",
65
+ },
66
+ });
67
+
68
+ // Pointing in, they sit further in while hidden.
69
+ const inStyles = css({
70
+ "&[data-state=hidden]": {
71
+ opacity: 0,
72
+ transform:
73
+ "translate(calc(var(--part-x) * -28px), calc(var(--part-y) * -28px))",
74
+ transition:
75
+ "opacity {durations.normal} {easings.in}, transform {durations.normal} {easings.in}",
76
+ },
77
+ "&[data-state=shown]": {
78
+ opacity: 1,
79
+ transform: "none",
80
+ transition:
81
+ "opacity {durations.normal} {easings.out} {durations.faster}, transform {durations.slower} {easings.outBack} {durations.faster}",
82
+ },
83
+ });
84
+
85
+ const pushStyles = css({
86
+ _controlHover: {
87
+ animation: "iconPartSpread {durations.slowest} {easings.in-out}",
88
+ },
89
+ "--spread": "14px",
90
+ });
91
+
92
+ const pullStyles = css({
93
+ _controlHover: {
94
+ animation: "iconPartSpread {durations.slowest} {easings.in-out}",
95
+ },
96
+ "--spread": "-10px",
97
+ });
@@ -0,0 +1,34 @@
1
+ import { css } from "../../styled-system/css";
2
+ import { IconFrame } from "../_icon/IconFrame";
3
+ import { IconPart } from "../_icon/IconPart";
4
+ import { MINUS_BOLD } from "../_icon/redrawn-parts";
5
+
6
+ /** The bar draws in across, the opposite of the plus's arms reaching. */
7
+ const DRAWS_IN = [-1, 0] as const;
8
+
9
+ type Props = {
10
+ /** Names the icon; without one it is decorative. */
11
+ label?: string | undefined;
12
+ size: number;
13
+ };
14
+
15
+ /**
16
+ * Phosphor's bold `Minus`. Its bar draws in while the control it is in is
17
+ * pointed at.
18
+ */
19
+ export const AnimatedMinusIcon = ({ label, size }: Props) => (
20
+ <IconFrame label={label} size={size}>
21
+ <IconPart
22
+ d={MINUS_BOLD.bar}
23
+ direction={DRAWS_IN}
24
+ hoverStyles={drawInStyles}
25
+ name="bar"
26
+ />
27
+ </IconFrame>
28
+ );
29
+
30
+ const drawInStyles = css({
31
+ _controlHover: {
32
+ animation: "iconArmReach {durations.slower} {easings.in-out}",
33
+ },
34
+ });
@@ -0,0 +1,49 @@
1
+ import { css } from "../../styled-system/css";
2
+ import { IconFrame } from "../_icon/IconFrame";
3
+ import { IconPart } from "../_icon/IconPart";
4
+ import { PLUS_BOLD, PLUS_REGULAR } from "../_icon/redrawn-parts";
5
+
6
+ /** The way each arm reaches: across, then down. */
7
+ const REACHES = [
8
+ [1, 0],
9
+ [0, 1],
10
+ ] as const;
11
+
12
+ const ARMS = { bold: PLUS_BOLD.arms, regular: PLUS_REGULAR.arms };
13
+
14
+ type Props = {
15
+ /** Names the icon; without one it is decorative. */
16
+ label?: string | undefined;
17
+ size: number;
18
+ weight?: keyof typeof ARMS | undefined;
19
+ };
20
+
21
+ /**
22
+ * Phosphor's `Plus`. Its arms reach out, one after the other, while
23
+ * the control it is in is pointed at.
24
+ */
25
+ export const AnimatedPlusIcon = ({
26
+ label,
27
+ size,
28
+ weight = "regular",
29
+ }: Props) => (
30
+ <IconFrame label={label} size={size}>
31
+ {ARMS[weight].map((d, index) => (
32
+ <IconPart
33
+ d={d}
34
+ direction={REACHES[index]}
35
+ hoverStyles={reachStyles}
36
+ key={d}
37
+ name="arm"
38
+ order={index}
39
+ />
40
+ ))}
41
+ </IconFrame>
42
+ );
43
+
44
+ const reachStyles = css({
45
+ _controlHover: {
46
+ animation:
47
+ "iconArmReach {durations.slower} {easings.in-out} calc(var(--part-order) * {durations.faster}) both",
48
+ },
49
+ });
@@ -0,0 +1,93 @@
1
+ import { css } from "../../styled-system/css";
2
+ import { IconFrame } from "../_icon/IconFrame";
3
+ import { IconPart } from "../_icon/IconPart";
4
+ import { ARROW_CLOCKWISE_REGULAR } from "../_icon/phosphor-parts";
5
+ import { X_REGULAR } from "../_icon/redrawn-parts";
6
+
7
+ /** Which way each of the X's strokes swings. */
8
+ const SWINGS = [
9
+ [-1, 0],
10
+ [1, 0],
11
+ ] as const;
12
+
13
+ type Props = {
14
+ /** Names the icon; without one it is decorative. */
15
+ label?: string | undefined;
16
+ /** Whether the page is loading: the icon then offers to stop it. */
17
+ loading: boolean;
18
+ size: number;
19
+ };
20
+
21
+ /**
22
+ * Phosphor's regular `ArrowClockwise`, to reload, and its `X` while the page
23
+ * loads, to stop. Pointed at, the arrow winds forward or the X snips. When
24
+ * loading starts the arrow spins away into the X, and it spins back once
25
+ * the page has loaded.
26
+ */
27
+ export const AnimatedReloadIcon = ({ label, loading, size }: Props) => (
28
+ <IconFrame label={label} size={size}>
29
+ <IconPart
30
+ d={ARROW_CLOCKWISE_REGULAR.arrow}
31
+ hoverStyles={loading ? undefined : windStyles}
32
+ name="arrow"
33
+ state={loading ? "hidden" : "shown"}
34
+ stateStyles={arrowStyles}
35
+ />
36
+ {X_REGULAR.arms.map((d, index) => (
37
+ <IconPart
38
+ d={d}
39
+ direction={SWINGS[index]}
40
+ hoverStyles={loading ? snipStyles : undefined}
41
+ key={d}
42
+ name="arm"
43
+ order={index}
44
+ state={loading ? "shown" : "hidden"}
45
+ stateStyles={armStyles}
46
+ />
47
+ ))}
48
+ </IconFrame>
49
+ );
50
+
51
+ const arrowStyles = css({
52
+ "&[data-state=hidden]": {
53
+ opacity: 0,
54
+ transform: "rotate(180deg) scale(0.6)",
55
+ transition:
56
+ "opacity {durations.normal} {easings.in}, transform {durations.slow} {easings.in}",
57
+ },
58
+ "&[data-state=shown]": {
59
+ opacity: 1,
60
+ transform: "none",
61
+ transition:
62
+ "opacity {durations.normal} {easings.out} {durations.faster}, transform {durations.slowest} {easings.outBack} {durations.faster}",
63
+ },
64
+ });
65
+
66
+ // Each stroke turns in from its own side.
67
+ const armStyles = css({
68
+ "&[data-state=hidden]": {
69
+ opacity: 0,
70
+ transform: "rotate(calc(var(--part-x) * 45deg)) scale(0.5)",
71
+ transition:
72
+ "opacity {durations.fast} {easings.in}, transform {durations.fast} {easings.in}",
73
+ },
74
+ "&[data-state=shown]": {
75
+ opacity: 1,
76
+ transform: "none",
77
+ transition:
78
+ "opacity {durations.normal} {easings.out} {durations.fast}, transform {durations.slower} {easings.outBack} {durations.fast}",
79
+ },
80
+ });
81
+
82
+ const windStyles = css({
83
+ _controlHover: {
84
+ animation: "iconArrowWind {durations.slowest} {easings.in-out}",
85
+ },
86
+ });
87
+
88
+ const snipStyles = css({
89
+ _controlHover: {
90
+ animation: "iconArmSwing {durations.slower} {easings.in-out}",
91
+ },
92
+ "--swing": "14deg",
93
+ });
@@ -0,0 +1,78 @@
1
+ import { useId } from "react";
2
+
3
+ import { css } from "../../styled-system/css";
4
+ import { IconFrame } from "../_icon/IconFrame";
5
+ import { IconPart } from "../_icon/IconPart";
6
+ import { SLIDERS_REGULAR } from "../_icon/redrawn-parts";
7
+
8
+ /** The way each knob slides: the top one along, the bottom one back. */
9
+ const SLIDES = [
10
+ [1, 0],
11
+ [-1, 0],
12
+ ] as const;
13
+
14
+ type Props = {
15
+ /** Names the icon; without one it is decorative. */
16
+ label?: string | undefined;
17
+ size: number;
18
+ };
19
+
20
+ /**
21
+ * Phosphor's regular `SlidersHorizontal`. Its knobs slide opposite ways and
22
+ * back while the control it is in is pointed at.
23
+ */
24
+ export const AnimatedSlidersIcon = ({ label, size }: Props) => {
25
+ const maskId = useId();
26
+ return (
27
+ <IconFrame label={label} size={size}>
28
+ <defs>
29
+ {/* Hide each track where its knob sits, and move with the knob. */}
30
+ {SLIDERS_REGULAR.knobDisks.map((d, index) => (
31
+ <mask
32
+ height="320"
33
+ id={`${maskId}-${index.toString()}`}
34
+ key={d}
35
+ maskUnits="userSpaceOnUse"
36
+ width="320"
37
+ x="-32"
38
+ y="-32"
39
+ >
40
+ <rect fill="white" height="320" width="320" x="-32" y="-32" />
41
+ <g fill="black">
42
+ <IconPart
43
+ d={d}
44
+ direction={SLIDES[index]}
45
+ hoverStyles={slideStyles}
46
+ name="knob-disk"
47
+ order={index}
48
+ />
49
+ </g>
50
+ </mask>
51
+ ))}
52
+ </defs>
53
+ {SLIDERS_REGULAR.tracks.map((d, index) => (
54
+ <g key={d} mask={`url(#${maskId}-${index.toString()})`}>
55
+ <IconPart d={d} name="track" />
56
+ </g>
57
+ ))}
58
+ {SLIDERS_REGULAR.knobs.map((d, index) => (
59
+ <IconPart
60
+ d={d}
61
+ direction={SLIDES[index]}
62
+ hoverStyles={slideStyles}
63
+ key={d}
64
+ name="knob"
65
+ order={index}
66
+ />
67
+ ))}
68
+ </IconFrame>
69
+ );
70
+ };
71
+
72
+ const slideStyles = css({
73
+ _controlHover: {
74
+ animation:
75
+ "iconPartSpread {durations.slowest} {easings.in-out} calc(var(--part-order) * {durations.fastest}) both",
76
+ },
77
+ "--spread": "24px",
78
+ });
@@ -1,4 +1,5 @@
1
1
  import { css } from "../../styled-system/css";
2
+ import { DIAGONALS } from "../_icon/diagonals";
2
3
  import { IconFrame } from "../_icon/IconFrame";
3
4
  import { IconPart } from "../_icon/IconPart";
4
5
  import { SQUARES_REGULAR } from "../_icon/phosphor-parts";
@@ -18,11 +19,12 @@ export const AnimatedSquaresIcon = ({ label, size }: Props) => (
18
19
  {SQUARES_REGULAR.squares.map((d, index) => (
19
20
  <IconPart
20
21
  d={d}
22
+ direction={DIAGONALS[index]}
21
23
  hoverStyles={squareSpreadStyles}
22
24
  key={d}
23
25
  name="square"
24
26
  order={index}
25
- stateStyles={SQUARE_STYLES[index]}
27
+ stateStyles={squarePressStyles}
26
28
  />
27
29
  ))}
28
30
  </IconFrame>
@@ -31,36 +33,16 @@ export const AnimatedSquaresIcon = ({ label, size }: Props) => (
31
33
  const squareSpreadStyles = css({
32
34
  _controlHover: {
33
35
  animation:
34
- "iconSquareSpread {durations.slowest} {easings.in-out} calc(var(--part-order) * {durations.fastest} / 2)",
36
+ "iconPartSpread {durations.slowest} {easings.in-out} calc(var(--part-order) * {durations.fastest} / 2)",
35
37
  },
38
+ "--spread": "9px",
36
39
  });
37
40
 
38
- // Each square moves along its own diagonal, out while pointed at and in
39
- // while pressed: top start, top end, bottom start, bottom end. Physical,
40
- // since the icon does not mirror.
41
- const SQUARE_STYLES = [
42
- css({
43
- _controlActive: { transform: "translate(5px, 5px)" },
44
- "--spread-x": "-9px",
45
- "--spread-y": "-9px",
46
- transition: "transform {durations.fast} {easings.out}",
47
- }),
48
- css({
49
- _controlActive: { transform: "translate(-5px, 5px)" },
50
- "--spread-x": "9px",
51
- "--spread-y": "-9px",
52
- transition: "transform {durations.fast} {easings.out}",
53
- }),
54
- css({
55
- _controlActive: { transform: "translate(5px, -5px)" },
56
- "--spread-x": "-9px",
57
- "--spread-y": "9px",
58
- transition: "transform {durations.fast} {easings.out}",
59
- }),
60
- css({
61
- _controlActive: { transform: "translate(-5px, -5px)" },
62
- "--spread-x": "9px",
63
- "--spread-y": "9px",
64
- transition: "transform {durations.fast} {easings.out}",
65
- }),
66
- ];
41
+ // Each square moves in along its diagonal while pressed.
42
+ const squarePressStyles = css({
43
+ _controlActive: {
44
+ transform:
45
+ "translate(calc(var(--part-x) * -5px), calc(var(--part-y) * -5px))",
46
+ },
47
+ transition: "transform {durations.fast} {easings.out}",
48
+ });
@@ -8,6 +8,11 @@ type Props = {
8
8
  /** The animation each cue plays. */
9
9
  cueStyles?: string | undefined;
10
10
  d: string;
11
+ /**
12
+ * The way it moves in motions that move parts apart, from -1 to 1 on each
13
+ * axis, as `--part-x` and `--part-y`.
14
+ */
15
+ direction?: readonly [number, number] | undefined;
11
16
  /** The animation played while the control the icon is in is pointed at. */
12
17
  hoverStyles?: string | undefined;
13
18
  /** What the part is, for styles and tests: "clapper", "arc". */
@@ -31,6 +36,7 @@ export const IconPart = ({
31
36
  cue = 0,
32
37
  cueStyles,
33
38
  d,
39
+ direction = [0, 0],
34
40
  hoverStyles,
35
41
  name,
36
42
  order = 0,
@@ -46,6 +52,8 @@ export const IconPart = ({
46
52
  {
47
53
  "--part-order": order,
48
54
  "--part-origin": `${origin[0].toString()}px ${origin[1].toString()}px`,
55
+ "--part-x": direction[0],
56
+ "--part-y": direction[1],
49
57
  } as CSSProperties
50
58
  }
51
59
  >
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The ways four corner parts move apart, as `IconPart` directions: top
3
+ * start, top end, bottom start, bottom end. Physical, since icons do not
4
+ * mirror.
5
+ */
6
+ export const DIAGONALS = [
7
+ [-1, -1],
8
+ [1, -1],
9
+ [-1, 1],
10
+ [1, 1],
11
+ ] as const;
@@ -13,6 +13,25 @@ export const iconKeyframes = {
13
13
  "0%, 100%": { opacity: "0.25" },
14
14
  "50%": { opacity: "1" },
15
15
  },
16
+ // A plus's arm reaches out along its direction, and back.
17
+ iconArmReach: {
18
+ "0%, 100%": { transform: "none" },
19
+ "50%": {
20
+ transform:
21
+ "scale(calc(1 + var(--part-x) * 0.18), calc(1 + var(--part-y) * 0.18))",
22
+ },
23
+ },
24
+ // An arm swings `--swing` the way its direction says, and back: an X
25
+ // snipping, a caret's point sharpening.
26
+ iconArmSwing: {
27
+ "0%, 100%": { transform: "none" },
28
+ "50%": { transform: "rotate(calc(var(--part-x) * var(--swing)))" },
29
+ },
30
+ // A reload arrow winds forward, and back.
31
+ iconArrowWind: {
32
+ "0%, 100%": { transform: "none" },
33
+ "50%": { transform: "rotate(40deg)" },
34
+ },
16
35
  // The bell's clapper, lagging the swing.
17
36
  iconBellClapper: {
18
37
  "0%, 100%": { transform: "none" },
@@ -73,11 +92,22 @@ export const iconKeyframes = {
73
92
  "0%, 100%": { opacity: "1" },
74
93
  "50%": { opacity: "0.25" },
75
94
  },
95
+ // A download's arrow drops into its tray.
96
+ iconDownloadDrop: {
97
+ "0%": { opacity: "0", transform: "translateY(-60px)" },
98
+ "70%": { opacity: "1", transform: "translateY(10px)" },
99
+ "100%": { opacity: "1", transform: "none" },
100
+ },
76
101
  // The gear turns one tooth. Its six teeth make the end look like the start.
77
102
  iconGearTurn: {
78
103
  "0%": { transform: "none" },
79
104
  "100%": { transform: "rotate(60deg)" },
80
105
  },
106
+ // A lock's keyhole swells as its shackle shuts.
107
+ iconKeyholePulse: {
108
+ "0%, 100%": { transform: "none" },
109
+ "50%": { transform: "scale(1.35)" },
110
+ },
81
111
  // A key presses down.
82
112
  iconKeyPress: {
83
113
  "0%, 100%": { transform: "none" },
@@ -103,6 +133,15 @@ export const iconKeyframes = {
103
133
  "35%": { transform: "rotate(-12deg)" },
104
134
  "70%": { transform: "rotate(5deg)" },
105
135
  },
136
+ // A part moves `--spread` out along its direction (see `IconPart`), and
137
+ // back.
138
+ iconPartSpread: {
139
+ "0%, 100%": { transform: "none" },
140
+ "50%": {
141
+ transform:
142
+ "translate(calc(var(--part-x) * var(--spread)), calc(var(--part-y) * var(--spread)))",
143
+ },
144
+ },
106
145
  // The eye's pupil looks one way, then the other.
107
146
  iconPupilGlance: {
108
147
  "0%, 100%": { transform: "none" },
@@ -123,10 +162,21 @@ export const iconKeyframes = {
123
162
  "0%, 100%": { transform: "none" },
124
163
  "50%": { transform: "scale(0.88)" },
125
164
  },
126
- // A launcher square moves out along `--spread-x` and `--spread-y`, and back.
127
- iconSquareSpread: {
165
+ // A lock's shackle lifts a little, and back.
166
+ iconShackleLift: {
167
+ "0%, 100%": { transform: "none" },
168
+ "50%": { transform: "translateY(-14px)" },
169
+ },
170
+ // A lock's shackle snaps shut from open.
171
+ iconShackleShut: {
172
+ "0%": { transform: "translateY(-30px)" },
173
+ "70%": { transform: "translateY(4px)" },
174
+ "100%": { transform: "none" },
175
+ },
176
+ // A download's tray gives under the arrow landing in it.
177
+ iconTrayGive: {
128
178
  "0%, 100%": { transform: "none" },
129
- "50%": { transform: "translate(var(--spread-x), var(--spread-y))" },
179
+ "70%": { transform: "scaleY(0.86)" },
130
180
  },
131
181
  // A speaker wave pulls in, for quieter.
132
182
  iconWavePull: {
@@ -168,3 +168,49 @@ export const CHECK_BOLD = {
168
168
  check:
169
169
  "M232.49 80.49L104.49 208.49A12 12 0 0 1 87.49 208.49L31.49 152.49A12 12 0 1 1 48.49 135.49L96 183 215.51 63.51A12 12 0 0 1 232.51 80.51Z",
170
170
  } as const;
171
+
172
+ /** CornersOut regular; top start, top end, bottom start, bottom end. */
173
+ export const CORNERS_OUT_REGULAR = {
174
+ corners: [
175
+ "M88 40H48A8 8 0 0 0 40 48V88A8 8 0 0 0 56 88V56H88A8 8 0 0 0 88 40Z",
176
+ "M216 48V88A8 8 0 0 1 200 88V56H168A8 8 0 0 1 168 40H208A8 8 0 0 1 216 48Z",
177
+ "M88 200H56V168A8 8 0 0 0 40 168V208A8 8 0 0 0 48 216H88A8 8 0 0 0 88 200Z",
178
+ "M208 160A8 8 0 0 0 200 168V200H168A8 8 0 0 0 168 216H208A8 8 0 0 0 216 208V168A8 8 0 0 0 208 160Z",
179
+ ],
180
+ } as const;
181
+
182
+ /** CornersIn regular; top start, top end, bottom start, bottom end. */
183
+ export const CORNERS_IN_REGULAR = {
184
+ corners: [
185
+ "M96 40A8 8 0 0 0 88 48V88H48A8 8 0 0 0 48 104H96A8 8 0 0 0 104 96V48A8 8 0 0 0 96 40Z",
186
+ "M152 96V48A8 8 0 0 1 168 48V88H208A8 8 0 0 1 208 104H160A8 8 0 0 1 152 96Z",
187
+ "M96 152H48A8 8 0 0 0 48 168H88V208A8 8 0 0 0 104 208V160A8 8 0 0 0 96 152Z",
188
+ "M208 152H160A8 8 0 0 0 152 160V208A8 8 0 0 0 168 208V168H208A8 8 0 0 0 208 152Z",
189
+ ],
190
+ } as const;
191
+
192
+ /** Rows regular; top first. */
193
+ export const ROWS_REGULAR = {
194
+ rows: [
195
+ "M208 48H48A16 16 0 0 0 32 64V104A16 16 0 0 0 48 120H208A16 16 0 0 0 224 104V64A16 16 0 0 0 208 48ZM208 104H48V64H208V104Z",
196
+ "M208 136H48A16 16 0 0 0 32 152V192A16 16 0 0 0 48 208H208A16 16 0 0 0 224 192V152A16 16 0 0 0 208 136ZM208 192H48V152H208V192Z",
197
+ ],
198
+ } as const;
199
+
200
+ /** Tabs regular. */
201
+ export const TABS_REGULAR = {
202
+ tabs: "M255.66 165.7H255.66V165.7A0.24 0.24 0 0 0 255.66 165.62L233.37 91.4A15.89 15.89 0 0 0 218.05 80H208A8 8 0 0 0 208 96H218.05L237.25 160H206L185.37 91.4A15.89 15.89 0 0 0 170.05 80H160A8 8 0 0 0 160 96H170.05L189.25 160H158L137.37 91.4A15.89 15.89 0 0 0 122.05 80H38A15.89 15.89 0 0 0 22.63 91.4L0.37 165.6 0.37 165.65V165.65S0.37 165.7 0.37 165.73A8.1 8.1 0 0 0 0 168 8 8 0 0 0 8 176H248A8 8 0 0 0 255.66 165.7ZM38 96H122.1L141.3 160H18.75Z",
203
+ } as const;
204
+
205
+ /** ArrowClockwise regular. */
206
+ export const ARROW_CLOCKWISE_REGULAR = {
207
+ arrow:
208
+ "M240 56V104A8 8 0 0 1 232 112H184A8 8 0 0 1 184 96H211.4L184.81 71.64 184.56 71.4A80 80 0 1 0 182.89 186.18 8 8 0 0 1 193.89 197.81 95.44 95.44 0 0 1 128 224H126.68A96 96 0 1 1 195.75 60L224 85.8V56A8 8 0 1 1 240 56Z",
209
+ } as const;
210
+
211
+ /** DownloadSimple regular. */
212
+ export const DOWNLOAD_REGULAR = {
213
+ arrow:
214
+ "M122.34 149.66A8 8 0 0 0 133.66 149.66L173.66 109.66A8 8 0 0 0 162.34 98.34L136 124.69V32A8 8 0 0 0 120 32V124.69L93.66 98.34A8 8 0 0 0 82.34 109.66Z",
215
+ tray: "M224 144V208A8 8 0 0 1 216 216H40A8 8 0 0 1 32 208V144A8 8 0 0 1 48 144V200H208V144A8 8 0 0 1 224 144Z",
216
+ } as const;
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Phosphor icons whose moving parts Phosphor merges into one outline, drawn
3
+ * again as separate parts that cover the same ground at rest: each is the
4
+ * same strokes and boxes, so the outline the parts join into is Phosphor's.
5
+ * As in Phosphor's paths, outlines run counterclockwise and holes clockwise.
6
+ */
7
+
8
+ /** X regular: its two 16-wide strokes, top start first. */
9
+ export const X_REGULAR = {
10
+ arms: [
11
+ "M61.66 50.34L205.66 194.34A8 8 0 0 1 194.34 205.66L50.34 61.66A8 8 0 0 1 61.66 50.34Z",
12
+ "M194.34 50.34A8 8 0 0 1 205.66 61.66L61.66 205.66A8 8 0 0 1 50.34 194.34Z",
13
+ ],
14
+ } as const;
15
+
16
+ /** Plus regular: its two 16-wide strokes, across first. */
17
+ export const PLUS_REGULAR = {
18
+ arms: [
19
+ "M40 120H216A8 8 0 0 1 216 136H40A8 8 0 0 1 40 120Z",
20
+ "M120 40A8 8 0 0 1 136 40V216A8 8 0 0 1 120 216Z",
21
+ ],
22
+ } as const;
23
+
24
+ /**
25
+ * Browsers regular: the window behind, whole, the window in front, and the
26
+ * front window's outline, which masks the one behind where it overlaps.
27
+ */
28
+ export const BROWSERS_REGULAR = {
29
+ back: "M216 40H72A16 16 0 0 0 56 56V168A16 16 0 0 0 72 184H216A16 16 0 0 0 232 168V56A16 16 0 0 0 216 40ZM72 56H216V168H72Z",
30
+ front:
31
+ "M184 72H40A16 16 0 0 0 24 88V200A16 16 0 0 0 40 216H184A16 16 0 0 0 200 200V88A16 16 0 0 0 184 72ZM184 88V104H40V88ZM184 200H40V120H184V200Z",
32
+ frontOutline:
33
+ "M184 72H40A16 16 0 0 0 24 88V200A16 16 0 0 0 40 216H184A16 16 0 0 0 200 200V88A16 16 0 0 0 184 72Z",
34
+ } as const;
35
+
36
+ /**
37
+ * SquareSplitHorizontal and SquareSplitVertical regular: their shared frame,
38
+ * and the divider each draws inside it.
39
+ */
40
+ export const SQUARE_SPLIT_REGULAR = {
41
+ frame:
42
+ "M200 40H56A16 16 0 0 0 40 56V200A16 16 0 0 0 56 216H200A16 16 0 0 0 216 200V56A16 16 0 0 0 200 40ZM56 56H200V200H56Z",
43
+ horizontal: "M120 56H136V200H120Z",
44
+ vertical: "M56 120H200V136H56Z",
45
+ } as const;
46
+
47
+ /**
48
+ * CaretLeft, CaretUp, CaretRight and CaretDown regular: their two 16-wide
49
+ * strokes, the one that turns clockwise to meet the other first, and the tip
50
+ * they meet at.
51
+ */
52
+ export const CARET_REGULAR = {
53
+ down: {
54
+ arms: [
55
+ "M42.34 101.66L122.34 181.66A8 8 0 0 0 133.66 170.34L53.66 90.34A8 8 0 0 0 42.34 101.66Z",
56
+ "M133.66 181.66L213.66 101.66A8 8 0 0 0 202.34 90.34L122.34 170.34A8 8 0 0 0 133.66 181.66Z",
57
+ ],
58
+ tip: [128, 176],
59
+ },
60
+ left: {
61
+ arms: [
62
+ "M154.34 42.34L74.34 122.34A8 8 0 0 0 85.66 133.66L165.66 53.66A8 8 0 0 0 154.34 42.34Z",
63
+ "M74.34 133.66L154.34 213.66A8 8 0 0 0 165.66 202.34L85.66 122.34A8 8 0 0 0 74.34 133.66Z",
64
+ ],
65
+ tip: [80, 128],
66
+ },
67
+ right: {
68
+ arms: [
69
+ "M101.66 213.66L181.66 133.66A8 8 0 0 0 170.34 122.34L90.34 202.34A8 8 0 0 0 101.66 213.66Z",
70
+ "M181.66 122.34L101.66 42.34A8 8 0 0 0 90.34 53.66L170.34 133.66A8 8 0 0 0 181.66 122.34Z",
71
+ ],
72
+ tip: [176, 128],
73
+ },
74
+ up: {
75
+ arms: [
76
+ "M213.66 154.34L133.66 74.34A8 8 0 0 0 122.34 85.66L202.34 165.66A8 8 0 0 0 213.66 154.34Z",
77
+ "M122.34 74.34L42.34 154.34A8 8 0 0 0 53.66 165.66L133.66 85.66A8 8 0 0 0 122.34 74.34Z",
78
+ ],
79
+ tip: [128, 80],
80
+ },
81
+ } as const;
82
+
83
+ /** X bold: its two 24-wide strokes, top start first. */
84
+ export const X_BOLD = {
85
+ arms: [
86
+ "M47.51 64.49L191.51 208.49A12 12 0 0 0 208.49 191.51L64.49 47.51A12 12 0 0 0 47.51 64.49Z",
87
+ "M191.51 47.51L47.51 191.51A12 12 0 0 0 64.49 208.49L208.49 64.49A12 12 0 0 0 191.51 47.51Z",
88
+ ],
89
+ } as const;
90
+
91
+ /** Plus bold: its two 24-wide strokes, across first. */
92
+ export const PLUS_BOLD = {
93
+ arms: [
94
+ "M40 140L216 140A12 12 0 0 0 216 116L40 116A12 12 0 0 0 40 140Z",
95
+ "M116 40L116 216A12 12 0 0 0 140 216L140 40A12 12 0 0 0 116 40Z",
96
+ ],
97
+ } as const;
98
+
99
+ /** Minus bold: its one 24-wide stroke. */
100
+ export const MINUS_BOLD = {
101
+ bar: "M40 140L216 140A12 12 0 0 0 216 116L40 116A12 12 0 0 0 40 140Z",
102
+ } as const;
103
+
104
+ /** Lock regular: its body, its shackle and its keyhole. */
105
+ export const LOCK_REGULAR = {
106
+ body: "M208 80H48A16 16 0 0 0 32 96V208A16 16 0 0 0 48 224H208A16 16 0 0 0 224 208V96A16 16 0 0 0 208 80ZM208 208H48V96H208V208Z",
107
+ keyhole: "M140 152A12 12 0 1 1 128 140 12 12 0 0 1 140 152Z",
108
+ shackle: "M80 80V56A48 48 0 0 1 176 56V80H160V56A32 32 0 0 0 96 56V80Z",
109
+ } as const;
110
+
111
+ /**
112
+ * SlidersHorizontal regular: its tracks and knobs, top first, and each
113
+ * knob's disk, which masks its track where the knob sits.
114
+ */
115
+ export const SLIDERS_REGULAR = {
116
+ knobDisks: [
117
+ "M136 80A32 32 0 1 0 72 80A32 32 0 1 0 136 80Z",
118
+ "M200 176A32 32 0 1 0 136 176A32 32 0 1 0 200 176Z",
119
+ ],
120
+ knobs: [
121
+ "M136 80A32 32 0 1 0 72 80A32 32 0 1 0 136 80ZM120 80A16 16 0 1 1 88 80A16 16 0 1 1 120 80Z",
122
+ "M200 176A32 32 0 1 0 136 176A32 32 0 1 0 200 176ZM184 176A16 16 0 1 1 152 176A16 16 0 1 1 184 176Z",
123
+ ],
124
+ tracks: [
125
+ "M40 88L216 88A8 8 0 0 0 216 72L40 72A8 8 0 0 0 40 88Z",
126
+ "M40 184L216 184A8 8 0 0 0 216 168L40 168A8 8 0 0 0 40 184Z",
127
+ ],
128
+ } as const;
@@ -169,7 +169,7 @@ export interface UtilityValues {
169
169
  transitionProperty: "common" | "colors" | "size" | "position" | "background";
170
170
  transition: "all" | "common" | "size" | "position" | "background" | "colors" | "opacity" | "shadow" | "transform";
171
171
  animation: Tokens["animations"];
172
- animationName: "ping" | "bounce" | "iconArcRipple" | "iconArcSearch" | "iconBellClapper" | "iconBellNudge" | "iconBellSwing" | "iconBoltStrike" | "iconBubbleTip" | "iconCapsuleBob" | "iconCheckDraw" | "iconCoreIn" | "iconCoreOut" | "iconDotBlink" | "iconGearTurn" | "iconKeyPress" | "iconLineWrite" | "iconMoonIn" | "iconMoonOut" | "iconMoonRock" | "iconPupilGlance" | "iconRayIn" | "iconRayOut" | "iconRayPulse" | "iconSquareSpread" | "iconWavePull" | "iconWavePush" | "levelToastEnter" | "levelToastHold" | "levelToastHoldAgain" | "noticeShown" | "pulse" | "spin" | "themeSwipeFromBottom" | "themeSwipeFromTop" | "toastCountdown";
172
+ animationName: "ping" | "bounce" | "iconArcRipple" | "iconArcSearch" | "iconArmReach" | "iconArmSwing" | "iconArrowWind" | "iconBellClapper" | "iconBellNudge" | "iconBellSwing" | "iconBoltStrike" | "iconBubbleTip" | "iconCapsuleBob" | "iconCheckDraw" | "iconCoreIn" | "iconCoreOut" | "iconDotBlink" | "iconDownloadDrop" | "iconGearTurn" | "iconKeyholePulse" | "iconKeyPress" | "iconLineWrite" | "iconMoonIn" | "iconMoonOut" | "iconMoonRock" | "iconPartSpread" | "iconPupilGlance" | "iconRayIn" | "iconRayOut" | "iconRayPulse" | "iconShackleLift" | "iconShackleShut" | "iconTrayGive" | "iconWavePull" | "iconWavePush" | "levelToastEnter" | "levelToastHold" | "levelToastHoldAgain" | "noticeShown" | "pulse" | "spin" | "themeSwipeFromBottom" | "themeSwipeFromTop" | "toastCountdown";
173
173
  animationTimingFunction: Tokens["easings"];
174
174
  animationDuration: Tokens["durations"];
175
175
  animationDelay: Tokens["durations"];