spaday-regular-layout 0.2.0__tar.gz → 0.2.2__tar.gz

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 (40) hide show
  1. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/.gitignore +5 -0
  2. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/PKG-INFO +8 -3
  3. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/README.md +6 -1
  4. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/build.mjs +9 -3
  5. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/package.json +7 -5
  6. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/pnpm-lock.yaml +133 -1
  7. spaday_regular_layout-0.2.2/js/src/css/spa.css +124 -0
  8. {spaday_regular_layout-0.2.0/spaday_regular_layout/extension → spaday_regular_layout-0.2.2/js/src/html}/index.html +1 -0
  9. spaday_regular_layout-0.2.2/js/src/ts/define-guard.ts +25 -0
  10. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/src/ts/index.ts +29 -0
  11. spaday_regular_layout-0.2.2/js/tests/index.spec.js +287 -0
  12. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/tools/bundle.mjs +1 -1
  13. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/tsconfig.json +2 -2
  14. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/pyproject.toml +3 -3
  15. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/spaday_regular_layout/__init__.py +2 -2
  16. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/spaday_regular_layout/example.py +1 -1
  17. spaday_regular_layout-0.2.2/spaday_regular_layout/extension/cdn/index.js +21 -0
  18. spaday_regular_layout-0.2.2/spaday_regular_layout/extension/cdn/index.js.map +7 -0
  19. spaday_regular_layout-0.2.2/spaday_regular_layout/extension/css/index.css +0 -0
  20. spaday_regular_layout-0.2.2/spaday_regular_layout/extension/css/spa.css +1 -0
  21. {spaday_regular_layout-0.2.0/js/src/html → spaday_regular_layout-0.2.2/spaday_regular_layout/extension}/index.html +1 -0
  22. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/spaday_regular_layout/tests/test_all.py +1 -0
  23. spaday_regular_layout-0.2.0/js/tests/index.spec.js +0 -137
  24. spaday_regular_layout-0.2.0/spaday_regular_layout/extension/cdn/index.js +0 -648
  25. spaday_regular_layout-0.2.0/spaday_regular_layout/extension/cdn/index.js.map +0 -7
  26. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/LICENSE +0 -0
  27. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/.oxfmtrc.json +0 -0
  28. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/.oxlintrc.json +0 -0
  29. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/playwright.config.js +0 -0
  30. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/pnpm-workspace.yaml +0 -0
  31. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/src/css/index.css +0 -0
  32. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/src/ts/css.d.ts +0 -0
  33. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/tools/css.mjs +0 -0
  34. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/tools/externals.mjs +0 -0
  35. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/tools/getarg.mjs +0 -0
  36. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/js/tools/html.mjs +0 -0
  37. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/spaday_regular_layout/components.cem.json +0 -0
  38. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/spaday_regular_layout/components.py +0 -0
  39. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/spaday_regular_layout/extension/css/lorax.css +0 -0
  40. {spaday_regular_layout-0.2.0 → spaday_regular_layout-0.2.2}/spaday_regular_layout/tests/test_example.py +0 -0
@@ -13,6 +13,10 @@ __pycache__/
13
13
  *.exp
14
14
  *.lib
15
15
 
16
+ # vcpkg
17
+ vcpkg/
18
+ vcpkg_installed/
19
+
16
20
  # Rust
17
21
  target
18
22
  target-capi
@@ -142,6 +146,7 @@ spaday_regular_layout/labextension
142
146
 
143
147
  # Emscripten SDK (locally installed)
144
148
  emsdk
149
+ .pyodide_build/
145
150
 
146
151
  # Mac
147
152
  .DS_Store
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: spaday-regular-layout
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: regular-layout for spaday
5
5
  Project-URL: Repository, https://github.com/1kbgz/spaday-regular-layout
6
6
  Project-URL: Homepage, https://github.com/1kbgz/spaday-regular-layout
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.14
17
17
  Classifier: Programming Language :: Python :: Implementation :: CPython
18
18
  Classifier: Programming Language :: Python :: Implementation :: PyPy
19
19
  Requires-Python: >=3.11
