@signal9/era-ui 4.11.1 → 4.11.2

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.
@@ -78,9 +78,21 @@
78
78
  * that gap; pushing it darker closes it. */
79
79
  --color-destructive: oklch(0.65 0.2 25); /* #f14d4c */
80
80
  --color-destructive-fg: oklch(0.96 0 0);
81
- --color-success: oklch(0.65 0.17 145);
81
+ /* The semantic trio is one family: same lightness and chroma as destructive,
82
+ * varying only in hue, so a success fill and a destructive fill carry the same
83
+ * weight — which is what makes the pane's traffic lights read as three lights
84
+ * rather than three unrelated colours.
85
+ *
86
+ * Green follows exactly (0.65 / 0.2). Yellow CANNOT, and this is a gamut wall
87
+ * rather than a preference: sRGB holds no dark saturated yellow. At the red's
88
+ * lightness, hue 85 caps at chroma 0.13 and renders #b3880f — brown, not
89
+ * yellow. So warning takes the deepest lightness that still reads yellow at its
90
+ * own ceiling (0.75 is the max chroma for that lightness), which closes most of
91
+ * the gap: measured against the page, the three now sit at 5.9 / 7.0 / 9.3
92
+ * where they sat at 5.9 / 7.0 / 11.1. */
93
+ --color-success: oklch(0.65 0.2 145);
82
94
  --color-success-fg: oklch(0.96 0 0);
83
- --color-warning: oklch(0.8 0.16 85);
95
+ --color-warning: oklch(0.75 0.15 85);
84
96
  --color-warning-fg: oklch(0.162 0 0);
85
97
  }
86
98
 
@@ -117,7 +129,10 @@
117
129
  --color-primary-hover: color-mix(in oklch, var(--color-primary) 85%, black);
118
130
  --color-destructive: oklch(0.65 0.2 25); /* #f14d4c */
119
131
  --color-destructive-fg: oklch(0.98 0 0);
120
- --color-success: oklch(0.5 0.17 145);
132
+ /* Chroma matched to destructive like the dark theme; the LIGHTNESSES stay
133
+ * where they are, because here they carry white text — green at the red's
134
+ * 0.65 drops to 2.99:1 against white, under the 3:1 a filled glyph needs. */
135
+ --color-success: oklch(0.5 0.2 145);
121
136
  --color-success-fg: oklch(0.98 0 0);
122
137
  --color-warning: oklch(0.72 0.15 85);
123
138
  --color-warning-fg: oklch(0.162 0 0);
@@ -39,11 +39,11 @@
39
39
  compoundVariants: [
40
40
  // md ⊃ xxs = (3sp − sp − 10)/2 — the named token.
41
41
  { size: 'md', content: 'xxs', class: 'gap-(--era-xxs-inset-md) px-(--era-xxs-inset-md)' },
42
- // sm ⊃ xxs = (2sp + 6 sp 10)/2 = (sp 4)/2, which is ALSO (h-xxs − text)/2
43
- // at 14px text — the same number --era-inset-xxs already carries, so the
44
- // identity is reused rather than a fifth token invented. (lg ⊃ xxs has no
42
+ // sm ⊃ xxs its own token, not the text inset it used to borrow. The two
43
+ // were the same number only while type was 14px at every density; dense's
44
+ // 12px broke the tie and left this pairing a pixel wide. (lg ⊃ xxs has no
45
45
  // token because nothing pairs a page header with pill-tier controls.)
46
- { size: 'sm', content: 'xxs', class: 'gap-(--era-inset-xxs) px-(--era-inset-xxs)' }
46
+ { size: 'sm', content: 'xxs', class: 'gap-(--era-xxs-inset-sm) px-(--era-xxs-inset-sm)' }
47
47
  ],
48
48
  defaultVariants: { size: 'lg', content: 'tier' }
49
49
  });
@@ -68,15 +68,24 @@
68
68
  Popover.Trigger, etc.) that open on pointerdown — otherwise dismissing
69
69
  a chip inside a trigger would also toggle the trigger.
70
70
  -->
71
+ <!-- The glyph steps up a sub-tier, icon-xs -> icon-xxs (10 -> 12px at dense),
72
+ the same exception Pane.Close takes and for the same reason: a dismiss is
73
+ a control you have to hit, and half of a Lucide glyph's box is padding
74
+ inside its own viewBox, so icon-xs drew a 5px × in a 14px button. 12
75
+ leaves a 1px inset on the BOX while the ink gains a fifth of its size.
76
+ It has to be written as [&_svg]: because that is the selector Button's
77
+ icon variant uses — the bare size-* that sat on the <X> lost to it and
78
+ had no effect at all. -->
71
79
  <Button
