sh3-core 0.11.4 → 0.11.6

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.
Files changed (47) hide show
  1. package/dist/BrandSlot.svelte +80 -0
  2. package/dist/BrandSlot.svelte.d.ts +3 -0
  3. package/dist/BrandSlot.test.d.ts +1 -0
  4. package/dist/BrandSlot.test.js +71 -0
  5. package/dist/Shell.svelte +8 -10
  6. package/dist/actions/ActionPanel.svelte +105 -0
  7. package/dist/actions/ActionPanel.svelte.d.ts +13 -0
  8. package/dist/actions/ActionPanel.test.d.ts +1 -0
  9. package/dist/actions/ActionPanel.test.js +80 -0
  10. package/dist/actions/ContextMenu.svelte +17 -85
  11. package/dist/actions/MenuBar.svelte +57 -0
  12. package/dist/actions/MenuBar.svelte.d.ts +3 -0
  13. package/dist/actions/MenuBar.test.d.ts +1 -0
  14. package/dist/actions/MenuBar.test.js +109 -0
  15. package/dist/actions/MenuButton.svelte +104 -0
  16. package/dist/actions/MenuButton.svelte.d.ts +9 -0
  17. package/dist/actions/MenuButton.test.d.ts +1 -0
  18. package/dist/actions/MenuButton.test.js +88 -0
  19. package/dist/actions/defaultMenuContainers.d.ts +2 -0
  20. package/dist/actions/defaultMenuContainers.js +7 -0
  21. package/dist/actions/defaultMenuContainers.test.d.ts +1 -0
  22. package/dist/actions/defaultMenuContainers.test.js +23 -0
  23. package/dist/actions/menuBarModel.d.ts +28 -0
  24. package/dist/actions/menuBarModel.js +67 -0
  25. package/dist/actions/menuBarModel.test.d.ts +1 -0
  26. package/dist/actions/menuBarModel.test.js +84 -0
  27. package/dist/actions/types.d.ts +8 -0
  28. package/dist/apps/lifecycle.js +8 -1
  29. package/dist/apps/lifecycle.test.js +211 -1
  30. package/dist/apps/registry.svelte.d.ts +17 -1
  31. package/dist/apps/registry.svelte.js +20 -1
  32. package/dist/apps/types.d.ts +28 -0
  33. package/dist/layout/store.svelte.d.ts +27 -0
  34. package/dist/layout/store.svelte.js +63 -0
  35. package/dist/overlays/ConfirmDialog.svelte +138 -0
  36. package/dist/overlays/ConfirmDialog.svelte.d.ts +13 -0
  37. package/dist/overlays/ConfirmDialog.test.d.ts +1 -0
  38. package/dist/overlays/ConfirmDialog.test.js +123 -0
  39. package/dist/overlays/FloatFrame.svelte +2 -2
  40. package/dist/overlays/ToastItem.svelte +3 -3
  41. package/dist/primitives/base.css +5 -5
  42. package/dist/sh3core-shard/sh3coreShard.svelte.js +20 -0
  43. package/dist/shell-shard/shellShard.svelte.js +0 -4
  44. package/dist/tokens.css +1 -1
  45. package/dist/version.d.ts +1 -1
  46. package/dist/version.js +1 -1
  47. package/package.json +1 -1