20
- Requires-Dist: spaday>=0.6.0
20
+ Requires-Dist: spaday<1.0,>=0.6.0
21
21
  Provides-Extra: develop
22
22
  Requires-Dist: build; extra == 'develop'
23
23
  Requires-Dist: bump-my-version; extra == 'develop'
@@ -48,7 +48,12 @@ Requires-Dist: uvicorn; extra == 'examples'
48
48
  Requires-Dist: websockets; extra == 'examples'
49
49
  Description-Content-Type: text/markdown
50
50
 
51
- # spaday-regular-layout
51
+ <a href="https://github.com/1kbgz/spaday-regular-layout">
52
+ <picture>
53
+ <source media="(prefers-color-scheme: dark)" srcset="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-dark.png?raw=true">
54
+ <img alt="spaday-regular-layout logo, a picnic blanket and basket inside a browser window" src="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-light.png?raw=true" width="800">
55
+ </picture>
56
+ </a>
52
57
 
53
58
  Serializable, resizable panel layouts for spaday, powered by `regular-layout`.
54
59
 
@@ -1,4 +1,9 @@
1
- # spaday-regular-layout
1
+ <a href="https://github.com/1kbgz/spaday-regular-layout">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-dark.png?raw=true">
4
+ <img alt="spaday-regular-layout logo, a picnic blanket and basket inside a browser window" src="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-light.png?raw=true" width="800">
5
+ </picture>
6
+ </a>
2
7
 
3
8
  Serializable, resizable panel layouts for spaday, powered by `regular-layout`.
4
9
 
@@ -1,4 +1,5 @@
1
1
  import { bundle } from "./tools/bundle.mjs";
2
+ import { bundle_css } from "./tools/css.mjs";
2
3
  import { node_modules_external } from "./tools/externals.mjs";
3
4
 
4
5
  import fs from "fs";
@@ -23,12 +24,17 @@ async function build() {
23
24
  force: true,
24
25
  });
25
26
 
27
+ // Bundle css (incl. spa.css, our shell-aligned theme — light + dark via the --spa-* tokens)
28
+ await bundle_css("src/css");
29
+
26
30
  // Copy HTML
27
31
  await cpy("src/html/*", "dist/");
28
32
 
29
33
  // Copy images
30
- fs.mkdirSync("dist/img", { recursive: true });
31
- await cpy("src/img/*", "dist/img");
34
+ if (fs.existsSync("src/img")) {
35
+ fs.mkdirSync("dist/img", { recursive: true });
36
+ await cpy("src/img/*", "dist/img");
37
+ }
32
38
 
33
39
  const theme = fs
34
40
  .readFileSync("node_modules/regular-layout/themes/lorax.css", "utf8")
@@ -47,4 +53,4 @@ async function build() {
47
53
  });
48
54
  }
49
55
 
50
- build();
56
+ await build();
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spaday-regular-layout",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "regular-layout for spaday",
5
5
  "repository": "git@github.com:1kbgz/spaday-regular-layout.git",
6
6
  "author": "1kbgz <dev@1kbgz.com>",
@@ -18,8 +18,7 @@
18
18
  "./package.json": "./package.json"
19
19
  },
20
20
  "files": [
21
- "dist/**/*",
22
- "index.d.ts"
21
+ "dist/**/*"
23
22
  ],
24
23
  "types": "./dist/esm/index.d.ts",
25
24
  "publishConfig": {
@@ -27,7 +26,9 @@
27
26
  },
28
27
  "scripts": {
29
28
  "build:debug": "node build.mjs --debug",
30
- "build": "node build.mjs",
29
+ "build:prod": "node build.mjs",
30
+ "build:types": "tsc",
31
+ "build": "npm-run-all build:prod build:types",
31
32
  "clean": "rm -rf dist playwright-report ../spaday_regular_layout/extension",
32
33
  "dev": "npm-run-all -p start watch",
33
34
  "lint": "oxlint . && oxfmt --check \"src/**/*.{js,ts,jsx,tsx,css}\" \"tests/**/*.{js,ts,jsx,tsx}\" \"*.mjs\" \"*.json\"",
@@ -40,13 +41,14 @@
40
41
  "watch": "nodemon --watch src -e ts,css,html --exec \"pnpm build:debug\""
41
42
  },