72
80
  icon
73
81
  size="icon"
74
82
  tone="destructive"
83
+ class="[&_svg]:size-(--era-icon-xxs)"
75
84
  onclick={ondismiss}
76
85
  onpointerdown={(e: PointerEvent) => e.stopPropagation()}
77
86
  onpointerup={(e: PointerEvent) => e.stopPropagation()}
78
87
  >
79
- <X class="size-(--era-h-xs)" />
88
+ <X />
80
89
  </Button>
81
90
  {/if}
82
91
  </div>
@@ -15,8 +15,16 @@
15
15
  <ContextMenu.Content
16
16
  bind:ref
17
17
  align="start"
18
+ // p-gutter, not p-(--era-panel-inset): the inset is SURFACE-owned and resolves
19
+ // to 0 on flat, so a menu there sat its rows flush against its own edges —
20
+ // the highlight ran edge to edge and the panel read as a list with no frame.
21
+ // The gutter is --era-gap, the same distance that separates the rows from
22
+ // each other, so a row sits an even gap from every edge (the pattern the
23
+ // conversations rail already documents). It is >= the panel inset at every
24
+ // density, so glass and bevel keep the frame protection the inset exists
25
+ // for.
18
26
  class={cn(
19
- 'z-50 w-max overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-(--era-panel-inset) shadow-(--era-shadow-lg) glass-blur',
27
+ 'z-50 w-max overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-gutter shadow-(--era-shadow-lg) glass-blur',
20
28
  className
21
29
  )}
22
30
  {sideOffset}
@@ -13,7 +13,7 @@
13
13
  <ContextMenu.Item
14
14
  bind:ref
15
15
  class={cn(
16
- 'flex h-(--era-h-md) cursor-pointer items-center rounded-(--era-item-rd) px-(--era-inset-md) text-body text-fg data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[highlighted]:bg-(--era-highlight) data-[highlighted]:shadow-(--era-highlight-shadow)',
16
+ 'flex h-(--era-h-md) cursor-pointer items-center gap-(--era-gap) rounded-(--era-item-rd) px-(--era-inset-md) text-body text-fg data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[highlighted]:bg-(--era-highlight) data-[highlighted]:shadow-(--era-highlight-shadow)',
17
17
  className
18
18
  )}
19
19
  {...restProps}
@@ -15,8 +15,16 @@
15
15
  <DropdownMenu.Content
16
16
  bind:ref
17
17
  align="start"
18
+ // p-gutter, not p-(--era-panel-inset): the inset is SURFACE-owned and resolves
19
+ // to 0 on flat, so a menu there sat its rows flush against its own edges —
20
+ // the highlight ran edge to edge and the panel read as a list with no frame.
21
+ // The gutter is --era-gap, the same distance that separates the rows from
22
+ // each other, so a row sits an even gap from every edge (the pattern the
23
+ // conversations rail already documents). It is >= the panel inset at every
24
+ // density, so glass and bevel keep the frame protection the inset exists
25
+ // for.
18
26
  class={cn(
19
- 'z-50 w-max min-w-(--bits-dropdown-menu-anchor-width) overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-(--era-panel-inset) shadow-(--era-shadow-lg) glass-blur data-[side=bottom]:rounded-t-none data-[side=top]:rounded-b-none',
27
+ 'z-50 w-max min-w-(--bits-dropdown-menu-anchor-width) overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-gutter shadow-(--era-shadow-lg) glass-blur data-[side=bottom]:rounded-t-none data-[side=top]:rounded-b-none',
20
28
  className
21
29
  )}
22
30
  {sideOffset}
@@ -13,7 +13,7 @@
13
13
  <DropdownMenu.Item
14
14
  bind:ref
15
15
  class={cn(
16
- 'flex h-(--era-h-md) cursor-pointer items-center rounded-(--era-item-rd) px-(--era-inset-md) text-body text-fg data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[highlighted]:bg-(--era-highlight) data-[highlighted]:shadow-(--era-highlight-shadow)',
16
+ 'flex h-(--era-h-md) cursor-pointer items-center gap-(--era-gap) rounded-(--era-item-rd) px-(--era-inset-md) text-body text-fg data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[highlighted]:bg-(--era-highlight) data-[highlighted]:shadow-(--era-highlight-shadow)',
17
17
  className
18
18
  )}
19
19
  {...restProps}
