@human-synthesis/norns-ui 0.0.6 → 0.0.8

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@human-synthesis/norns-ui",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "UI library for the Norns ecosystem — Pug + Civet components on Tailwind v4.",
5
5
  "license": "MIT",
6
6
  "author": "Daniel Teodoroiu (https://humansynthesis.ai)",
@@ -55,6 +55,7 @@ export function presetUI() {
55
55
  // 0.0.4 — display layer
56
56
  Icon: c('Icon'),
57
57
  Card: c('Card'),
58
+ Window: c('Window'),
58
59
  Surface: c('Surface'),
59
60
  Banner: c('Banner'),
60
61
  Badge: c('Badge'),
@@ -0,0 +1,43 @@
1
+ .norns-window(class!="{classes}")
2
+ +if('!hideHeader')
3
+ header.norns-window-header
4
+ .norns-window-title.truncate {title}
5
+ .norns-window-actions
6
+ +if('actions')
7
+ | {@render actions()}
8
+ +if('onClose')
9
+ button.norns-window-close(type="button" aria-label="Close" onclick!="{onClose}")
10
+ | ✕
11
+ section.norns-window-body(class!="{bodyClasses}")
12
+ | {@render children?.()}
13
+
14
+ <script>
15
+ import { cn } from '@human-synthesis/norns-ui/cn'
16
+
17
+ // Layout-only window: chrome (header + close + custom actions) wrapping
18
+ // a body slot. Sizing is the caller's responsibility — pass dimensions
19
+ // via `class` (e.g. `class="w-[520px] h-[380px]"`) or compose inside a
20
+ // parent that constrains the box (a SvelteFlow node, a fixed panel,
21
+ // a flex child, etc).
22
+ //
23
+ // Header layout: title on the left (truncated), then a flex row of
24
+ // caller-provided action elements (via the `actions` snippet), then an
25
+ // optional `✕` close button when `onClose` is supplied. The close button
26
+ // is rendered after the snippet so the snippet can position icons / chips
27
+ // alongside it.
28
+ //
29
+ // `hideHeader` removes the entire header bar (useful for windows that
30
+ // already have their own custom chrome but still want the rounded shell).
31
+ {
32
+ title = ''
33
+ hideHeader = false
34
+ onClose
35
+ actions
36
+ children
37
+ class: extra = ''
38
+ bodyClass = ''
39
+ } := $props()
40
+
41
+ classes := cn 'norns-window', extra
42
+ bodyClasses := cn 'norns-window-body', bodyClass
43
+ </script>
@@ -32,11 +32,16 @@
32
32
  background-color: var(--color-bg);
33
33
  }
34
34
 
35
+ /* Respect prefers-reduced-motion without nuking decorative animations
36
+ * entirely: cap iterations to 1 (so infinite loops like the shiny
37
+ * sweep, sparkle, gradient shift play once and stop instead of
38
+ * looping), and shrink incidental transitions. Finite animations
39
+ * (ripple, copy-pop, toast-in, banner-in) keep their natural duration
40
+ * so users still see the state change they signal. */
35
41
  @media (prefers-reduced-motion: reduce) {
36
42
  *,
37
43
  *::before,
38
44
  *::after {
39
- animation-duration: 0.01ms !important;
40
45
  animation-iteration-count: 1 !important;
41
46
  transition-duration: 0.01ms !important;
42
47
  scroll-behavior: auto !important;
@@ -647,6 +652,70 @@
647
652
  box-shadow: var(--ui-focus-ring);
648
653
  }
649
654
 
655
+ /* ============================================================ */
656
+ /* Window */
657
+ /* ============================================================ */
658
+ .norns-window {
659
+ display: flex;
660
+ flex-direction: column;
661
+ background-color: var(--color-bg-elevated);
662
+ color: var(--color-fg);
663
+ border: 1px solid var(--color-border);
664
+ border-radius: var(--ui-radius-lg);
665
+ overflow: hidden;
666
+ box-shadow: var(--ui-elev-1, 0 1px 2px rgb(0 0 0 / 0.04));
667
+ }
668
+ .norns-window-header {
669
+ flex-shrink: 0;
670
+ display: flex;
671
+ align-items: center;
672
+ justify-content: space-between;
673
+ gap: 0.5rem;
674
+ padding: 0.4rem 0.625rem;
675
+ border-bottom: 1px solid var(--color-border);
676
+ background-color: var(--color-bg-subtle);
677
+ user-select: none;
678
+ cursor: move;
679
+ }
680
+ .norns-window-title {
681
+ flex: 1;
682
+ min-width: 0;
683
+ font-size: 0.85rem;
684
+ font-weight: 600;
685
+ color: var(--color-fg);
686
+ }
687
+ .norns-window-actions {
688
+ display: flex;
689
+ align-items: center;
690
+ gap: 0.25rem;
691
+ flex-shrink: 0;
692
+ }
693
+ .norns-window-close {
694
+ display: inline-flex;
695
+ align-items: center;
696
+ justify-content: center;
697
+ width: 1.25rem;
698
+ height: 1.25rem;
699
+ border-radius: var(--ui-radius-sm);
700
+ background: transparent;
701
+ color: var(--color-fg-muted);
702
+ border: 0;
703
+ cursor: pointer;
704
+ font-size: 0.85rem;
705
+ line-height: 1;
706
+ padding: 0;
707
+ }
708
+ .norns-window-close:hover {
709
+ background: var(--color-bg-muted);
710
+ color: var(--color-fg);
711
+ }
712
+ .norns-window-body {
713
+ flex: 1;
714
+ min-height: 0;
715
+ overflow: auto;
716
+ background-color: var(--color-bg);
717
+ }
718
+
650
719
  /* ============================================================ */
651
720
  /* Banner */
652
721
  /* ============================================================ */