42
43
  "dependencies": {
43
- "regular-layout": "^0.6.1"
44
+ "regular-layout": "=0.6.1"
44
45
  },
45
46
  "devDependencies": {
46
47
  "@playwright/test": "^1.62.0",
47
48
  "cpy": "^13.2.2",
48
49
  "esbuild": "^0.28.1",
49
50
  "http-server": "^14.1.1",
51
+ "lightningcss": "^1.33.0",
50
52
  "nodemon": "^3.1.10",
51
53
  "npm-run-all": "^4.1.5",
52
54
  "oxfmt": "^0.63.0",
@@ -9,7 +9,7 @@ importers:
9
9
  .:
10
10
  dependencies:
11
11
  regular-layout:
12
- specifier: ^0.6.1
12
+ specifier: '=0.6.1'
13
13
  version: 0.6.1
14
14
  devDependencies:
15
15
  '@playwright/test':
@@ -24,6 +24,9 @@ importers:
24
24
  http-server:
25
25
  specifier: ^14.1.1
26
26
  version: 14.1.1(debug@4.4.3(supports-color@5.5.0))(supports-color@5.5.0)
27
+ lightningcss:
28
+ specifier: ^1.33.0
29
+ version: 1.33.0
27
30
  nodemon:
28
31
  specifier: ^3.1.10
29
32
  version: 3.1.14
@@ -725,6 +728,10 @@ packages:
725
728
  resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
726
729
  engines: {node: '>= 0.4'}
727
730
 
731
+ detect-libc@2.1.2:
732
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
733
+ engines: {node: '>=8'}
734
+
728
735
  dunder-proto@1.0.1:
729
736
  resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
730
737
  engines: {node: '>= 0.4'}
@@ -1045,6 +1052,80 @@ packages:
1045
1052
  resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==}
1046
1053
  engines: {node: '>=12.20'}
1047
1054
 
1055
+ lightningcss-android-arm64@1.33.0:
1056
+ resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==}
1057
+ engines: {node: '>= 12.0.0'}
1058
+ cpu: [arm64]
1059
+ os: [android]
1060
+
1061
+ lightningcss-darwin-arm64@1.33.0:
1062
+ resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==}
1063
+ engines: {node: '>= 12.0.0'}
1064
+ cpu: [arm64]
1065
+ os: [darwin]
1066
+
1067
+ lightningcss-darwin-x64@1.33.0:
1068
+ resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==}
1069
+ engines: {node: '>= 12.0.0'}
1070
+ cpu: [x64]
1071
+ os: [darwin]
1072
+
1073
+ lightningcss-freebsd-x64@1.33.0:
1074
+ resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==}
1075
+ engines: {node: '>= 12.0.0'}
1076
+ cpu: [x64]
1077
+ os: [freebsd]
1078
+
1079
+ lightningcss-linux-arm-gnueabihf@1.33.0:
1080
+ resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==}
1081
+ engines: {node: '>= 12.0.0'}
1082
+ cpu: [arm]
1083
+ os: [linux]
1084
+
1085
+ lightningcss-linux-arm64-gnu@1.33.0:
1086
+ resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==}
1087
+ engines: {node: '>= 12.0.0'}
1088
+ cpu: [arm64]
1089
+ os: [linux]
1090
+ libc: [glibc]
1091
+
1092
+ lightningcss-linux-arm64-musl@1.33.0:
1093
+ resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==}
1094
+ engines: {node: '>= 12.0.0'}
1095
+ cpu: [arm64]
1096
+ os: [linux]
1097
+ libc: [musl]
1098
+
1099
+ lightningcss-linux-x64-gnu@1.33.0:
1100
+ resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==}
1101
+ engines: {node: '>= 12.0.0'}
1102
+ cpu: [x64]
1103
+ os: [linux]
1104
+ libc: [glibc]
1105
+
1106
+ lightningcss-linux-x64-musl@1.33.0:
1107
+ resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==}
1108
+ engines: {node: '>= 12.0.0'}
1109
+ cpu: [x64]
1110
+ os: [linux]
1111
+ libc: [musl]
1112
+
1113
+ lightningcss-win32-arm64-msvc@1.33.0:
1114
+ resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==}
1115
+ engines: {node: '>= 12.0.0'}
1116
+ cpu: [arm64]
1117
+ os: [win32]
1118
+
1119
+ lightningcss-win32-x64-msvc@1.33.0:
1120
+ resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==}
1121
+ engines: {node: '>= 12.0.0'}
1122
+ cpu: [x64]
1123
+ os: [win32]
1124
+
1125
+ lightningcss@1.33.0:
1126
+ resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==}
1127
+ engines: {node: '>= 12.0.0'}
1128
+
1048
1129
  load-json-file@4.0.0:
