@santi020k/lumen 4.0.0 → 4.1.0

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/README.md CHANGED
@@ -68,6 +68,10 @@ also want to import its framework-neutral registry or diagnostics APIs:
68
68
  pnpm add @santi020k/lumen
69
69
  ```
70
70
 
71
+ Set direction with the `dir` attribute on `html` or a containing element. Select and NativeSelect
72
+ place their chevron from the nearest `dir="rtl"` or `dir="ltr"` ancestor, so nested LTR regions
73
+ inside RTL work even when a consumer CSS pipeline compiles `:dir()` into language selectors.
74
+
71
75
  ## Typography
72
76
 
73
77
  Lumen defaults `--ui-font` to the canonical Santi020k Montserrat family stack:
@@ -28,7 +28,7 @@
28
28
  "gradle": "9.8.0",
29
29
  "instrumentationApi": 35,
30
30
  "jdk": 21,
31
- "kotlin": "2.4.20",
31
+ "kotlin": "2.4.21",
32
32
  "minSdk": 23
33
33
  }
34
34
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@santi020k/lumen",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -51,7 +51,7 @@
51
51
  "lumen": "./bin/lumen.mjs"
52
52
  },
53
53
  "dependencies": {
54
- "@santi020k/lumen-core": "^4.0.0",
54
+ "@santi020k/lumen-core": "^4.1.0",
55
55
  "semver": "^7.8.5",
56
56
  "typescript": "~6.0.3"
57
57
  },
@@ -14,17 +14,17 @@
14
14
  "peerDependencies": {
15
15
  "astro": ">=5"
16
16
  },
17
- "version": "4.0.0"
17
+ "version": "4.1.0"
18
18
  },
19
19
  "@santi020k/lumen-core": {
20
20
  "peerDependencies": {
21
21
  "@rive-app/canvas": "^2.44.0"
22
22
  },
23
- "version": "4.0.0"
23
+ "version": "4.1.0"
24
24
  },
25
25
  "@santi020k/lumen-elements": {
26
26
  "peerDependencies": {},
27
- "version": "4.0.0"
27
+ "version": "4.1.0"
28
28
  },
29
29
  "@santi020k/lumen-icons-brand": {
30
30
  "peerDependencies": {},
@@ -34,18 +34,18 @@
34
34
  "peerDependencies": {
35
35
  "react": ">=19"
36
36
  },
37
- "version": "4.0.0"
37
+ "version": "4.1.0"
38
38
  },
39
39
  "@santi020k/lumen-mcp": {
40
40
  "peerDependencies": {},
41
- "version": "4.0.0"
41
+ "version": "4.1.0"
42
42
  },
43
43
  "@santi020k/lumen-react": {
44
44
  "peerDependencies": {
45
45
  "react": ">=19",
46
46
  "motion": "^14.0.0"
47
47
  },
48
- "version": "4.0.0"
48
+ "version": "4.1.0"
49
49
  },
50
50
  "@santi020k/lumen-react-hook-form": {
51
51
  "peerDependencies": {
@@ -53,7 +53,7 @@
53
53
  "react": ">=19",
54
54
  "react-hook-form": ">=7.76.0 <8"
55
55
  },
56
- "version": "4.0.0"
56
+ "version": "4.0.1"
57
57
  },
58
58
  "@santi020k/lumen-react-native": {
59
59
  "peerDependencies": {
@@ -62,7 +62,7 @@
62
62
  "react-native": ">=0.86.2",
63
63
  "react-native-svg": ">=12 <16"
64
64
  },
65
- "version": "4.0.0"
65
+ "version": "4.0.1"
66
66
  },
67
67
  "@santi020k/lumen-tokens": {
68
68
  "peerDependencies": {},
@@ -73,9 +73,9 @@
73
73
  "swift": {
74
74
  "package": "https://github.com/santi020k/lumen.git",
75
75
  "revision": null,
76
- "tag": "v4.0.0"
76
+ "tag": "v4.1.0"
77
77
  },
78
- "version": "4.0.0"
78
+ "version": "4.1.0"
79
79
  },
80
80
  "migration": {
81
81
  "codemod": null,
@@ -172,6 +172,17 @@
172
172
  }
173
173
  }
174
174
 
175
+ @keyframes ui-skeleton-pulse {
176
+ 0%,
177
+ 100% {
178
+ opacity: 1;
179
+ }
180
+
181
+ 50% {
182
+ opacity: 0.55;
183
+ }
184
+ }
185
+
175
186
  @keyframes ui-spin {
176
187
  to {
177
188
  transform: rotate(360deg);
@@ -790,15 +801,21 @@
790
801
  background-image:
791
802
  linear-gradient(45deg, transparent 50%, hsl(var(--ink-muted)) 50%),
792
803
  linear-gradient(135deg, hsl(var(--ink-muted)) 50%, transparent 50%);
793
- background-position:
794
- calc(100% - 1rem) 50%,
795
- calc(100% - 0.72rem) 50%;
804
+ background-position: var(--_ui-select-chevron, calc(100% - 1rem) 50%, calc(100% - 0.72rem) 50%);
796
805
  background-size:
797
806
  0.32rem 0.32rem,
798
807
  0.32rem 0.32rem;
799
808
  background-repeat: no-repeat;
800
809
  }
801
810
 
811
+ [dir="rtl"] {
812
+ --_ui-select-chevron: 0.72rem 50%, 1rem 50%;
813
+ }
814
+
815
+ [dir="ltr"] {
816
+ --_ui-select-chevron: calc(100% - 1rem) 50%, calc(100% - 0.72rem) 50%;
817
+ }
818
+
802
819
  .ui-label {
803
820
  color: hsl(var(--ink));
804
821
  font-size: 0.875rem;
@@ -1007,7 +1024,9 @@
1007
1024
  }
1008
1025
 
1009
1026
  .ui-skeleton {
1010
- min-height: 1rem;
1027
+ /* A default height, not a minimum, lets explicit styles and classes size placeholders below 1rem. */
1028
+ width: var(--ui-skeleton-width, auto);
1029
+ height: var(--ui-skeleton-height, 1rem);
1011
1030
  border-radius: var(--ui-radius-sm);
1012
1031
  background: linear-gradient(
1013
1032
  90deg,
@@ -1019,6 +1038,42 @@
1019
1038
  animation: ui-shimmer 2.2s linear infinite;
1020
1039
  }
1021
1040
 
1041
+ .ui-skeleton:where(:not(:empty)) {
1042
+ height: var(--ui-skeleton-height, auto);
1043
+ min-height: 1rem;
1044
+ }
1045
+
1046
+ lumen-skeleton.ui-skeleton,
1047
+ lumen-progress.ui-progress {
1048
+ display: block;
1049
+ }
1050
+
1051
+ .ui-skeleton--text {
1052
+ height: var(--ui-skeleton-height, 0.75rem);
1053
+ }
1054
+
1055
+ .ui-skeleton--circle {
1056
+ flex: 0 0 auto;
1057
+ width: var(--ui-skeleton-width, var(--ui-skeleton-height, 2.5rem));
1058
+ height: var(--ui-skeleton-height, var(--ui-skeleton-width, 2.5rem));
1059
+ border-radius: 50%;
1060
+ }
1061
+
1062
+ .ui-skeleton--pulse {
1063
+ background: hsl(var(--surface-strong));
1064
+ animation: ui-skeleton-pulse 1.6s ease-in-out infinite;
1065
+ }
1066
+
1067
+ .ui-skeleton--static {
1068
+ animation: none;
1069
+ }
1070
+
1071
+ @media (prefers-reduced-motion: reduce) {
1072
+ .ui-skeleton {
1073
+ animation: none;
1074
+ }
1075
+ }
1076
+
1022
1077
  .ui-spinner {
1023
1078
  box-sizing: border-box;
1024
1079
  display: inline-block;
@@ -1586,7 +1641,9 @@ lumen-dialog.ui-dialog:not([hidden]):has(> [data-slot="dialog-body"]) {
1586
1641
 
1587
1642
  .ui-input-otp__native[data-ui-enhanced="true"] {
1588
1643
  position: absolute;
1589
- width: 1px;
1644
+ inset-block-start: 0;
1645
+ inset-inline-start: 0;
1646
+ width: 100%;
1590
1647
  height: 1px;
1591
1648
  overflow: hidden;
1592
1649
  clip-path: inset(50%);
package/styles.css CHANGED
@@ -179,6 +179,17 @@
179
179
  }
180
180
  }
181
181
 
182
+ @keyframes ui-skeleton-pulse {
183
+ 0%,
184
+ 100% {
185
+ opacity: 1;
186
+ }
187
+
188
+ 50% {
189
+ opacity: 0.55;
190
+ }
191
+ }
192
+
182
193
  @keyframes ui-spin {
183
194
  to {
184
195
  transform: rotate(360deg);
@@ -1663,15 +1674,26 @@
1663
1674
  background-image:
1664
1675
  linear-gradient(45deg, transparent 50%, hsl(var(--ink-muted)) 50%),
1665
1676
  linear-gradient(135deg, hsl(var(--ink-muted)) 50%, transparent 50%);
1666
- background-position:
1667
- calc(100% - 1rem) 50%,
1668
- calc(100% - 0.72rem) 50%;
1677
+ background-position: var(--_ui-select-chevron, calc(100% - 1rem) 50%, calc(100% - 0.72rem) 50%);
1669
1678
  background-size:
1670
1679
  0.32rem 0.32rem,
1671
1680
  0.32rem 0.32rem;
1672
1681
  background-repeat: no-repeat;
1673
1682
  }
1674
1683
 
1684
+ /*
1685
+ * Keep the chevron inside the inline-end padding. The private property inherits from the nearest
1686
+ * explicit `dir` attribute, so nested LTR regions inside RTL work and consumer CSS pipelines that
1687
+ * rewrite `:dir()` into language selectors cannot misplace it.
1688
+ */
1689
+ [dir="rtl"] {
1690
+ --_ui-select-chevron: 0.72rem 50%, 1rem 50%;
1691
+ }
1692
+
1693
+ [dir="ltr"] {
1694
+ --_ui-select-chevron: calc(100% - 1rem) 50%, calc(100% - 0.72rem) 50%;
1695
+ }
1696
+
1675
1697
  .ui-label {
1676
1698
  color: hsl(var(--ink));
1677
1699
  font-size: 0.875rem;
@@ -1785,6 +1807,7 @@
1785
1807
 
1786
1808
  .ui-date-picker__popover {
1787
1809
  width: min(21rem, calc(100vw - 2rem));
1810
+ color: inherit;
1788
1811
  max-height: none;
1789
1812
  overflow: visible;
1790
1813
  border-radius: var(--ui-radius-lg);
@@ -2126,7 +2149,9 @@
2126
2149
  }
2127
2150
 
2128
2151
  .ui-skeleton {
2129
- min-height: 1rem;
2152
+ /* A default height, not a minimum, lets explicit styles and classes size placeholders below 1rem. */
2153
+ width: var(--ui-skeleton-width, auto);
2154
+ height: var(--ui-skeleton-height, 1rem);
2130
2155
  border-radius: var(--ui-radius-sm);
2131
2156
  background: linear-gradient(
2132
2157
  90deg,
@@ -2138,6 +2163,44 @@
2138
2163
  animation: ui-shimmer 2.2s linear infinite;
2139
2164
  }
2140
2165
 
2166
+ /* Skeletons that wrap text or elements keep growing with their content. */
2167
+ .ui-skeleton:where(:not(:empty)) {
2168
+ height: var(--ui-skeleton-height, auto);
2169
+ min-height: 1rem;
2170
+ }
2171
+
2172
+ lumen-skeleton.ui-skeleton,
2173
+ lumen-progress.ui-progress {
2174
+ display: block;
2175
+ }
2176
+
2177
+ .ui-skeleton--text {
2178
+ height: var(--ui-skeleton-height, 0.75rem);
2179
+ }
2180
+
2181
+ .ui-skeleton--circle {
2182
+ flex: 0 0 auto;
2183
+ width: var(--ui-skeleton-width, var(--ui-skeleton-height, 2.5rem));
2184
+ height: var(--ui-skeleton-height, var(--ui-skeleton-width, 2.5rem));
2185
+ border-radius: 50%;
2186
+ }
2187
+
2188
+ .ui-skeleton--pulse {
2189
+ background: hsl(var(--surface-strong));
2190
+ animation: ui-skeleton-pulse 1.6s ease-in-out infinite;
2191
+ }
2192
+
2193
+ .ui-skeleton--static {
2194
+ animation: none;
2195
+ }
2196
+
2197
+ /* Critical CSS omits the universal reduction below, so Skeleton stops its own loop. */
2198
+ @media (prefers-reduced-motion: reduce) {
2199
+ .ui-skeleton {
2200
+ animation: none;
2201
+ }
2202
+ }
2203
+
2141
2204
  .ui-icon {
2142
2205
  --ui-icon-size: 1em;
2143
2206
  display: inline-flex;
@@ -4271,9 +4334,12 @@ lumen-dialog-close {
4271
4334
  text-align: center;
4272
4335
  }
4273
4336
 
4337
+ /* A 1px-wide text field makes Chromium apply maxlength to the old value when input replaces a selection. */
4274
4338
  .ui-input-otp__native[data-ui-enhanced="true"] {
4275
4339
  position: absolute;
4276
- width: 1px;
4340
+ inset-block-start: 0;
4341
+ inset-inline-start: 0;
4342
+ width: 100%;
4277
4343
  height: 1px;
4278
4344
  overflow: hidden;
4279
4345
  clip-path: inset(50%);
package/v4-migration.json CHANGED
@@ -437,11 +437,12 @@
437
437
  "approval": {
438
438
  "approver": "Santiago Molina (santi020k)",
439
439
  "date": "2026-10-07",
440
- "decision": "Publish Lumen 4.0.0 and deploy the coordinated release; deliver playground 1.0.3 for Apple and Android review with current screenshots and listing metadata under the standing authorization, after all checks and reviews pass. Standing authorization is recorded by santi020k in PR #95 comment 6027959606.",
441
- "reviewedRevision": "cdb28a38aca0071af35021341bb7fbbefd7730a6",
440
+ "decision": "Approve the independently reviewed Mac certificate extraction correction and real macOS tool regression under the standing authorization recorded by santi020k in PR #95 comment 6027959606. Delivery remains conditional on all required hosted checks and current Codex review passing before protected merge. Preserve immutable v4.0.0 artifacts and approved iOS and Android submissions and rollout holds; deliver the corrected Mac build from merged main.",
441
+ "reviewedRevision": "eea78c5a5d49f9f6610fbe23b75a8e721db03f7e",
442
442
  "evidence": [
443
- "https://github.com/santi020k/lumen/commit/cdb28a38aca0071af35021341bb7fbbefd7730a6",
444
- "https://github.com/santi020k/lumen/pull/95"
443
+ "https://github.com/santi020k/lumen/commit/eea78c5a5d49f9f6610fbe23b75a8e721db03f7e",
444
+ "https://github.com/santi020k/lumen/pull/95",
445
+ "https://github.com/santi020k/lumen/pull/101"
445
446
  ]
446
447
  }
447
448
  }