@deadragdoll/reactnu 0.1.52 → 0.1.56

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/dist/styles.css CHANGED
@@ -51,6 +51,7 @@
51
51
  --nu-window-shadow-offset-x: 1ch;
52
52
  --nu-window-shadow-offset-y: 1em;
53
53
  --nu-window-title-controls-width: 7.8ch;
54
+ --nu-window-title-icon-width: 1em;
54
55
  --nu-window-title-height: calc(1em + 3px);
55
56
  --nu-window-status-height: 1.35rem;
56
57
  --nu-window-inactive-overlay: rgba(0, 0, 0, 0.22);
@@ -1092,7 +1093,7 @@
1092
1093
  padding: 0 0.65rem;
1093
1094
  }
1094
1095
  .nu-main-menu__item--submenu .nu-main-menu__item-button {
1095
- grid-template-columns: 1.1rem 1fr auto 0.8rem;
1096
+ grid-template-columns: 1.1rem var(--nu-glyph-cell-size) 1fr auto 0.8rem;
1096
1097
  gap: 0.45rem;
1097
1098
  width: 100%;
1098
1099
  min-width: 13rem;
@@ -1175,6 +1176,14 @@
1175
1176
  .nu-main-menu__check-box[data-unchecked-shape="none"] {
1176
1177
  border-color: transparent;
1177
1178
  }
1179
+ .nu-main-menu__icon {
1180
+ display: inline-flex;
1181
+ align-items: center;
1182
+ justify-content: center;
1183
+ inline-size: var(--nu-glyph-cell-size);
1184
+ block-size: var(--nu-glyph-cell-size);
1185
+ color: currentColor;
1186
+ }
1178
1187
  .nu-main-menu__label {
1179
1188
  min-width: 0;
1180
1189
  }
@@ -3520,7 +3529,8 @@
3520
3529
  align-items: center;
3521
3530
  justify-content: center;
3522
3531
  min-height: var(--nu-window-title-height);
3523
- padding: 0 var(--nu-window-title-controls-width) 0 0.45rem;
3532
+ padding: 0 var(--nu-window-title-controls-width) 0
3533
+ calc(0.45rem + var(--nu-window-title-icon-width));
3524
3534
  background: var(--nu-color-title-bg);
3525
3535
  color: var(--nu-color-title-text);
3526
3536
  line-height: 1;
@@ -3534,6 +3544,24 @@
3534
3544
  text-overflow: ellipsis;
3535
3545
  white-space: nowrap;
3536
3546
  }