@@ -15,8 +15,16 @@
15
15
  <Menubar.Content
16
16
  bind:ref
17
17
  align="start"
18
+ // p-gutter, not p-(--era-panel-inset): the inset is SURFACE-owned and resolves
19
+ // to 0 on flat, so a menu there sat its rows flush against its own edges —
20
+ // the highlight ran edge to edge and the panel read as a list with no frame.
21
+ // The gutter is --era-gap, the same distance that separates the rows from
22
+ // each other, so a row sits an even gap from every edge (the pattern the
23
+ // conversations rail already documents). It is >= the panel inset at every
24
+ // density, so glass and bevel keep the frame protection the inset exists
25
+ // for.
18
26
  class={cn(
19
- 'z-50 w-max min-w-(--bits-menubar-menu-anchor-width) overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-(--era-panel-inset) shadow-(--era-shadow-lg) glass-blur data-[side=bottom]:rounded-t-none data-[side=top]:rounded-b-none',
27
+ 'z-50 w-max min-w-(--bits-menubar-menu-anchor-width) overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-gutter shadow-(--era-shadow-lg) glass-blur data-[side=bottom]:rounded-t-none data-[side=top]:rounded-b-none',
20
28
  className
21
29
  )}
22
30
  {sideOffset}
@@ -13,7 +13,7 @@
13
13
  <Menubar.Item
14
14
  bind:ref
15
15
  class={cn(
16
- 'flex h-(--era-h-md) cursor-pointer items-center rounded-(--era-item-rd) px-(--era-inset-md) text-body text-fg data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[highlighted]:bg-(--era-highlight) data-[highlighted]:shadow-(--era-highlight-shadow)',
16
+ 'flex h-(--era-h-md) cursor-pointer items-center gap-(--era-gap) rounded-(--era-item-rd) px-(--era-inset-md) text-body text-fg data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[highlighted]:bg-(--era-highlight) data-[highlighted]:shadow-(--era-highlight-shadow)',
17
17
  className
18
18
  )}
19
19
  {...restProps}
@@ -14,8 +14,16 @@
14
14
  <Select.Content
15
15
  bind:ref
16
16
  align="start"
17
+ // p-gutter, not p-(--era-panel-inset): the inset is SURFACE-owned and resolves
18
+ // to 0 on flat, so a menu there sat its rows flush against its own edges —
19
+ // the highlight ran edge to edge and the panel read as a list with no frame.
20
+ // The gutter is --era-gap, the same distance that separates the rows from
21
+ // each other, so a row sits an even gap from every edge (the pattern the
22
+ // conversations rail already documents). It is >= the panel inset at every
23
+ // density, so glass and bevel keep the frame protection the inset exists
24
+ // for.
17
25
  class={cn(
18
- 'z-50 w-max min-w-(--bits-select-anchor-width) overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-(--era-panel-inset) shadow-(--era-shadow-lg) glass-blur data-[side=bottom]:rounded-t-none data-[side=top]:rounded-b-none',
26
+ 'z-50 w-max min-w-(--bits-select-anchor-width) overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-gutter shadow-(--era-shadow-lg) glass-blur data-[side=bottom]:rounded-t-none data-[side=top]:rounded-b-none',
19
27
  className
20
28
  )}
21
29
  {sideOffset}
@@ -10,7 +10,7 @@
10
10
  <Select.Item
11
11
  bind:ref
12
12
  class={cn(
13
- 'flex h-(--era-h-md) cursor-pointer items-center rounded-(--era-item-rd) px-(--era-inset-md) text-body text-fg data-[highlighted]:bg-(--era-highlight) data-[highlighted]:shadow-(--era-highlight-shadow)',
13
+ 'flex h-(--era-h-md) cursor-pointer items-center gap-(--era-gap) rounded-(--era-item-rd) px-(--era-inset-md) text-body text-fg data-[highlighted]:bg-(--era-highlight) data-[highlighted]:shadow-(--era-highlight-shadow)',
14
14
  className
15
15
  )}
16
16
  {...restProps}
@@ -1244,11 +1244,11 @@
1244
1244
  <ContextMenu.Content onOpenAutoFocus={(e: Event) => e.preventDefault()}>
1245
1245
  <ContextMenu.Item onSelect={togglePlay}>
