mac-human-design 0.1.15 → 0.1.17

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/changelog.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  This file tracks changes between published npm versions of `mac-human-design`.
4
4
 
5
+ ## 0.1.17
6
+
7
+ ### Changed
8
+
9
+ - Added center-origin Motion feedback for checkbox, radio, switch, slider thumb,
10
+ and tab indicator primitives so selection controls feel responsive without
11
+ shifting layout.
12
+ - Added CSS transition polish for menu rows, tabs, toggles, switches, sliders,
13
+ progress indicators, and selected states.
14
+ - Preserved icon-only button centering by keeping all new feedback scale-based
15
+ and non-positional.
16
+ - Bumped the package to `0.1.17`.
17
+
18
+ ## 0.1.16
19
+
20
+ ### Changed
21
+
22
+ - Added shared Motion-backed entrance and layout transitions to
23
+ `MacWindowToolbar` so Tauri toolbars animate consistently with the Base UI
24
+ wrappers while keeping icon controls centered.
25
+ - Added shared Motion-backed row and state transitions to `MacDataTable`,
26
+ including subtle selected-row emphasis and non-layout-shifting interactive
27
+ feedback.
28
+ - Bumped the package to `0.1.16`.
29
+
5
30
  ## 0.1.15
6
31
 
7
32
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mac-human-design",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "Reusable macOS-oriented UI primitives and SF Symbols bridge for Tauri apps.",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -165,6 +165,21 @@ function getMotionDefaults(macClassName: string, props: Record<string, unknown>)
165
165
  };
166
166
  }
167
167
 
168
+ if (includesAny(macClassName, ["hd-mac-checkbox", "hd-mac-radio"])) {
169
+ return {
170
+ whileHover: { scale: 1.03 },
171
+ whileTap: { scale: 0.92 },
172
+ transition: macFastTransition,
173
+ };
174
+ }
175
+
176
+ if (macClassName.includes("hd-mac-switch")) {
177
+ return {
178
+ whileTap: { scale: 0.985 },
179
+ transition: macFastTransition,
180
+ };
181
+ }
182
+
168
183
  if (includesAny(macClassName, ["hd-mac-checkbox-indicator", "hd-mac-radio-indicator"])) {
169
184
  return fadeScaleDefaults({ opacity: 0, scale: 0.72 }, { opacity: 1, scale: 1 });
170
185
  }
@@ -172,6 +187,7 @@ function getMotionDefaults(macClassName: string, props: Record<string, unknown>)
172
187
  if (macClassName.includes("hd-mac-switch-thumb") || macClassName.includes("hd-mac-slider-thumb")) {
173
188
  return {
174
189
  layout: true,
190
+ whileHover: { scale: 1.04 },
175
191
  whileTap: { scale: 0.92 },
176
192
  transition: macDefaultTransition,
177
193
  };
@@ -234,6 +250,13 @@ function getMotionDefaults(macClassName: string, props: Record<string, unknown>)
234
250
  return fadeScaleDefaults({ opacity: 0, scale: 0.76 }, { opacity: 1, scale: 1 }, macFastTransition);
235
251
  }
236
252
 
253
+ if (macClassName.includes("hd-mac-tab-indicator")) {
254
+ return {
255
+ layout: true,
256
+ transition: macDefaultTransition,
257
+ };
258
+ }
259
+
237
260
  if (includesAny(macClassName, ["hd-mac-avatar", "hd-mac-avatar-image", "hd-mac-avatar-fallback"])) {
238
261
  return fadeScaleDefaults({ opacity: 0, scale: 0.92 });
239
262
  }
@@ -1,4 +1,5 @@
1
1
  import * as React from "react";
2
+ import { motion, type Transition } from "motion/react";
2
3
 