3547
+ .nu-window__title-icon {
3548
+ position: absolute;
3549
+ top: 0;
3550
+ bottom: 0;
3551
+ left: 0.35rem;
3552
+ display: inline-flex;
3553
+ align-items: center;
3554
+ justify-content: center;
3555
+ width: var(--nu-window-title-icon-width);
3556
+ overflow: hidden;
3557
+ color: inherit;
3558
+ }
3559
+ .nu-window__title-icon > svg,
3560
+ .nu-window__title-icon > img {
3561
+ display: block;
3562
+ max-width: 100%;
3563
+ max-height: calc(var(--nu-window-title-height) - 2px);
3564
+ }
3537
3565
  .nu-window__title-controls {
3538
3566
  position: absolute;
3539
3567
  top: 0;
@@ -3726,6 +3754,16 @@ button.nu-app-bar-item:focus-visible {
3726
3754
  outline: none;
3727
3755
  box-shadow: none;
3728
3756
  }
3757
+ .nu-window-bar__icon {
3758
+ display: inline-flex;
3759
+ align-items: center;
3760
+ justify-content: center;
3761
+ flex: none;
3762
+ inline-size: var(--nu-glyph-cell-size);
3763
+ block-size: var(--nu-glyph-cell-size);
3764
+ margin-inline-end: 0.6ch;
3765
+ color: inherit;
3766
+ }
3729
3767
  .nu-app-bar-host {
3730
3768
  position: absolute;
3731
3769
  right: 0;
@@ -1,7 +1,9 @@
1
+ import { ReactNode } from "react";
1
2
  export type WindowBarItem = {
2
3
  active?: boolean;
3
4
  domain?: string;
4
5
  id: string;
6
+ icon?: ReactNode;
5
7
  minimized?: boolean;
6
8
  title: string;
7
9
  };
@@ -11,6 +11,10 @@ export type NuManagedWindowSnapshot = {
11
11
  width?: number;
12
12
  };
13
13
  export type NuManagedWindowDefinition = {
14
+ /** Windows with the same value share their active/inactive chrome state. */
15
+ activationGroup?: string;
16
+ /** Locks pointer resizing to this width / height ratio and disables maximize. */
17
+ aspectRatio?: number;
14
18
  appModal?: boolean;
15
19
  bodyClassName?: string;
16
20
  border?: WindowBorder;
@@ -18,7 +22,13 @@ export type NuManagedWindowDefinition = {
18
22
  closeable?: boolean;
19
23
  content: ReactNode | ((controls: NuManagedWindowControls) => ReactNode);
20
24
  domain?: string;
25
+ /** Decorative visual rendered in the fixed left title-bar slot. */
26
+ icon?: ReactNode;
21
27
  maximizable?: boolean;
28
+ /** Minimum rendered height and resize bound for this window. */
29
+ minHeight?: CSSProperties["minHeight"];
30
+ /** Minimum rendered width and resize bound for this window. */
31
+ minWidth?: CSSProperties["minWidth"];
22
32
  modal?: boolean | string;
23
33
  minimizable?: boolean;
24
34
  mode?: WindowMode;
package/docs/MainMenu.md CHANGED
@@ -18,6 +18,7 @@
18
18
  - `MainMenuItem`
19
19
  - `id`
20
20
  - `text`
21
+ - `icon?: ReactNode` — decorative icon in a popup menu row
21
22
  - `hotkey?`
22
23
  - `shortcut?`
23
24
  - `checked?`
@@ -50,6 +50,78 @@ windowManager.openWindow({
50
50
  });
51
51
  ```
52
52
 
53
+ ## Title Icons
54
+
55
+ `openWindow(...)` and `openDialog(...)` accept `icon?: ReactNode`. It renders in
56
+ the fixed left title-bar slot, so managed dialogs use the same chrome as regular
57
+ windows. The same icon is reused in the minimized AppBar item, the MDI
58
+ `Window` menu, and the `Pick...` dialog.
59
+
60
+ ```tsx
61
+ windowManager.openDialog({
62
+ content: <NetworkSettings />,
63
+ icon: <NuGlyph name="gear" />,
64
+ title: "Network settings"
65
+ });
66
+ ```
67
+
68
+ ## Fixed Aspect Ratio
69
+
70
+ Set a positive `aspectRatio` (width / height) for image, video, map, or other
71
+ fixed-ratio content. Pointer resizing keeps the ratio, combines `minWidth` and
72
+ `minHeight` into a ratio-consistent minimum, and disables maximizing the
73
+ managed window.
74
+
75
+ ```tsx
76
+ windowManager.openWindow({
77
+ aspectRatio: 178 / 704,
78
+ content: <VirtualRemote />,
79
+ minWidth: "11rem",
80
+ style: { height: "50rem", width: "13rem" },
81
+ title: "Remote"
82
+ });
83
+ ```
84
+
85
+ ## Linked Activation
86
+
87
+ Set the same `activationGroup` on managed windows that represent one logical
88
+ workspace. Activating either one gives every visible member of that group the
89
+ active window chrome. Activating a window outside the group makes all members
90
+ inactive again. This only links activation visuals; it does not dock, move, or
91
+ resize the windows together.
92
+
93
+ ```tsx
94
+ windowManager.openWindow({
95
+ activationGroup: "receiver-42",
96
+ content: <ReceiverOverview />,
97
+ title: "Receiver overview"
98
+ });
99
+
100
+ windowManager.openWindow({
101
+ activationGroup: "receiver-42",
102
+ content: <ReceiverDiagnostics />,
103
+ title: "Receiver diagnostics"
104
+ });
105
+ ```
106
+
107
+ App-modal dialogs remain the sole active surface while open, regardless of an
108
+ activation group.
109
+
110
+ ## Size Limits
111
+
112
+ Managed windows accept `minWidth` and `minHeight` directly. They override the
113
+ provider's default minimum width (`26rem` for a window and `22rem` for a
114
+ dialog) and constrain pointer resizing as well as CSS layout.
115
+
116
+ ```tsx
117
+ windowManager.openWindow({
118
+ content: <CompactLog />,
119
+ minHeight: "10rem",
120
+ minWidth: "18rem",
121
+ title: "Compact log"
122
+ });
123
+ ```
124
+
53
125
  ## Helper Dialogs
54
126
 
55
127
  The same manager also provides async helper dialogs:
package/docs/Window.md CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  ```tsx
14
14
  <Window
15
+ icon={<NuGlyph name="folder" />}
15
16
  title="Activity Log"
16
17
  mode="window"
17
18
  statusBar={
@@ -30,11 +31,16 @@
30
31
  - `title: string`
31
32
  - `mode?: "dialog" | "window"`
32
33
  - `border?: "single" | "double"`
34
+ - `icon?: ReactNode` — decorative visual in the fixed left title-bar slot
33
35
  - `minimized?: boolean`
34
36
  - `maximized?: boolean`
35
37
  - `closeable?: boolean`
36
38
  - `draggable?: boolean`
37
39
  - `resizable?: boolean`
40
+ - `aspectRatio?: number` — positive width / height ratio; locks pointer resize
41
+ and suppresses the maximize control
42
+ - `minWidth?: number | string` — defaults to `240px` for a standalone window
43
+ - `minHeight?: number | string` — defaults to `120px` for a standalone window
38
44
  - `scrollable?: boolean`
39
45
  - `statusBar?: ReactNode`
40
46
  - `titleButtons?: WindowTitleButtonDefinition[]`
@@ -45,9 +51,22 @@
45
51
  - `onSizeChange?(size)`
46
52
  - `onActivate?()`
47
53
 
54
+ `activationGroup?: string` is available on a managed window definition passed
55
+ to `useNuWindowManager().openWindow(...)`; it is resolved by
56
+ `NuWindowProvider`, rather than by a standalone `Window` instance. See
57
+ [NuWindowProvider](./NuWindowProvider.md#linked-activation).
58
+
48
59
  ## Notes
49
60
 
50
61
  - Drag and resize are implemented with pointer events and local DOM updates for smoother motion.
51
62
  - The public `WindowTitleButton` and `useWindowTitleButtons()` helpers support custom title-bar controls.
63
+ - The left title-bar slot is always reserved. Pass `icon` to show a `NuGlyph`,
64
+ Font Awesome icon, SVG, or another React node without shifting the title.
52
65
  - `StatusBarItem` only provides placement semantics (`grow`, `align`) and does not enforce its own border or chrome.
53
66
  - Plain string `statusBar` still works for simple status lines.
67
+ - `minWidth` and `minHeight` are applied as CSS limits and as the lower bounds
68
+ for pointer resizing. A managed window may also specify them in its
69
+ `openWindow(...)` definition.
70
+ - With `aspectRatio`, resizing follows whichever pointer axis has the greater
71
+ ratio-adjusted movement. The other dimension is derived from the ratio, and
72
+ the effective minimum remains ratio-consistent.
package/docs/WindowBar.md CHANGED
@@ -17,8 +17,11 @@
17
17
  - Marks the active window
18
18
  - Groups windows by `domain`
19
19
  - Opens a picker dialog when a grouped domain is clicked
20
+ - Shows each managed window's `icon` beside its title; grouped entries use the
21
+ active window's icon when one is available
20
22
 
21
23
  ## Notes
22
24
 
23
25
  - Grouping is driven by `NuManagedWindowDefinition.domain`.
24
26
  - Grouped pickers use the shared MDI-style window picker dialog logic.
27
+ - The MDI `Window` menu and `Pick...` dialog reuse the same managed-window icon.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deadragdoll/reactnu",
3
- "version": "0.1.52",
3
+ "version": "0.1.56",
4
4
  "private": false,
5
5
  "description": "React components with a precise DOS-era utility interface.",
6
6
  "license": "MIT",