@@ -0,0 +1,123 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { tick } from 'svelte';
3
+ import { modalManager } from './modal';
4
+ import { registerLayerRoot, unregisterLayerRoot } from './roots';
5
+ import ConfirmDialog from './ConfirmDialog.svelte';
6
+ function makeLayerRoot() {
7
+ const el = document.createElement('div');
8
+ el.style.position = 'relative';
9
+ document.body.appendChild(el);
10
+ registerLayerRoot('modal', el);
11
+ return el;
12
+ }
13
+ function teardownLayerRoot(el) {
14
+ unregisterLayerRoot('modal');
15
+ el.remove();
16
+ }
17
+ describe('ConfirmDialog', () => {
18
+ let layerRoot;
19
+ beforeEach(() => {
20
+ layerRoot = makeLayerRoot();
21
+ });
22
+ afterEach(() => {
23
+ modalManager.closeAll();
24
+ teardownLayerRoot(layerRoot);
25
+ });
26
+ it('renders title and body', async () => {
27
+ modalManager.open(ConfirmDialog, {
28
+ title: 'Reset layout?',
29
+ body: 'This discards your customizations.',
30
+ onConfirm: () => { },
31
+ });
32
+ await tick();
33
+ const box = layerRoot.querySelector('.modal-box');
34
+ expect(box.textContent).toContain('Reset layout?');
35
+ expect(box.textContent).toContain('This discards your customizations.');
36
+ });
37
+ it('Cancel button calls onCancel and closes', async () => {
38
+ const onCancel = vi.fn();
39
+ const onConfirm = vi.fn();
40
+ modalManager.open(ConfirmDialog, {
41
+ title: 't',
42
+ body: 'b',
43
+ onCancel,
44
+ onConfirm,
45
+ });
46
+ await tick();
47
+ const cancelBtn = layerRoot.querySelector('[data-confirm-dialog-cancel]');
48
+ cancelBtn.click();
49
+ await tick();
50
+ expect(onCancel).toHaveBeenCalledOnce();
51
+ expect(onConfirm).not.toHaveBeenCalled();
52
+ expect(layerRoot.querySelector('.sh3-modal-host')).toBeNull();
53
+ });
54
+ it('Confirm button calls onConfirm and closes', async () => {
55
+ const onConfirm = vi.fn();
56
+ modalManager.open(ConfirmDialog, {
57
+ title: 't',
58
+ body: 'b',
59
+ onConfirm,
60
+ });
61
+ await tick();
62
+ const confirmBtn = layerRoot.querySelector('[data-confirm-dialog-confirm]');
63
+ confirmBtn.click();
64
+ await tick();
65
+ expect(onConfirm).toHaveBeenCalledOnce();
66
+ expect(layerRoot.querySelector('.sh3-modal-host')).toBeNull();
67
+ });
68
+ it('awaits async onConfirm before closing', async () => {
69
+ let resolveFn = () => { };
70
+ const onConfirm = vi.fn(() => new Promise((resolve) => {
71
+ resolveFn = resolve;
72
+ }));
73
+ modalManager.open(ConfirmDialog, {
74
+ title: 't',
75
+ body: 'b',
76
+ onConfirm,
77
+ });
78
+ await tick();
79
+ const confirmBtn = layerRoot.querySelector('[data-confirm-dialog-confirm]');
80
+ confirmBtn.click();
81
+ await tick();
82
+ // Modal still open — onConfirm hasn't resolved yet.
83
+ expect(layerRoot.querySelector('.sh3-modal-host')).not.toBeNull();
84
+ resolveFn();
85
+ await tick();
86
+ await tick();
87
+ expect(layerRoot.querySelector('.sh3-modal-host')).toBeNull();
88
+ });
89
+ it('confirmTone: "danger" applies the danger class to the confirm button', async () => {
90
+ modalManager.open(ConfirmDialog, {
91
+ title: 't',
92
+ body: 'b',
93
+ confirmTone: 'danger',
94
+ onConfirm: () => { },
95
+ });
96
+ await tick();
97
+ const confirmBtn = layerRoot.querySelector('[data-confirm-dialog-confirm]');
98
+ expect(confirmBtn.classList.contains('confirm-dialog-btn-danger')).toBe(true);
99
+ });
100
+ it('uses provided confirmLabel and cancelLabel', async () => {
101
+ modalManager.open(ConfirmDialog, {
102
+ title: 't',
103
+ body: 'b',
104
+ confirmLabel: 'Wipe',
105
+ cancelLabel: 'Keep',
106
+ onConfirm: () => { },
107
+ });
108
+ await tick();
109
+ expect(layerRoot.querySelector('[data-confirm-dialog-confirm]').textContent).toContain('Wipe');
110
+ expect(layerRoot.querySelector('[data-confirm-dialog-cancel]').textContent).toContain('Keep');
111
+ });
112
+ it('default focus is the Cancel button', async () => {
113
+ modalManager.open(ConfirmDialog, {
114
+ title: 't',
115
+ body: 'b',
116
+ onConfirm: () => { },
117
+ });
118
+ await tick();
119
+ await tick(); // focus is set in $effect after mount
120
+ const cancelBtn = layerRoot.querySelector('[data-confirm-dialog-cancel]');
121
+ expect(document.activeElement).toBe(cancelBtn);
122
+ });
123
+ });
@@ -109,7 +109,7 @@
109
109
  position: absolute;
110
110
  display: flex;
111
111
  flex-direction: column;