3
4
  export type MacDataTableColumn<Row> = {
4
5
  id: string;
@@ -43,6 +44,11 @@ function alignmentClassName(align: MacDataTableColumn<unknown>["align"]) {
43
44
  return undefined;
44
45
  }
45
46
 
47
+ const tableTransition: Transition = {
48
+ default: { type: "spring", stiffness: 520, damping: 44, mass: 0.78 },
49
+ opacity: { duration: 0.12, ease: "easeOut" },
50
+ };
51
+
46
52
  export function MacDataTable<Row>({
47
53
  columns,
48
54
  rows,
@@ -63,14 +69,19 @@ export function MacDataTable<Row>({
63
69
  const hasInteractiveRows = Boolean(onRowClick || onRowDoubleClick);
64
70
 
65
71
  return (
66
- <div
72
+ <motion.div
73
+ initial={{ opacity: 0 }}
74
+ animate={{ opacity: 1 }}
75
+ transition={tableTransition}
67
76
  className={joinClasses("hd-mac-data-table", bordered && "hd-mac-data-table-bordered", className)}
68
77
  style={style}
69
78
  >
70
- <div
79
+ <motion.div
80
+ layout
71
81
  className="hd-mac-data-table-header"
72
82
  role="row"
73
83
  style={{ gridTemplateColumns }}
84
+ transition={tableTransition}
74
85
  >
75
86
  {columns.map((column) => (
76
87
  <div
@@ -86,18 +97,40 @@ export function MacDataTable<Row>({
86
97
  {column.header}
87
98
  </div>
88
99
  ))}
89
- </div>
100
+ </motion.div>
90
101
 
91
102
  {loading ? (
92
- <div className="hd-mac-data-table-message">{loadingContent}</div>
103
+ <motion.div
104
+ initial={{ opacity: 0, y: -2 }}
105
+ animate={{ opacity: 1, y: 0 }}
106
+ transition={tableTransition}
107
+ className="hd-mac-data-table-message"
108
+ >
109
+ {loadingContent}
110
+ </motion.div>
93
111
  ) : rows.length === 0 ? (
94
- <div className="hd-mac-data-table-message">{emptyContent}</div>
112
+ <motion.div
113
+ initial={{ opacity: 0, y: -2 }}
114
+ animate={{ opacity: 1, y: 0 }}
115
+ transition={tableTransition}
116
+ className="hd-mac-data-table-message"
117
+ >
118
+ {emptyContent}
119
+ </motion.div>
95
120
  ) : (
96
121
  rows.map((row, index) => {
97
122
  const selected = isRowSelected?.(row, index) ?? false;
98
123
  return (
99
- <div
124
+ <motion.div
100
125
  key={getRowKey(row, index)}
126
+ layout
127
+ initial={{ opacity: 0, y: 3 }}
128
+ animate={{ opacity: 1, y: 0 }}
129
+ whileTap={hasInteractiveRows ? { scale: 0.998 } : undefined}
130
+ transition={{
131
+ ...tableTransition,
132
+ delay: Math.min(index * 0.012, 0.06),
133
+ }}
101
134
  className={joinClasses(
102
135
  "hd-mac-data-table-row",
103
136
  hasInteractiveRows && "hd-mac-data-table-row-interactive",
@@ -123,10 +156,10 @@ export function MacDataTable<Row>({
123
156
  {column.render(row, index)}
124
157
  </div>
125
158
  ))}
126
- </div>
159
+ </motion.div>
127
160
  );
128
161
  })
129
162
  )}
130
- </div>
163
+ </motion.div>
131
164
  );
132
165
  }
@@ -1,4 +1,5 @@
1
1
  import * as React from "react";
2
+ import { motion, type Transition } from "motion/react";
2
3
 
3
4
  export type MacWindowToolbarProps = {
4
5
  leading?: React.ReactNode;
@@ -13,6 +14,11 @@ function joinClasses(...classes: Array<string | undefined | false>) {
13
14
  return classes.filter(Boolean).join(" ");
14
15
  }
15
16
 
17
+ const toolbarTransition: Transition = {
18
+ default: { type: "spring", stiffness: 500, damping: 42, mass: 0.8 },
19
+ opacity: { duration: 0.14, ease: "easeOut" },
20
+ };
21
+
16
22
  export function MacWindowToolbar({
17
23
  leading,
18
24
  title,
@@ -22,31 +28,54 @@ export function MacWindowToolbar({
22
28
  style,
23
29
  }: MacWindowToolbarProps) {
24
30
  return (
25
- <div
31
+ <motion.div
32
+ initial={{ opacity: 0, y: -4 }}
33
+ animate={{ opacity: 1, y: 0 }}
34
+ transition={toolbarTransition}
26
35
  className={joinClasses("hd-mac-window-toolbar", className)}
27
36
  data-tauri-drag-region
28
37
  style={style}
29
38
  >
30
39
  {leading ? (
31
- <div className="hd-mac-window-toolbar-group" data-tauri-no-drag-region>
40
+ <motion.div
41
+ layout
42
+ className="hd-mac-window-toolbar-group"
43
+ data-tauri-no-drag-region
44
+ transition={toolbarTransition}
45
+ >
32
46
  {leading}
33
- </div>
47
+ </motion.div>
34
48
  ) : null}
35
49
  {title ? (
36
- <div className="hd-mac-window-toolbar-title" data-tauri-drag-region>
50
+ <motion.div
51
+ layout
52
+ className="hd-mac-window-toolbar-title"
53
+ data-tauri-drag-region
54
+ transition={toolbarTransition}
55
+ >
37
56
  {title}
38
- </div>
57
+ </motion.div>
39
58
  ) : null}
40
59
  {children ? (
41
- <div className="hd-mac-window-toolbar-content" data-tauri-no-drag-region>
60
+ <motion.div
61
+ layout
62
+ className="hd-mac-window-toolbar-content"
63
+ data-tauri-no-drag-region
64
+ transition={toolbarTransition}
65
+ >
42
66
  {children}
43
- </div>
67
+ </motion.div>
44
68
  ) : null}
45
69
  {trailing ? (
46
- <div className="hd-mac-window-toolbar-group" data-tauri-no-drag-region>
70
+ <motion.div
71
+ layout
72
+ className="hd-mac-window-toolbar-group"
73
+ data-tauri-no-drag-region
74
+ transition={toolbarTransition}
75
+ >
47
76
  {trailing}
48
- </div>
77
+ </motion.div>
49
78
  ) : null}
50
- </div>
79
+ </motion.div>
51
80
  );
52
81
  }
@@ -27,6 +27,7 @@
27
27
  --hd-mac-motion-fast: 90ms cubic-bezier(0.2, 0.8, 0.2, 1);
28
28
  --hd-mac-motion-standard: 140ms cubic-bezier(0.2, 0.8, 0.2, 1);
29
29
  --hd-mac-motion-surface: 180ms cubic-bezier(0.16, 1, 0.3, 1);
30
+ --hd-mac-motion-row: 120ms cubic-bezier(0.2, 0.8, 0.2, 1);
30
31
  }
31
32
 
32
33
  @media (prefers-color-scheme: dark) {
@@ -64,7 +65,14 @@
64
65
  .hd-mac-stepper-button,
65
66
  .hd-mac-switch,
66
67
  .hd-mac-switch-thumb,
67
- .hd-mac-slider-thumb {
68
+ .hd-mac-slider-thumb,
69
+ .hd-mac-checkbox,
70
+ .hd-mac-radio,
71
+ .hd-mac-tab,
72
+ .hd-mac-menu-item,
73
+ .hd-mac-window-toolbar,
74
+ .hd-mac-data-table,
75
+ .hd-mac-data-table-row {
68
76
  transition-duration: 1ms !important;
69
77
  animation-duration: 1ms !important;
70
78
  animation-iteration-count: 1 !important;
@@ -581,6 +589,10 @@
581
589
  font: 400 13px/18px var(--hd-mac-font);
582
590
  text-decoration: none;
583
591
  user-select: none;
592
+ transition:
593
+ background-color var(--hd-mac-motion-fast),
594
+ color var(--hd-mac-motion-fast),
595
+ filter var(--hd-mac-motion-fast);
584
596
  }
585
597
 
586
598
  .hd-mac-menu-item[data-highlighted],
@@ -591,6 +603,11 @@
591
603
  color: #fff;
592
604
  }
593
605
 
606
+ .hd-mac-menu-item:active,
607
+ .hd-mac-navigation-link:active {
608
+ filter: brightness(0.96);
609
+ }
610
+
594
611
  .hd-mac-menu-item-indicator {
595
612
  width: 14px;
596
613
  display: inline-flex;
@@ -716,6 +733,23 @@
716
733
  background: var(--hd-mac-raised);
717
734
  box-shadow: var(--hd-mac-control-shadow);
718
735
  color: #fff;
736
+ transform-origin: center;
737
+ transition:
738
+ background-color var(--hd-mac-motion-standard),
739
+ border-color var(--hd-mac-motion-standard),
740
+ box-shadow var(--hd-mac-motion-standard),
741
+ filter var(--hd-mac-motion-fast),
742
+ transform var(--hd-mac-motion-fast);
743
+ }
744
+
745
+ .hd-mac-checkbox:hover,
746
+ .hd-mac-radio:hover {
747
+ filter: brightness(1.04);
748
+ }
749
+
750
+ .hd-mac-checkbox:active,
751
+ .hd-mac-radio:active {
752
+ filter: brightness(0.98);
719
753
  }
720
754
 
721
755
  .hd-mac-checkbox {
@@ -731,11 +765,15 @@
731
765
  .hd-mac-radio[data-checked] {
732
766
  border-color: transparent;
733
767
  background: var(--hd-mac-blue);
768
+ box-shadow:
769
+ 0 1px 0 rgba(255, 255, 255, 0.22) inset,
770
+ 0 1px 2px rgba(10, 132, 255, 0.32);
734
771
  }
735
772
 
736
773
  .hd-mac-checkbox-indicator,
737
774
  .hd-mac-radio-indicator {
738
775
  color: currentColor;
776
+ transform-origin: center;
739
777
  }
740
778
 
741
779
  .hd-mac-checkbox-indicator::before {
@@ -768,11 +806,28 @@
768
806
  border-radius: 999px;
769
807
  padding: 2px;
770
808
  background: var(--hd-mac-fill-pressed);
771
- transition: background-color 140ms ease;
809
+ box-shadow:
810
+ 0 1px 1px rgba(0, 0, 0, 0.08) inset,
811
+ 0 1px 0 rgba(255, 255, 255, 0.32);
812
+ transform-origin: center;
813
+ transition:
814
+ background-color var(--hd-mac-motion-standard),
815
+ border-color var(--hd-mac-motion-standard),
816
+ box-shadow var(--hd-mac-motion-standard),
817
+ filter var(--hd-mac-motion-fast),
818
+ transform var(--hd-mac-motion-fast);
819
+ }
820
+
821
+ .hd-mac-switch:hover {
822
+ filter: brightness(1.035);
772
823
  }
773
824
 
774
825
  .hd-mac-switch[data-checked] {
775
826
  background: var(--hd-mac-green);
827
+ border-color: color-mix(in srgb, var(--hd-mac-green) 74%, transparent);
828
+ box-shadow:
829
+ 0 1px 0 rgba(255, 255, 255, 0.26) inset,
830
+ 0 1px 2px rgba(48, 209, 88, 0.28);
776
831
  }
777
832
 
778
833
  .hd-mac-switch-thumb {
@@ -781,13 +836,24 @@
781
836
  border-radius: 999px;
782
837
  background: #fff;
783
838
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.32);
784
- transition: transform 160ms cubic-bezier(0.22, 1, 0.36, 1);
839
+ transform-origin: center;
840
+ transition:
841
+ transform var(--hd-mac-motion-surface),
842
+ box-shadow var(--hd-mac-motion-standard);
843
+ }
844
+
845
+ .hd-mac-switch:active .hd-mac-switch-thumb {
846
+ transform: scale(0.94);
785
847
  }
786
848
 
787
849
  .hd-mac-switch[data-checked] .hd-mac-switch-thumb {
788
850
  transform: translateX(16px);
789
851
  }
790
852
 
853
+ .hd-mac-switch[data-checked]:active .hd-mac-switch-thumb {
854
+ transform: translateX(16px) scale(0.94);
855
+ }
856
+
791
857
  .hd-mac-toggle-group {
792
858
  display: inline-flex;
793
859
  align-items: center;
@@ -835,6 +901,13 @@
835
901
  background: transparent;
836
902
  box-shadow: none;
837
903
  padding: 2px 10px;
904
+ transition:
905
+ background-color var(--hd-mac-motion-standard),
906
+ border-color var(--hd-mac-motion-standard),
907
+ box-shadow var(--hd-mac-motion-standard),
908
+ color var(--hd-mac-motion-standard),
909
+ filter var(--hd-mac-motion-fast),
910
+ transform var(--hd-mac-motion-fast);
838
911
  }
839
912
 
840
913
  .hd-mac-symbol-icon-button[data-loading] {
@@ -892,6 +965,22 @@
892
965
  background: transparent;
893
966
  color: var(--hd-mac-secondary-text);
894
967
  font: 590 12px/16px var(--hd-mac-font);
968
+ transform-origin: center;
969
+ transition:
970
+ background-color var(--hd-mac-motion-standard),
971
+ box-shadow var(--hd-mac-motion-standard),
972
+ color var(--hd-mac-motion-standard),
973
+ filter var(--hd-mac-motion-fast),
974
+ transform var(--hd-mac-motion-fast);
975
+ }
976
+
977
+ .hd-mac-tab:hover {
978
+ background: var(--hd-mac-fill-hover);
979
+ color: var(--hd-mac-text);
980
+ }
981
+
982
+ .hd-mac-tab:active {
983
+ filter: brightness(0.98);
895
984
  }
896
985
 
897
986
  .hd-mac-tab[data-selected] {
@@ -909,6 +998,10 @@
909
998
  height: 2px;
910
999
  border-radius: 999px;
911
1000
  background: var(--hd-mac-blue);
1001
+ transform-origin: center;
1002
+ transition:
1003
+ transform var(--hd-mac-motion-standard),
1004
+ opacity var(--hd-mac-motion-standard);
912
1005
  }
913
1006
 
914
1007
  .hd-mac-slider {
@@ -935,12 +1028,17 @@
935
1028
  .hd-mac-slider-track {
936
1029
  height: 4px;
937
1030
  width: 100%;
1031
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2) inset;
938
1032
  }
939
1033
 
940
1034
  .hd-mac-slider-indicator,
941
1035
  .hd-mac-progress-indicator,
942
1036
  .hd-mac-meter-indicator {
943
1037
  background: var(--hd-mac-blue);
1038
+ transition:
1039
+ width var(--hd-mac-motion-surface),
1040
+ transform var(--hd-mac-motion-surface),
1041
+ background-color var(--hd-mac-motion-standard);
944
1042
  }
945
1043
 
946
1044
  .hd-mac-slider-indicator {
@@ -954,6 +1052,23 @@
954
1052
  border-radius: 999px;
955
1053
  background: #fff;
956
1054
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.34);
1055
+ transform-origin: center;
1056
+ transition:
1057
+ border-color var(--hd-mac-motion-standard),
1058
+ box-shadow var(--hd-mac-motion-standard),
1059
+ transform var(--hd-mac-motion-fast);
1060
+ }
1061
+
1062
+ .hd-mac-slider-thumb:hover {
1063
+ box-shadow:
1064
+ 0 1px 4px rgba(0, 0, 0, 0.34),
1065
+ 0 0 0 3px color-mix(in srgb, var(--hd-mac-blue) 16%, transparent);
1066
+ }
1067
+
1068
+ .hd-mac-slider-thumb:active {
1069
+ box-shadow:
1070
+ 0 1px 2px rgba(0, 0, 0, 0.28),
1071
+ 0 0 0 4px color-mix(in srgb, var(--hd-mac-blue) 22%, transparent);
957
1072
  }
958
1073
 
959
1074
  .hd-mac-progress,
@@ -1161,7 +1276,14 @@
1161
1276
  border-bottom: 1px solid var(--hd-mac-border);
1162
1277
  padding: 10px 16px;
1163
1278
  background: var(--hd-mac-surface);
1279
+ backdrop-filter: saturate(180%) blur(20px);
1280
+ -webkit-backdrop-filter: saturate(180%) blur(20px);
1164
1281
  box-sizing: border-box;
1282
+ transform-origin: top center;
1283
+ transition:
1284
+ background-color var(--hd-mac-motion-surface),
1285
+ border-color var(--hd-mac-motion-surface),
1286
+ box-shadow var(--hd-mac-motion-surface);
1165
1287
  }
1166
1288
 
1167
1289
  .hd-mac-window-toolbar-group,
@@ -1171,6 +1293,7 @@
1171
1293
  align-items: center;
1172
1294
  gap: 8px;
1173
1295
  flex-wrap: wrap;
1296
+ transform-origin: center;
1174
1297
  }
1175
1298
 
1176
1299
  .hd-mac-window-toolbar-title {
@@ -1187,6 +1310,7 @@
1187
1310
  min-width: 0;
1188
1311
  color: var(--hd-mac-text);
1189
1312
  font-family: var(--hd-mac-font);
1313
+ transform-origin: top center;
1190
1314
  }
1191
1315
 
1192
1316
  .hd-mac-data-table-bordered {
@@ -1211,6 +1335,12 @@
1211
1335
  .hd-mac-data-table-row {
1212
1336
  border-bottom: 1px solid var(--hd-mac-border);
1213
1337
  padding: 8px 10px;
1338
+ transform-origin: center;
1339
+ transition:
1340
+ background-color var(--hd-mac-motion-row),
1341
+ border-color var(--hd-mac-motion-row),
1342
+ box-shadow var(--hd-mac-motion-row),
1343
+ filter var(--hd-mac-motion-fast);
1214
1344
  }
1215
1345
 
1216
1346
  .hd-mac-data-table-row:last-child {
@@ -1225,8 +1355,13 @@
1225
1355
  background: var(--hd-mac-fill-hover);
1226
1356
  }
1227
1357
 
1358
+ .hd-mac-data-table-row-interactive:active {
1359
+ filter: brightness(0.98);
1360
+ }
1361
+
1228
1362
  .hd-mac-data-table-row[data-selected] {
1229
1363
  background: color-mix(in srgb, var(--hd-mac-blue) 18%, transparent);
1364
+ box-shadow: inset 3px 0 0 var(--hd-mac-blue);
1230
1365
  }
1231
1366
 
1232
1367
  .hd-mac-data-table-row[data-selected]:hover {