1049
1130
  resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==}
1050
1131
  engines: {node: '>=4'}
@@ -1905,6 +1986,8 @@ snapshots:
1905
1986
  has-property-descriptors: 1.0.2
1906
1987
  object-keys: 1.1.1
1907
1988
 
1989
+ detect-libc@2.1.2: {}
1990
+
1908
1991
  dunder-proto@1.0.1:
1909
1992
  dependencies:
1910
1993
  call-bind-apply-helpers: 1.0.2
@@ -2331,6 +2414,55 @@ snapshots:
2331
2414
 
2332
2415
  junk@4.0.1: {}
2333
2416
 
2417
+ lightningcss-android-arm64@1.33.0:
2418
+ optional: true
2419
+
2420
+ lightningcss-darwin-arm64@1.33.0:
2421
+ optional: true
2422
+
2423
+ lightningcss-darwin-x64@1.33.0:
2424
+ optional: true
2425
+
2426
+ lightningcss-freebsd-x64@1.33.0:
2427
+ optional: true
2428
+
2429
+ lightningcss-linux-arm-gnueabihf@1.33.0:
2430
+ optional: true
2431
+
2432
+ lightningcss-linux-arm64-gnu@1.33.0:
2433
+ optional: true
2434
+
2435
+ lightningcss-linux-arm64-musl@1.33.0:
2436
+ optional: true
2437
+
2438
+ lightningcss-linux-x64-gnu@1.33.0:
2439
+ optional: true
2440
+
2441
+ lightningcss-linux-x64-musl@1.33.0:
2442
+ optional: true
2443
+
2444
+ lightningcss-win32-arm64-msvc@1.33.0:
2445
+ optional: true
2446
+
2447
+ lightningcss-win32-x64-msvc@1.33.0:
2448
+ optional: true
2449
+
2450
+ lightningcss@1.33.0:
2451
+ dependencies:
2452
+ detect-libc: 2.1.2
2453
+ optionalDependencies:
2454
+ lightningcss-android-arm64: 1.33.0
2455
+ lightningcss-darwin-arm64: 1.33.0
2456
+ lightningcss-darwin-x64: 1.33.0
2457
+ lightningcss-freebsd-x64: 1.33.0
2458
+ lightningcss-linux-arm-gnueabihf: 1.33.0
2459
+ lightningcss-linux-arm64-gnu: 1.33.0
2460
+ lightningcss-linux-arm64-musl: 1.33.0
2461
+ lightningcss-linux-x64-gnu: 1.33.0
2462
+ lightningcss-linux-x64-musl: 1.33.0
2463
+ lightningcss-win32-arm64-msvc: 1.33.0
2464
+ lightningcss-win32-x64-msvc: 1.33.0
2465
+
2334
2466
  load-json-file@4.0.0:
2335
2467
  dependencies:
2336
2468
  graceful-fs: 4.2.11
