dsh-cait 1.0.3 → 1.0.4

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/client/helpers.js CHANGED
@@ -1,103 +1,103 @@
1
- const API = '/cait/api/rpc'
2
- const SYNC_POLL_MS = 2000
3
-
4
- // Only the last mounted library must stay checked. An unmounted library is
5
- // always selectable, even when that is currently the only mounted one.
6
- function isMountToggleDisabled({ mounted, mountedCount, busy = false } = {}) {
7
- return Boolean(busy) || (Boolean(mounted) && Number(mountedCount) <= 1)
8
- }
9
-
10
- function computeNextMountIds(currentIds, id, checked) {
11
- const current = Array.isArray(currentIds) ? currentIds : []
12
- if (!checked && current.length <= 1) return null
13
- return checked
14
- ? [...new Set([...current, id])]
15
- : current.filter((item) => item !== id)
16
- }
17
-
18
- // A dirty draft wins over a remote snapshot; the banner asks the user to
19
- // save/refresh instead of silently replacing their text.
20
- function shouldAdoptRemote({ currentRevision, nextRevision, dirty = false } = {}) {
21
- return !dirty && Number(nextRevision) !== Number(currentRevision)
22
- }
23
-
24
- const LANGUAGES = [
25
- ['en', 'English'],
26
- ['zh-CN', '简体中文'],
27
- ['zh-TW', '繁體中文'],
28
- ['ja', '日本語'],
29
- ['ko', '한국어'],
30
- ['fr', 'Français'],
31
- ['de', 'Deutsch'],
32
- ['es', 'Español'],
33
- ['pt', 'Português'],
34
- ['ru', 'Русский'],
35
- ['ar', 'العربية'],
36
- ['it', 'Italiano'],
37
- ]
38
-
39
- // --- UI scaling ---------------------------------------------------------
40
- // styles.js is authored in fixed CSS pixels, which makes the workbench look
41
- // undersized next to the rest of DSH once the window is maximized. Every
42
- // length is therefore rewritten as `calc(<n>px * var(--cait-u))` and
43
- // --cait-u (a unitless multiplier) tracks the size of the panel.
44
- const CAIT_UNIT_VAR = '--cait-u'
45
- // The designed density is calibrated for roughly 1100×680 CSS pixels of
46
- // DSH panel area. Fullscreen/maximized windows on 1440p and 4K displays
47
- // were still capped at 1.4× with the old 1320×800 base, which left the
48
- // 13px body type visibly smaller than the surrounding DSH UI. Keep the
49
- // height term so short windows do not overflow, but let large panels grow
50
- // to 1.8× before the cap applies.
51
- const CAIT_UI_BASE = { width: 1100, height: 680 }
52
- const CAIT_UI_MIN_UNIT = 1
53
- const CAIT_UI_MAX_UNIT = 1.8
54
-
55
- // Grow with the panel but never shrink below the designed size; the height
56
- // term keeps short/wide windows from becoming oversized and scroll-heavy.
57
- function computeCaitUnit({ width, height } = {}) {
58
- const w = Number(width)
59
- const h = Number(height)
60
- if (!(w > 0) || !(h > 0)) return CAIT_UI_MIN_UNIT
61
- const fit = Math.min(w / CAIT_UI_BASE.width, h / CAIT_UI_BASE.height)
62
- const unit = Math.min(CAIT_UI_MAX_UNIT, Math.max(CAIT_UI_MIN_UNIT, fit))
63
- return Math.round(unit * 1000) / 1000
64
- }
65
-
66
- const CSS_PX_RE = /(-?(?:\d+\.?\d*|\.\d+))px/g
67
-
68
- function scaleCssChunk(chunk, unitVar) {
69
- return chunk.replace(CSS_PX_RE, (whole, value) => {
70
- // Hairlines stay exactly 1px so borders keep rendering crisply.
71
- if (Math.abs(Number(value)) <= 1) return whole
72
- return `calc(${value}px * var(${unitVar}, 1))`
73
- })
74
- }
75
-
76
- // Scale declaration values only. Media/supports/container preludes are
77
- // copied verbatim: var() is not allowed in a media condition and those
78
- // breakpoints must keep matching viewport pixels.
79
- function scaleCssLengths(css, unitVar = CAIT_UNIT_VAR) {
80
- const source = String(css ?? '')
81
- let output = ''
82
- let index = 0
83
- while (index < source.length) {
84
- const at = source.indexOf('@', index)
85
- if (at === -1) {
86
- output += scaleCssChunk(source.slice(index), unitVar)
87
- break
88
- }
89
- output += scaleCssChunk(source.slice(index, at), unitVar)
90
- let cursor = at
91
- let depth = 0
92
- while (cursor < source.length) {
93
- const ch = source[cursor]
94
- if (ch === '(') depth += 1
95
- else if (ch === ')') depth = Math.max(0, depth - 1)
96
- else if (depth === 0 && (ch === '{' || ch === ';')) break
97
- cursor += 1
98
- }
99
- output += source.slice(at, cursor + 1)
100
- index = cursor + 1
101
- }
102
- return output
103
- }
1
+ const API = '/cait/api/rpc'
2
+ const SYNC_POLL_MS = 2000
3
+
4
+ // Only the last mounted library must stay checked. An unmounted library is
5
+ // always selectable, even when that is currently the only mounted one.
6
+ function isMountToggleDisabled({ mounted, mountedCount, busy = false } = {}) {
7
+ return Boolean(busy) || (Boolean(mounted) && Number(mountedCount) <= 1)
8
+ }
9
+
10
+ function computeNextMountIds(currentIds, id, checked) {
11
+ const current = Array.isArray(currentIds) ? currentIds : []
12
+ if (!checked && current.length <= 1) return null
13
+ return checked
14
+ ? [...new Set([...current, id])]
15
+ : current.filter((item) => item !== id)
16
+ }
17
+
18
+ // A dirty draft wins over a remote snapshot; the banner asks the user to
19
+ // save/refresh instead of silently replacing their text.
20
+ function shouldAdoptRemote({ currentRevision, nextRevision, dirty = false } = {}) {
21
+ return !dirty && Number(nextRevision) !== Number(currentRevision)
22
+ }
23
+
24
+ const LANGUAGES = [
25
+ ['en', 'English'],
26
+ ['zh-CN', '简体中文'],
27
+ ['zh-TW', '繁體中文'],
28
+ ['ja', '日本語'],
29
+ ['ko', '한국어'],
30
+ ['fr', 'Français'],
31
+ ['de', 'Deutsch'],
32
+ ['es', 'Español'],
33
+ ['pt', 'Português'],
34
+ ['ru', 'Русский'],
35
+ ['ar', 'العربية'],
36
+ ['it', 'Italiano'],
37
+ ]
38
+
39
+ // --- UI scaling ---------------------------------------------------------
40
+ // styles.js is authored in fixed CSS pixels, which makes the workbench look
41
+ // undersized next to the rest of DSH once the window is maximized. Every
42
+ // length is therefore rewritten as `calc(<n>px * var(--cait-u))` and
43
+ // --cait-u (a unitless multiplier) tracks the size of the panel.
44
+ const CAIT_UNIT_VAR = '--cait-u'
45
+ // The designed density is calibrated for roughly 1100×680 CSS pixels of
46
+ // DSH panel area. Fullscreen/maximized windows on 1440p and 4K displays
47
+ // were still capped at 1.4× with the old 1320×800 base, which left the
48
+ // 13px body type visibly smaller than the surrounding DSH UI. Keep the
49
+ // height term so short windows do not overflow, but let large panels grow
50
+ // to 1.8× before the cap applies.
51
+ const CAIT_UI_BASE = { width: 1100, height: 680 }
52
+ const CAIT_UI_MIN_UNIT = 1
53
+ const CAIT_UI_MAX_UNIT = 1.8
54
+
55
+ // Grow with the panel but never shrink below the designed size; the height
56
+ // term keeps short/wide windows from becoming oversized and scroll-heavy.
57
+ function computeCaitUnit({ width, height } = {}) {
58
+ const w = Number(width)
59
+ const h = Number(height)
60
+ if (!(w > 0) || !(h > 0)) return CAIT_UI_MIN_UNIT
61
+ const fit = Math.min(w / CAIT_UI_BASE.width, h / CAIT_UI_BASE.height)
62
+ const unit = Math.min(CAIT_UI_MAX_UNIT, Math.max(CAIT_UI_MIN_UNIT, fit))
63
+ return Math.round(unit * 1000) / 1000
64
+ }
65
+
66
+ const CSS_PX_RE = /(-?(?:\d+\.?\d*|\.\d+))px/g
67
+
68
+ function scaleCssChunk(chunk, unitVar) {
69
+ return chunk.replace(CSS_PX_RE, (whole, value) => {
70
+ // Hairlines stay exactly 1px so borders keep rendering crisply.
71
+ if (Math.abs(Number(value)) <= 1) return whole
72
+ return `calc(${value}px * var(${unitVar}, 1))`
73
+ })
74
+ }
75
+
76
+ // Scale declaration values only. Media/supports/container preludes are
77
+ // copied verbatim: var() is not allowed in a media condition and those
78
+ // breakpoints must keep matching viewport pixels.
79
+ function scaleCssLengths(css, unitVar = CAIT_UNIT_VAR) {
80
+ const source = String(css ?? '')
81
+ let output = ''
82
+ let index = 0
83
+ while (index < source.length) {
84
+ const at = source.indexOf('@', index)
85
+ if (at === -1) {
86
+ output += scaleCssChunk(source.slice(index), unitVar)
87
+ break
88
+ }
89
+ output += scaleCssChunk(source.slice(index, at), unitVar)
90
+ let cursor = at
91
+ let depth = 0
92
+ while (cursor < source.length) {
93
+ const ch = source[cursor]
94
+ if (ch === '(') depth += 1
95
+ else if (ch === ')') depth = Math.max(0, depth - 1)
96
+ else if (depth === 0 && (ch === '{' || ch === ';')) break
97
+ cursor += 1
98
+ }
99
+ output += source.slice(at, cursor + 1)
100
+ index = cursor + 1
101
+ }
102
+ return output
103
+ }