@stnd/lab 1.6.1 → 1.7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @stnd/lab
2
2
 
3
+ ## 1.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Auto-bumped @stnd/lab due to modified code.
8
+
3
9
  ## 1.6.1
4
10
 
5
11
  ### Patch Changes
package/Lab.svelte CHANGED
@@ -24,7 +24,7 @@
24
24
  } from "./color.js";
25
25
 
26
26
  // Sidebar transition parameters (defaults)
27
- let sidebarDuration = $state(2000); // milliseconds
27
+ let sidebarDuration = $state(220); // milliseconds
28
28
  let customEasing = $state(bezier(0.22, 1, 0.36, 1));
29
29
 
30
30
  // =========================================================================
@@ -157,12 +157,27 @@
157
157
  }
158
158
  }
159
159
 
160
+ let openTimer;
161
+
160
162
  function openLab() {
161
163
  clearTimeout(closeTimer);
164
+ clearTimeout(openTimer);
162
165
  view = "open";
163
166
  }
164
167
 
168
+ function hoverOpenLab() {
169
+ if (typeof window !== "undefined" && !window.matchMedia("(hover: hover) and (pointer: fine)").matches) {
170
+ return;
171
+ }
172
+ clearTimeout(closeTimer);
173
+ clearTimeout(openTimer);
174
+ openTimer = setTimeout(() => {
175
+ view = "open";
176
+ }, 120);
177
+ }
178
+
165
179
  function requestCloseLab() {
180
+ clearTimeout(openTimer);
166
181
  if (pinned || activePicker || isDraggingPlane) return;
167
182
  // Keep open if user is interacting with inputs or popovers inside
168
183
  if (
@@ -177,13 +192,29 @@
177
192
  clearTimeout(closeTimer);
178
193
  closeTimer = setTimeout(() => {
179
194
  view = "dormant";
180
- }, 100);
195
+ }, 280);
181
196
  }
182
197
 
183
198
  function cancelCloseLab() {
199
+ clearTimeout(openTimer);
184
200
  clearTimeout(closeTimer);
185
201
  }
186
202
 
203
+ function togglePinned() {
204
+ pinned = !pinned;
205
+ try {
206
+ sessionStorage.setItem("stnd-pinned", String(pinned));
207
+ } catch {}
208
+ }
209
+
210
+ function collapseLab() {
211
+ pinned = false;
212
+ try {
213
+ sessionStorage.setItem("stnd-pinned", "false");
214
+ } catch {}
215
+ view = "dormant";
216
+ }
217
+
187
218
  let modified = $state(new Set());
188
219
  let version = $state("");
189
220
  let viewportW = $state(0);
@@ -764,6 +795,23 @@
764
795
  // Keyboard shortcuts