1246
1246
  {#if ended}
1247
- <RotateCcw class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1247
+ <RotateCcw class="size-(--era-h-xs)" aria-hidden="true" />
1248
1248
  {:else if paused}
1249
- <Play class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1249
+ <Play class="size-(--era-h-xs)" aria-hidden="true" />
1250
1250
  {:else}
1251
- <Pause class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1251
+ <Pause class="size-(--era-h-xs)" aria-hidden="true" />
1252
1252
  {/if}
1253
1253
  <span>{playLabel}</span>
1254
1254
  </ContextMenu.Item>
@@ -1256,11 +1256,11 @@
1256
1256
  {#if showVolume && !mobileMode}
1257
1257
  <ContextMenu.Item onSelect={(e: Event) => remote.toggleMuted(e)}>
1258
1258
  {#if mutedState || volumeState === 0}
1259
- <VolumeX class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1259
+ <VolumeX class="size-(--era-h-xs)" aria-hidden="true" />
1260
1260
  {:else if volumeState < 0.5}
1261
- <Volume1 class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1261
+ <Volume1 class="size-(--era-h-xs)" aria-hidden="true" />
1262
1262
  {:else}
1263
- <Volume2 class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1263
+ <Volume2 class="size-(--era-h-xs)" aria-hidden="true" />
1264
1264
  {/if}
1265
1265
  <span>{muteLabel}</span>
1266
1266
  </ContextMenu.Item>
@@ -1269,7 +1269,7 @@
1269
1269
  {#if showSpeed && !mobileMode}
1270
1270
  <ContextMenu.Sub>
1271
1271
  <ContextMenu.SubTrigger>
1272
- <Gauge class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1272
+ <Gauge class="size-(--era-h-xs)" aria-hidden="true" />
1273
1273
  <span class="flex-1">Speed</span>
1274
1274
  <span class="ml-auto pl-(--era-gap) text-muted">
1275
1275
  {rateState === 1 ? '1x' : `${rateState}x`}
@@ -1293,7 +1293,7 @@
1293
1293
  {#if showQualityMenu && !mobileMode}
1294
1294
  <ContextMenu.Sub>
1295
1295
  <ContextMenu.SubTrigger>
1296
- <Settings class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1296
+ <Settings class="size-(--era-h-xs)" aria-hidden="true" />
1297
1297
  <span class="flex-1">Quality</span>
1298
1298
  <span class="ml-auto pl-(--era-gap) text-muted">{qualityHint}</span>
1299
1299
  </ContextMenu.SubTrigger>
@@ -1314,9 +1314,9 @@
1314
1314
  {#if showPip && canEnterPip && !mobileMode}
1315
1315
  <ContextMenu.Item onSelect={(e: Event) => remote.togglePictureInPicture(e)}>
1316
1316
  {#if pipState}
1317
- <PictureInPicture2 class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1317
+ <PictureInPicture2 class="size-(--era-h-xs)" aria-hidden="true" />
1318
1318
  {:else}
1319
- <PictureInPicture class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1319
+ <PictureInPicture class="size-(--era-h-xs)" aria-hidden="true" />
1320
1320
  {/if}
1321
1321
  <span>{pipState ? 'Exit picture-in-picture' : 'Picture-in-picture'}</span>
1322
1322
  </ContextMenu.Item>
@@ -1325,9 +1325,9 @@
1325
1325
  {#if canEnterFullscreen}
1326
1326
  <ContextMenu.Item onSelect={(e: Event) => remote.toggleFullscreen(FULLSCREEN_TARGET, e)}>
1327
1327
  {#if fullscreenState}
1328
- <Minimize class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1328
+ <Minimize class="size-(--era-h-xs)" aria-hidden="true" />
1329
1329
  {:else}
1330
- <Maximize class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1330
+ <Maximize class="size-(--era-h-xs)" aria-hidden="true" />
1331
1331
  {/if}
1332
1332
  <span>{fullscreenState ? 'Exit fullscreen' : 'Fullscreen'}</span>
1333
1333
  </ContextMenu.Item>
@@ -1336,7 +1336,7 @@
1336
1336
  <ContextMenu.Separator />
1337
1337
 
1338
1338
  <ContextMenu.Item onSelect={downloadVideo}>
1339
- <Download class="mr-(--era-gap) size-(--era-h-xs)" aria-hidden="true" />
1339
+ <Download class="size-(--era-h-xs)" aria-hidden="true" />
1340
1340
  <span>Download video</span>
1341
1341
  </ContextMenu.Item>
1342
1342
  </ContextMenu.Content>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signal9/era-ui",
3
- "version": "4.11.1",
3
+ "version": "4.11.2",
4
4
  "scripts": {
5
5
  "dev": "vite dev --host",
6
6
  "build": "vite build && npm run prepack",