@@ -0,0 +1,124 @@
1
+ /* The `spa` theme: neutral panel chrome aligned with the spaday shell and WebAwesome.
2
+ * Apply with class="spa" on <spaday-regular-layout>. Every color rides a local token
3
+ * that defers to the shell's --spa-* variables, so an application that re-themes the
4
+ * shell carries the layout with it, and spaday's page-mode convention applies: `wa-dark`
5
+ * on the root switches to the dark values, `wa-light` flips a nested island back. The
6
+ * fallbacks keep a standalone page coherent in both modes. */
7
+
8
+ spaday-regular-layout.spa {
9
+ --spa-rl-surface: var(--spa-surface, #fff);
10
+ --spa-rl-surface-2: var(--spa-surface-2, #fafafa);
11
+ --spa-rl-border: var(--spa-border, #e6e6e6);
12
+ --spa-rl-muted: var(--spa-muted, #666);
13
+ --spa-rl-shadow: rgba(0, 0, 0, 0.05);
14
+ }
15
+
16
+ :where(.wa-dark) spaday-regular-layout.spa {
17
+ --spa-rl-surface: var(--spa-surface, #15191e);
18
+ --spa-rl-surface-2: var(--spa-surface-2, #1d232b);
19
+ --spa-rl-border: var(--spa-border, #333b45);
20
+ --spa-rl-muted: var(--spa-muted, #9aa3ad);
21
+ --spa-rl-shadow: rgba(0, 0, 0, 0.35);
22
+ }
23
+
24
+ :where(.wa-light) spaday-regular-layout.spa {
25
+ --spa-rl-surface: var(--spa-surface, #fff);
26
+ --spa-rl-surface-2: var(--spa-surface-2, #fafafa);
27
+ --spa-rl-border: var(--spa-border, #e6e6e6);
28
+ --spa-rl-muted: var(--spa-muted, #666);
29
+ --spa-rl-shadow: rgba(0, 0, 0, 0.05);
30
+ }
31
+
32
+ spaday-regular-layout.spa regular-layout-frame {
33
+ --rl-tab-width: 200px;
34
+ }
35
+
36
+ /* Panel content chrome (only the selected frame's container is rendered). */
37
+ spaday-regular-layout.spa regular-layout-frame::part(container) {
38
+ box-sizing: border-box;
39
+ margin: 0 3px 3px 3px;
40
+ padding: 8px;
41
+ /* Square top-left so the tab strip sits flush; rounded elsewhere. */
42
+ border-radius: 0 8px 8px 8px;
43
+ border: 1px solid var(--spa-rl-border);
44
+ background: var(--spa-rl-surface);
45
+ box-shadow: 0 1px 2px var(--spa-rl-shadow);
46
+ }
47
+
48
+ /* Transparent strip; the engine tiles the per-frame tabs across it. */
49
+ spaday-regular-layout.spa regular-layout-frame::part(titlebar) {
50
+ margin: 3px 6px 0 3px;
51
+ align-items: end;
52
+ }
53
+
54
+ spaday-regular-layout.spa regular-layout-frame::part(tab) {
55
+ box-sizing: border-box;
56
+ align-items: center;
57
+ justify-content: center;
58
+ font-size: 12px;
59
+ padding: 0 10px;
60
+ margin-right: 2px;
61
+ cursor: pointer;
62
+ border: 1px solid var(--spa-rl-border);
63
+ border-bottom: none;
64
+ border-radius: 8px 8px 0 0;
65
+ background: var(--spa-rl-surface-2);
66
+ color: var(--spa-rl-muted);
67
+ }
68
+
69
+ spaday-regular-layout.spa regular-layout-frame::part(title) {
70
+ overflow: hidden;
71
+ text-overflow: ellipsis;
72
+ white-space: nowrap;
73
+ }
74
+
75
+ /* The active tab shares the container's surface so the two read as one panel. */
76
+ spaday-regular-layout.spa regular-layout-frame::part(active-tab) {
77
+ background: var(--spa-rl-surface);
78
+ color: inherit;
79
+ }
80
+
81
+ spaday-regular-layout.spa regular-layout-frame::part(close) {
82
+ border: none;
83
+ border-radius: 4px;
84
+ background: transparent;
85
+ color: var(--spa-rl-muted);
86
+ cursor: pointer;
87
+ /* The engine renders the close control as an empty <button>; without an
88
+ * explicit glyph and box it collapses to nothing. */
89
+ width: 16px;
90
+ height: 14px;
91
+ padding: 0;
92
+ font-size: 13px;
93
+ line-height: 13px;
94
+ align-self: center;
95
+ }
96
+
97
+ spaday-regular-layout.spa regular-layout-frame::part(close)::before {
98
+ content: "\00d7";
99
+ }
100
+
101
+ spaday-regular-layout.spa regular-layout-frame::part(close):hover {
102
+ transition: background-color 0.2s;
103
+ background-color: var(--spa-rl-surface-2);
104
+ }
105
+
106
+ /* While dragging, dim the settled frames and accent the floating one. */
107
+ spaday-regular-layout.spa:has(.overlay) > * {
108
+ opacity: 0.6;
109
+ }
110
+
111
+ spaday-regular-layout.spa:has(.overlay) > .overlay {
112
+ opacity: 1;
113
+ }
114
+
115
+ spaday-regular-layout.spa regular-layout-frame.overlay {
116
+ background: var(--spa-rl-surface-2);
117
+ border: 1px dashed var(--spa-rl-border);
118
+ border-radius: 8px;
119
+ transition:
120
+ top 0.1s ease-in-out,
121
+ height 0.1s ease-in-out,
122
+ width 0.1s ease-in-out,
123
+ left 0.1s ease-in-out;
124
+ }
@@ -7,6 +7,7 @@
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
8
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
9
9
  <link rel="stylesheet" type="text/css" href="css/lorax.css" />
10
+ <link rel="stylesheet" type="text/css" href="css/spa.css" />
10
11
  <script type="module" src="cdn/index.js"></script>
11
12
  </head>
12
13
  <body></body>
@@ -0,0 +1,25 @@
1
+ /** Tolerate another bundle having already registered the engine's custom elements.
2
+ *
3
+ * Perspective 5's viewer bundles the same `regular-layout` engine and registers
4
+ * `regular-layout` / `regular-layout-frame` / `regular-layout-tab` at import. Whichever
5
+ * bundle loads second would throw from `customElements.define` and die entirely —
6
+ * taking the `spaday-regular-layout` wrapper with it. Importing this module FIRST makes
7
+ * `define` idempotent (skip names that already exist); `restoreDefine()` puts the real
8
+ * one back immediately after the engine import, so the guard never leaks to other
9
+ * scripts. Both bundles pin the engine to the same exact version, so adopting the other
10
+ * copy's registration is adopting identical code.
11
+ */
12
+
13
+ const original = customElements.define.bind(customElements);
14
+
15
+ customElements.define = (
16
+ name: string,
17
+ ctor: CustomElementConstructor,
18
+ options?: ElementDefinitionOptions,
19
+ ) => {
20
+ if (!customElements.get(name)) original(name, ctor, options);
21
+ };
22
+
23
+ export function restoreDefine(): void {
24
+ customElements.define = original;
25
+ }
@@ -1,13 +1,42 @@
1
+ // the guard must execute before the engine module registers its elements
2
+ import { restoreDefine } from "./define-guard";
1
3
  import {
2
4
  RegularLayout as BaseRegularLayout,
3
5
  type Layout,
4
6
  } from "regular-layout";
5
7
 
8
+ restoreDefine();
9
+
6
10
  /** A regular-layout whose saved layout tree can be assigned as a spaday prop. */
7
11
  export class SpadayRegularLayout extends BaseRegularLayout {
8
12
  #pendingLayout: Layout | null = null;
9
13
  #restoring = 0;
10
14
 
15
+ constructor() {
16
+ super();
17
+ // Frames drive drag-rearranging through these two instance methods; a
18
+ // locked layout swallows them so tabs still select and close but panels
19
+ // cannot be dragged into new positions.
20
+ const setOverlay = this.setOverlayState;
21
+ const clearOverlay = this.clearOverlayState;
22
+ this.setOverlayState = async (...args) => {
23
+ if (this.locked) return;
24
+ return setOverlay(...args);
25
+ };
26
+ this.clearOverlayState = async (...args) => {
27
+ if (this.locked) return;
28
+ return clearOverlay(...args);
29
+ };
30
+ }
31
+
32
+ get locked(): boolean {
33
+ return this.hasAttribute("locked");
34
+ }
35
+
36
+ set locked(value: boolean) {
37
+ this.toggleAttribute("locked", Boolean(value));
38
+ }
39
+
11
40
  connectedCallback(): void {
12
41
  this.#restoring += 1;
13
42
  super.connectedCallback();