765
796
  function onKey(e) {
766
797
  const mod = navigator.platform.includes("Mac") ? e.metaKey : e.ctrlKey;
798
+ const el = document.activeElement;
799
+ const typing =
800
+ !!el && (["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName) || el.isContentEditable);
801
+
802
+ // Right-sidebar shortcut `]` when not typing
803
+ if (!typing && !e.metaKey && !e.ctrlKey && !e.altKey && e.key === "]") {
804
+ e.preventDefault();
805
+ if (view === "dormant") {
806
+ view = "open";
807
+ pinned = true;
808
+ } else if (!pinned) {
809
+ pinned = true;
810
+ } else {
811
+ collapseLab();
812
+ }
813
+ return;
814
+ }
767
815
 
768
816
  // Toggle lab with Cmd/Ctrl+S (override default save shortcut)
769
817
  if (mod && !e.shiftKey && e.key.toLowerCase() === "s") {
@@ -811,6 +859,7 @@
811
859
  if (view !== "open" || pinned) return;
812
860
  if (sidebarEl && e.composedPath().includes(sidebarEl)) return;
813
861
  if (
862
+ e.target.closest?.(".lab-open-btn") ||
814
863
  e.target.closest?.(".lab-handler") ||
815
864
  e.target.closest?.(".lab-handler-top")
816
865
  )
@@ -856,13 +905,12 @@
856
905
  // EFFECTS
857
906
  // =========================================================================
858
907
 
859
- // Persist panel state + dispatch event for dev toolbar
860
- // Shrink the page when the sidebar is open (like DevTools)
908
+ // Shrink the page only when the Lab is pinned open on wide screens
861
909
  $effect(() => {
862
910
  if (duplicate) return;
863
911
  if (typeof document === "undefined") return;
864
912
  const el = document.documentElement;
865
- if (view === "open") {
913
+ if (view === "open" && pinned) {
866
914
  el.classList.add("lab-open");
867
915
  } else {
868
916
  el.classList.remove("lab-open");
@@ -1223,61 +1271,81 @@
1223
1271
 
1224
1272
  {#if !duplicate}
1225
1273
  <!-- ======================================================================
1226
- TRIGGER / HANDLER
1274
+ TOP-RIGHT STICKY FLASK TRIGGER (Right Sidebar Minimized Mode)
1227
1275
  ====================================================================== -->
1228
- {#if handlerVisible}
1229
- <div
1230
- class="lab-handler-top m-0"
1231
- role="button"
1232
- tabindex="0"
1233
- aria-label="Open Design Lab"
1234
- onmouseenter={openLab}
1235
- onmouseleave={requestCloseLab}
1236
- onclick={() => (view = view === "dormant" ? "open" : "dormant")}
1237
- onkeydown={(e) => e.key === "Enter" && (view = "open")}
1238
- >
1239
- <div class="lab-dot"></div>
1240
- </div>
1241
-
1242
- <div
1243
- class="lab-handler m-0"
1244
- class:scrolling={isScrolling}
1276
+ {#if handlerVisible && view === "dormant"}
1277
+ <button
1278
+ type="button"
1279
+ class="item lab-open-btn m-0"
1245
1280
  class:modified={modCount > 0}
1246
- onmouseenter={openLab}
1247
- onmouseleave={requestCloseLab}
1248
- role="button"
1249
- tabindex="0"
1250
1281
  aria-label="Open Design Lab"
1251
- onclick={() => (view = view === "dormant" ? "open" : "dormant")}
1252
- onkeydown={(e) => e.key === "Enter" && (view = "open")}
1282
+ title="Open Design Lab ( ] )"
1283
+ onpointerenter={hoverOpenLab}
1284
+ onpointerleave={requestCloseLab}
1285
+ onclick={() => {
1286
+ clearTimeout(openTimer);
1287
+ view = "open";
1288
+ pinned = true;
1289
+ try {
1290
+ sessionStorage.setItem("stnd-pinned", "true");
1291
+ } catch {}
1292
+ }}
1253
1293
  >
1254
- <div class="lab-handler-bar"></div>
1255
- </div>
1294
+ <svg
1295
+ xmlns="http://www.w3.org/2000/svg"
1296
+ width="1.25em"
1297
+ height="1.25em"
1298
+ viewBox="0 0 256 256"
1299
+ fill="currentColor"
1300
+ aria-hidden="true"
1301
+ >
1302
+ <path
1303
+ d="M221.6,199.77,160,96.92V40h8a8,8,0,0,0,0-16H88a8,8,0,0,0,0,16h8V96.92L34.4,199.77A16,16,0,0,0,48.13,224H207.87a16,16,0,0,0,13.73-24.23ZM110.86,103.25A7.93,7.93,0,0,0,112,99.14V40h32V99.14a7.93,7.93,0,0,0,1.14,4.11L183.36,167c-12.19,2.31-26.07-.37-41.19-8.19-19-9.82-35.87-12.48-50.25-8.23ZM48.13,208l24.51-40.91c11.79-4.76,25.75-2.66,43.1,6.31,15.65,8.09,30.12,11.66,43.18,10.67a63.36,63.36,0,0,0,15.46-3L207.87,208Z"
1304
+ />
1305
+ </svg>
1306
+ {#if modCount > 0}
1307
+ <span class="lab-mod-dot" title="{modCount} active override(s)"></span>
1308
+ {/if}
1309
+ </button>
1256
1310
  {/if}
1257
1311
 
1258
1312
  <!-- ======================================================================
1259
- SIDE PANEL
1313
+ RIGHT SIDEBAR PANE
1260
1314
  ====================================================================== -->
1261
1315
  {#if view === "open"}
1262
1316
  <div
1263
1317
  bind:this={sidebarEl}
1264
1318
  transition:fly={{
1265
- x: 320,
1319
+ x: 340,
1266
1320
  duration: sidebarDuration,
1267
1321
  easing: customEasing,
1268
1322
  opacity: false,
1269
1323
  }}
1270
- class="lab-sidebar no-rhythm mt-0"
1324
+ class="pane lab-sidebar no-rhythm mt-0"
1325
+ data-pinned={pinned ? "" : undefined}
1271
1326
  role="dialog"
1272
1327
  tabindex="-1"
1273
1328
  aria-label="Design Lab"
1274
- onmouseenter={cancelCloseLab}
1275
- onmouseleave={requestCloseLab}
1329
+ onpointerenter={cancelCloseLab}
1330
+ onpointerleave={requestCloseLab}
1276
1331
  >
1277
1332
  <!-- ═══════════ HEADER ═══════════ -->
1278
1333
  <header class="lab-header">
1279
1334
  <div class="lab-header-title">
1280
- <h2>stnd</h2>
1335
+ <svg
1336
+ xmlns="http://www.w3.org/2000/svg"
1337
+ width="1.15em"
1338
+ height="1.15em"
1339
+ viewBox="0 0 256 256"
1340
+ fill="currentColor"
1341
+ class="lab-flask-mark"
1342
+ aria-hidden="true"
1343
+ >
1344
+ <path
1345
+ d="M221.6,199.77,160,96.92V40h8a8,8,0,0,0,0-16H88a8,8,0,0,0,0,16h8V96.92L34.4,199.77A16,16,0,0,0,48.13,224H207.87a16,16,0,0,0,13.73-24.23ZM110.86,103.25A7.93,7.93,0,0,0,112,99.14V40h32V99.14a7.93,7.93,0,0,0,1.14,4.11L183.36,167c-12.19,2.31-26.07-.37-41.19-8.19-19-9.82-35.87-12.48-50.25-8.23ZM48.13,208l24.51-40.91c11.79-4.76,25.75-2.66,43.1,6.31,15.65,8.09,30.12,11.66,43.18,10.67a63.36,63.36,0,0,0,15.46-3L207.87,208Z"
1346
+ />
1347
+ </svg>
1348
+ <h2>stnd lab</h2>
1281
1349
  {#if version}<span class="lab-version">v{version}</span>{/if}
1282
1350
  </div>
1283
1351
  <div class="lab-header-meta">
@@ -1300,16 +1368,17 @@
1300
1368
 
1301
1369
  <button
1302
1370
  class="smaller icon ghost"
1303
- onclick={() => (pinned = !pinned)}
1304
- aria-label={pinned ? "Unpin Lab" : "Pin Lab"}
1305
- title={pinned ? "Unpin Lab" : "Pin Lab"}
1371
+ onclick={togglePinned}
1372
+ aria-label={pinned ? "Unpin Lab (hover peek mode)" : "Pin Lab open"}
1373
+ title={pinned ? "Pinned open — click to switch to hover peek" : "Hover peek — click to pin open"}
1306
1374
  >
1307
1375
  {pinned ? "●" : "○"}
1308
1376
  </button>
1309
1377
  <button
1310
1378
  class="smaller icon ghost"
1311
- onclick={() => (view = "dormant")}
1312
- aria-label="Close Lab"
1379
+ onclick={collapseLab}
1380
+ aria-label="Minimize Lab to top-right icon"
1381
+ title="Collapse Lab ( ] )"
1313
1382
  >
1314
1383
  ✕
1315
1384
  </button>
@@ -1877,10 +1946,12 @@
1877
1946
  STYLES — Fully scoped, isolated from design tokens
1878
1947
  ====================================================================== -->
1879
1948
  <style>
1880
- /* ═══════════ PAGE SHRINK (like DevTools) ═══════════ */
1881
- :global(html.lab-open) {
1882
- margin-right: var(--lab-sidebar-w, 320px);
1883
- transition: margin-right var(--transition);
1949
+ /* ═══════════ PAGE SHRINK (only when pinned on wide screens) ═══════════ */
1950
+ @media (min-width: 1025px) {
1951
+ :global(html.lab-open) {
1952
+ margin-right: calc(var(--lab-sidebar-w, 304px) + var(--window-inset, 8px) * 2);
1953
+ transition: margin-right var(--transition);
1954
+ }
1884
1955
  }
1885
1956
  :global(html:not(.lab-open)) {
1886
1957
  transition: margin-right var(--transition);
@@ -1889,89 +1960,82 @@
1889
1960
  /* ═══════════ DESIGN CONSTANTS ═══════════ */
1890
1961
  :root {
1891
1962
  --lab-font-size: 12px;
1892
- --lab-sidebar-w: 320px;
1963
+ --lab-sidebar-w: 304px;
1893
1964
  }
1894
1965
 
1895
- /* ═══════════ HANDLER TRIGGER ═══════════ */
1896
- :global(:root[data-lab-handler="false"]) .lab-handler,
1897
- :global(:root[data-lab-handler="false"]) .lab-handler-top,
1898
- :global(:root[data-lab-no-handler]) .lab-handler,
1899
- :global(:root[data-lab-no-handler]) .lab-handler-top {
1966
+ /* ═══════════ TOP-RIGHT STICKY FLASK TRIGGER ═══════════ */
1967
+ :global(:root[data-lab-handler="false"]) .lab-open-btn,
1968
+ :global(:root[data-lab-no-handler]) .lab-open-btn {
1900
1969
  display: none !important;
1901
1970
  pointer-events: none !important;
1902
1971
  }
1903
1972
 
1904
- .lab-handler-top {
1905
- position: fixed;
1906
- z-index: 200;
1907
- top: 0;
1908
- right: 0;
1909
- padding: var(--space-2);
1910
- cursor: pointer;
1911
- opacity: 0.1;
1912
- transition: opacity var(--transition);
1913
- display: none;
1914
- }
1915
- .lab-handler-top:hover {
1916
- opacity: 1;
1917
- }
1918
- .lab-dot {
1919
- width: var(--space-d4);
1920
- height: var(--space-d4);
1921
- background: var(--color-foreground);
1922
- border-radius: 50%;
1923
- }
1924
-
1925
- .lab-handler {
1973
+ .lab-open-btn {
1926
1974
  position: fixed;
1927
- z-index: 200;
1928
- top: 20%;
1929
- right: 0;
1930
- padding: var(--space); /* Bigger hit area */
1931
- padding-right: 20px;
1932
- cursor: normal;
1933
- display: flex;
1934
- flex-direction: row;
1975
+ z-index: 9991;
1976
+ top: calc(var(--window-inset, 8px) + env(safe-area-inset-top, 0px));
1977
+ right: calc(var(--window-inset, 8px) + env(safe-area-inset-right, 0px));
1978
+ display: inline-flex;
1935
1979
  align-items: center;
1936
- transition: all var(--transition);
1980
+ justify-content: center;
1981
+ width: calc(var(--space) * 1.5);
1982
+ height: calc(var(--space) * 1.5);
1983
+ padding: 0;
1984
+ border: none;
1985
+ border-radius: var(--radius-sm);
1986
+ background: var(--color-surface-raised);
1987
+ color: var(--color-muted);
1988
+ box-shadow: var(--shadow), var(--pane-edge);
1989
+ cursor: pointer;
1990
+ transition:
1991
+ color var(--transition-fast),
1992
+ background var(--transition-fast),
1993
+ transform var(--transition-fast),
1994
+ box-shadow var(--transition-fast);
1937
1995
  }
1938
- .lab-handler.scrolling .lab-handler-bar {
1939
- background: oklch(from var(--color-foreground) l c h / 0.3);
1996
+ .lab-open-btn:hover {
1997
+ color: var(--color-foreground);
1998
+ background: var(--color-surface-overlay);
1999
+ box-shadow: var(--shadow-lg), var(--pane-edge);
1940
2000
  }
1941
- .lab-handler-bar {
1942
- width: var(--space-d4);
1943
- height: var(--space-2);
1944
- background: oklch(from var(--color-foreground) l c h / 0);
1945
- border-radius: var(--radius);
1946
- box-shadow: var(--shadow-inset) var(--shadow-ring);
1947
- transition: all var(--transition);
1948
- cursor: normal;
1949
- backdrop-filter: var(--filter-glass);
2001
+ .lab-open-btn.modified {
2002
+ color: var(--color-accent);
1950
2003
  }
1951
- .lab-handler.modified .lab-handler-bar {
1952
- background: oklch(from var(--color-accent) l c h / 0.1);
2004
+ .lab-mod-dot {
2005
+ position: absolute;
2006
+ top: 4px;
2007
+ right: 4px;
2008
+ width: 6px;
2009
+ height: 6px;
2010
+ border-radius: 50%;
2011
+ background: var(--color-accent);
1953
2012
  }
1954
2013
 
1955
- /* ═══════════ SIDEBAR ═══════════ */
2014
+ /* ═══════════ RIGHT SIDEBAR PANE (Reveal Dev Panel geometry) ═══════════ */
1956
2015
  .lab-sidebar {
1957
2016
  position: fixed;
1958
2017
  z-index: 9992;
1959
- top: 0;
1960
- right: 0;
2018
+ top: calc(var(--window-inset, 8px) + env(safe-area-inset-top, 0px));
2019
+ right: calc(var(--window-inset, 8px) + env(safe-area-inset-right, 0px));
1961
2020
  width: var(--lab-sidebar-w);
1962
- height: 100dvh;
2021
+ height: calc(
2022
+ 100dvh - 2 * var(--window-inset, 8px) - env(safe-area-inset-top, 0px) -
2023
+ env(safe-area-inset-bottom, 0px)
2024
+ );
2025
+ margin: 0;
2026
+ padding: 0;
1963
2027
 
1964
2028
  color: var(--color-foreground);
1965
2029
  font: var(--lab-font-size) / 1.5 var(--font-monospace);
1966
- border-left: var(--border);
2030
+ border-radius: var(--pane-radius, 9px);
1967
2031
  display: flex;
1968
2032
  flex-direction: column;
1969
- box-shadow: var(--shadow-ring), var(--shadow-glow);
1970
- background: var(--color-surface);
1971
- backdrop-filter: var(--filter-blur);
2033
+ box-shadow: var(--shadow-overlay), var(--pane-edge);
2034
+ background: var(--color-surface-raised);
2035
+ backdrop-filter: var(--filter-glass);
2036
+ overflow: hidden;
1972
2037
  /* Ensure the sidebar stays fully opaque and never animates opacity */
1973
2038
  opacity: 1 !important;
1974
- /* Explicitly disable opacity animation while preserving other transitions */
1975
2039
  transition:
1976
2040
  transform var(--transition),
1977
2041
  box-shadow var(--transition),
@@ -1986,8 +2050,6 @@
1986
2050
  /* Reset children to Lab font, allowing explicit font-family previews to win */
1987
2051
  .lab-sidebar * {
1988
2052
  box-sizing: border-box;
1989
- /* Disable opacity transitions on child elements to prevent fading when opening the lab.
1990
- Other property transitions for children remain allowed outside of opacity. */
1991
2053
  transition: opacity 0s !important;
1992
2054
  }
1993
2055
  .lab-sidebar *:not([style*="font-family"]) {
@@ -2000,19 +2062,22 @@
2000
2062
  flex-wrap: wrap;
2001
2063
  align-items: center;
2002
2064
  gap: 0;
2003
- padding: var(--space-d6) var(--space-d2);
2065
+ padding: var(--space-d4) var(--space-d2);
2004
2066
  border-bottom: var(--border);
2005
2067
  flex-shrink: 0;
2006
-
2007
2068
  background: var(--color-surface-raised);
2008
2069
  }
2009
2070
  .lab-header-title {
2010
2071
  display: flex;
2011
2072
  align-items: center;
2012
- gap: 0px;
2073
+ gap: var(--space-d5);
2013
2074
  flex: 1;
2014
2075
  min-width: 0;
2015
2076
  }
2077
+ .lab-flask-mark {
2078
+ color: var(--color-accent);
2079
+ flex-shrink: 0;
2080
+ }
2016
2081
  .lab-header h2 {
2017
2082
  font-size: var(--scale-d2) !important;
2018
2083
  line-height: 1 !important;
@@ -2371,11 +2436,15 @@
2371
2436
  /* ═══════════ RESPONSIVE ═══════════ */
2372
2437
  @media (max-width: 480px) {
2373
2438
  .lab-sidebar {
2439
+ top: 0;
2440
+ right: 0;
2374
2441
  width: 100vw;
2442
+ height: 100dvh;
2443
+ border-radius: 0;
2375
2444
  }
2376
2445
  }
2377
2446
  @media print {
2378
- .lab-handler,
2447
+ .lab-open-btn,
2379
2448
  .lab-sidebar {
2380
2449
  display: none !important;
2381
2450
  }
package/README.md CHANGED
@@ -14,7 +14,7 @@ status: active
14
14
  tags:
15
15
  - package
16
16
  - stnd
17
- theme: kernel
17
+ theme: maker
18
18
  type: package
19
19
  visibility: public
20
20
  garden-url: https://standard.garden/@francis/readme
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stnd/lab",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "type": "module",
5
5
  "svelte": "./Lab.svelte",
6
6
  "author": "Francis Fontaine",