112
- background: var(--shell-grad-bg-elevated, var(--shell-bg-elevated, #1e1e1e));
112
+ background: var(--shell-grad-bg-elevated, var(--shell-bg-elevated));
113
113
  color: var(--shell-fg);
114
114
  border: 1px solid var(--shell-border-strong);
115
115
  border-radius: var(--shell-radius);
@@ -121,7 +121,7 @@
121
121
  align-items: center;
122
122
  justify-content: space-between;
123
123
  padding: 4px 8px;
124
- background: var(--shell-bg, #111);
124
+ background: var(--shell-grad-bg-sunken, var(--shell-bg-sunken));
125
125
  cursor: move;
126
126
  user-select: none;
127
127
  border-bottom: 1px solid var(--shell-border-strong);
@@ -66,9 +66,9 @@
66
66
  .toast-message { flex: 1; }
67
67
 
68
68
  .toast-info { border-left-color: var(--shell-accent); }
69
- .toast-success { border-left-color: #5cb176; }
70
- .toast-warn { border-left-color: #d6a84a; }
71
- .toast-error { border-left-color: #d06060; }
69
+ .toast-success { border-left-color: var(--shell-success); }
70
+ .toast-warn { border-left-color: var(--shell-warning); }
71
+ .toast-error { border-left-color: var(--shell-error); }
72
72
 
73
73
  @keyframes toast-in {
74
74
  from { opacity: 0; transform: translateY(8px); }
@@ -15,8 +15,8 @@ input[type="submit"],
15
15
  input[type="reset"],
16
16
  .shell-base-button {
17
17
  padding: 6px 14px;
18
- background: var(--shell-accent, #6ea8fe);
19
- color: var(--shell-fg, #fff);
18
+ background: var(--shell-accent);
19
+ color: var(--shell-fg-on-accent);
20
20
  border: none;
21
21
  border-radius: var(--shell-radius);
22
22
  cursor: pointer;
@@ -113,7 +113,7 @@ input[type="radio"].shell-base-radio {
113
113
  content: "";
114
114
  width: 8px;
115
115
  height: 8px;
116
- background: #fff;
116
+ background: var(--shell-fg-on-accent);
117
117
  clip-path: polygon(14% 44%, 0 60%, 40% 100%, 100% 20%, 85% 8%, 38% 70%);
118
118
  }
119
119
 
@@ -122,7 +122,7 @@ input[type="radio"].shell-base-radio {
122
122
  width: 6px;
123
123
  height: 6px;
124
124
  border-radius: 50%;
125
- background: #fff;
125
+ background: var(--shell-fg-on-accent);
126
126
  }
127
127
 
128
128
  .shell-base-check:focus-visible,
@@ -167,7 +167,7 @@ input[type="checkbox"].shell-base-switch {
167
167
  .shell-base-switch:checked { background: var(--shell-accent); }
168
168
  .shell-base-switch:checked::before {
169
169
  transform: translateX(12px);
170
- background: #fff;
170
+ background: var(--shell-fg-on-accent);
171
171
  }
172
172
 
173
173
  .shell-base-switch:focus-visible {
@@ -24,10 +24,13 @@
24
24
  import { mount, unmount } from 'svelte';
25
25
  import ShellHome from './ShellHome.svelte';
26
26
  import KeysAndPeers from '../shell/views/KeysAndPeers.svelte';
27
+ import ConfirmDialog from '../overlays/ConfirmDialog.svelte';
27
28
  import { VERSION } from '../version';
28
29
  import { __setBindingsZone } from '../actions/bindings-store';
29
30
  import { registeredApps } from '../apps/registry.svelte';
30
31
  import { launchApp } from '../apps/lifecycle';
32
+ import { resetActivePresetToDefault } from '../layout/store.svelte';
33
+ import { modalManager } from '../overlays/modal';
31
34
  export const sh3coreShard = {
32
35
  manifest: {
33
36
  id: '__sh3core__',
@@ -57,6 +60,23 @@ export const sh3coreShard = {
57
60
  import('../actions/listeners').then(({ openPalette }) => openPalette());
58
61
  },
59
62
  });
63
+ ctx.actions.register({
64
+ id: 'sh3.app.reset-layout',
65
+ label: 'Reset Current Layout',
66
+ scope: ['app'],
67
+ paletteItem: true,
68
+ contextItem: false,
69
+ run() {
70
+ modalManager.open(ConfirmDialog, {
71
+ title: 'Reset layout?',
72
+ body: 'This discards the current arrangement of the active preset and ' +
73
+ 'rebuilds it from the app default. Floats will be removed.',
74
+ confirmLabel: 'Reset',
75
+ confirmTone: 'danger',
76
+ onConfirm: () => resetActivePresetToDefault(),
77
+ });
78
+ },
79
+ });
60
80
  const factory = {
61
81
  mount(container, _context) {
62
82
  const instance = mount(ShellHome, { target: container });
@@ -176,10 +176,6 @@ export function makeShellApiForTest() {
176
176
  export const shellShard = {
177
177
  manifest,
178
178
  activate(ctx) {
179
- if (!ctx.isAdmin) {
180
- // Non-admin: don't expose the view. Nothing to register.
181
- return;
182
- }
183
179
  registerV1Verbs(ctx);
184
180
  const shell = makeShellApi(ctx);
185
181
  // The AZERTY `²` key (top-left on FR keyboards, below Escape) opens the
package/dist/tokens.css CHANGED
@@ -33,7 +33,7 @@
33
33
  --shell-accent-muted: #3a5580;
34
34
 
35
35
  /* Inputs */
36
- --shell-input-bg: #2a2a2a;
36
+ --shell-input-bg: var(--shell-bg-sunken);
37
37
  --shell-input-border-focus: var(--shell-accent);
38
38
  --shell-focus-ring: 0 0 0 2px color-mix(in srgb, var(--shell-accent) 40%, transparent);
39
39
 
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Auto-generated from package.json — do not edit manually. */
2
- export declare const VERSION = "0.11.4";
2
+ export declare const VERSION = "0.11.6";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Auto-generated from package.json — do not edit manually. */
2
- export const VERSION = '0.11.4';
2
+ export const VERSION = '0.11.6';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh3-core",
3
- "version": "0.11.4",
3
+ "version": "0.11.6",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"