@deadragdoll/reactnu 0.1.18 → 0.1.24

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
@@ -542,6 +542,73 @@
542
542
  .nu-info__accent[data-upper] {
543
543
  text-transform: uppercase;
544
544
  }
545
+ .nu-icon-grid {
546
+ position: relative;
547
+ min-width: 0;
548
+ min-height: 0;
549
+ width: 100%;
550
+ height: 100%;
551
+ overflow: hidden;
552
+ user-select: none;
553
+ }
554
+ .nu-icon-grid__icon {
555
+ position: absolute;
556
+ display: grid;
557
+ grid-template-rows: 3.25rem minmax(0, 2.2em);
558
+ justify-items: center;
559
+ width: 6rem;
560
+ height: 6rem;
561
+ padding: 0.25rem;
562
+ border: 1px solid transparent;
563
+ background: transparent;
564
+ color: var(--nu-text-primary);
565
+ font: inherit;
566
+ line-height: 1.1;
567
+ text-align: center;
568
+ cursor: default;
569
+ touch-action: none;
570
+ }
571
+ .nu-icon-grid__icon:focus-visible,
572
+ .nu-icon-grid__icon[data-selected] {
573
+ border-color: var(--nu-border-light);
574
+ outline: 1px solid var(--nu-border-dark);
575
+ outline-offset: -3px;
576
+ background: var(--nu-color-title-bg);
577
+ color: var(--nu-text-inverse);
578
+ }
579
+ .nu-icon-grid__icon[data-dragging] {
580
+ z-index: 1;
581
+ }
582
+ .nu-icon-grid__icon:disabled {
583
+ opacity: 0.6;
584
+ }
585
+ .nu-icon-grid__glyph {
586
+ display: inline-flex;
587
+ align-items: center;
588
+ justify-content: center;
589
+ width: 3rem;
590
+ height: 3rem;
591
+ color: var(--nu-text-hotkey);
592
+ }
593
+ .nu-icon-grid__glyph > img,
594
+ .nu-icon-grid__glyph > svg {
595
+ display: block;
596
+ max-width: 100%;
597
+ max-height: 100%;
598
+ width: 100%;
599
+ height: 100%;
600
+ object-fit: contain;
601
+ }
602
+ .nu-icon-grid__label {
603
+ display: -webkit-box;
604
+ max-width: 100%;
605
+ overflow: hidden;
606
+ overflow-wrap: anywhere;
607
+ text-overflow: ellipsis;
608
+ -webkit-box-orient: vertical;
609
+ -webkit-line-clamp: 2;
610
+ line-clamp: 2;
611
+ }
545
612
  .nu-listbox {
546
613
  flex: 1 1 auto;
547
614
  align-self: stretch;
@@ -39,6 +39,8 @@ See: [Slot Customization](./SLOT_CUSTOMIZATION.md)
39
39
  - `useNuWindowManager()`
40
40
  opens, updates, activates, and closes managed windows
41
41
  also exposes `showMessageBox(...)` and `showInputBox(...)`
42
+ - `useNuIconManager()`
43
+ manages icons inside a `NuIconProvider`
42
44
  - `usePopupMenu()`
43
45
  anchor/open helper for `PopupMenu`
44
46
  - `useWindowMenu()`
@@ -113,6 +115,8 @@ See: [Slot Customization](./SLOT_CUSTOMIZATION.md)
113
115
  docs: [MainMenu](./MainMenu.md)
114
116
  - `PopupMenu`
115
117
  docs: [PopupMenu](./PopupMenu.md)
118
+ - `NuIconProvider`, `NuIconGrid`
119
+ docs: [Icon Grid](./IconGrid.md)
116
120
 
117
121
  ## Windowing And Desktop Chrome
118
122
 
@@ -19,6 +19,7 @@
19
19
  - [Frame](./Frame.md)
20
20
  - [Glyph](./Glyph.md)
21
21
  - [Info](./Info.md)
22
+ - [Icon Grid](./IconGrid.md)
22
23
  - [ListBox](./ListBox.md)
23
24
  - [ListView](./ListView.md)
24
25
  - [MainMenu](./MainMenu.md)
package/docs/Desktop.md CHANGED
@@ -21,6 +21,19 @@
21
21
  - `appBarContent?: ReactNode`
22
22
  - standard `div` props
23
23
 
24
+ ## Application icons
25
+
26
+ `NuDesktop` does not own a separate icon implementation. Compose a reusable
27
+ `NuIconProvider` and `NuIconGrid` inside the desktop workspace instead. The
28
+ same pair can also live inside a `Window`.
29
+
30
+ Use `NuIconGrid`'s `contextMenuItems` callback for a desktop background menu.
31
+ It receives `useNuIconManager()`'s methods, so an `Arrange icons` submenu can
32
+ call `arrangeIcons("columns")`, `arrangeIcons("rows")`, or
33
+ `arrangeIcons("name")`.
34
+
35
+ See [Icon Grid](./IconGrid.md) for the full API and interaction contract.
36
+
24
37
  ## Notes
25
38
 
26
39
  - The desktop owns the browser viewport and is intended to behave like a bounded screen.
@@ -0,0 +1,93 @@
1
+ # Icon Grid
2
+
3
+ `NuIconProvider` owns a mutable collection of application icons. Place a
4
+ `NuIconGrid` anywhere inside it: on the desktop, in a `Window`, or in another
5
+ bounded surface.
6
+
7
+ ```tsx
8
+ import {
9
+ NuIconGrid,
10
+ NuIconProvider,
11
+ useNuIconManager
12
+ } from "@deadragdoll/reactnu";
13
+
14
+ function Applications() {
15
+ return (
16
+ <NuIconProvider
17
+ defaultIcons={[
18
+ {
19
+ id: "diagnostics",
20
+ icon: "/icons/diagnostics.svg",
21
+ label: "&Diagnostics",
22
+ onDoubleClick: () => openDiagnostics()
23
+ }
24
+ ]}
25
+ >
26
+ <NuIconGrid
27
+ defaultArrangeMode="columns"
28
+ contextMenuItems={(icons) => [
29
+ {
30
+ id: "arrange-icons",
31
+ items: [
32
+ {
33
+ id: "arrange-by-name",
34
+ text: "&By name",
35
+ onSelect: () => icons.arrangeIcons("name")
36
+ }
37
+ ],
38
+ text: "&Arrange icons"
39
+ }
40
+ ]}
41
+ />
42
+ </NuIconProvider>
43
+ );
44
+ }
45
+ ```
46
+
47
+ ## API
48
+
49
+ `NuIconProvider`
50
+
51
+ - `defaultIcons?: NuIconDefinition[]` seeds its internal collection. IDs should
52
+ be unique; omitted IDs are generated.
53
+ - Icon `icon` accepts a URL string for SVG, PNG, or JPEG assets, or inline
54
+ React content such as an `<svg>`.
55
+
56
+ `NuIconGrid`
57
+
58
+ - `contextMenuItems` accepts ordinary `MainMenuNode[]` or a callback receiving
59
+ the icon manager. Use the callback for a background menu such as Arrange
60
+ icons.
61
+ - `defaultArrangeMode="columns" | "rows" | "name"` arranges seeded icons
62
+ once, after the grid measures a non-zero available area. This prevents icons
63
+ from initially landing outside a bounded `Window`.
64
+
65
+ `useNuIconManager()`
66
+
67
+ - `addIcon(definition)` returns the new icon ID.
68
+ - `updateIcon(id, patch)`, `removeIcon(id)`, `moveIcon(id, position)`, and
69
+ `selectIcon(id | null)` update the provider collection.
70
+ - `arrangeIcons("columns" | "rows" | "name")` lays out the current icons.
71
+
72
+ Each icon can have `onClick`, `onDoubleClick`, `onContextMenu`,
73
+ `onPositionChange`, and its own `contextMenuItems`.
74
+
75
+ ## Interaction and accessibility
76
+
77
+ - Drag icons to move them inside the grid; their resulting positions remain in
78
+ the provider for the lifetime of that provider.
79
+ - A click selects an icon. Enter and Space activate its normal button action.
80
+ - Right-click opens the icon menu; `Shift+F10` and the Context Menu key open it
81
+ from the keyboard.
82
+ - Right-click the grid background for the grid context menu, such as Arrange
83
+ icons. An `onContextMenu` handler may call `preventDefault()` to replace it.
84
+ - Labels wrap to two lines. Longer labels receive an ellipsis; long unbroken
85
+ words are wrapped instead of overflowing their icon cell.
86
+
87
+ ## Persistence
88
+
89
+ The provider keeps icon positions for its mounted lifetime. To restore a layout
90
+ after a reload, save a position from `onPositionChange` and pass it back as the
91
+ icon's `position` in `defaultIcons` on the next mount. Call `arrangeIcons(...)`
92
+ only for an explicit user action, rather than on every render, so a saved layout
93
+ is not overwritten.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deadragdoll/reactnu",
3
- "version": "0.1.18",
3
+ "version": "0.1.24",
4
4
  "private": false,
5
5
  "description": "React components with a precise DOS-era utility interface.",
6
6
  "license": "MIT",