ds-one 0.3.0-alpha.1 → 0.3.0-alpha.2

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. package/DS1/0-face/device.ts +180 -34
  2. package/DS1/1-root/one.css +1 -1
  3. package/DS1/index.ts +0 -1
  4. package/README.md +2 -2
  5. package/dist/0-face/device.d.ts +47 -1
  6. package/dist/0-face/device.d.ts.map +1 -1
  7. package/dist/0-face/device.js +132 -25
  8. package/dist/ds-one.bundle.js +1421 -1436
  9. package/dist/ds-one.bundle.js.map +1 -1
  10. package/dist/ds-one.bundle.min.js +1206 -1217
  11. package/dist/ds-one.bundle.min.js.map +1 -1
  12. package/dist/index.d.ts +0 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +0 -1
  15. package/package.json +1 -1
  16. package/DS1/0-face/scaling.ts +0 -152
  17. package/dist/0-face/scaling.d.ts +0 -48
  18. package/dist/0-face/scaling.d.ts.map +0 -1
  19. package/dist/0-face/scaling.js +0 -114
  20. package/dist/2-core/styles/ds-banner.css +0 -77
  21. package/dist/2-core/styles/ds-button.css +0 -67
  22. package/dist/2-core/styles/ds-cycle.css +0 -21
  23. package/dist/2-core/styles/ds-date.css +0 -9
  24. package/dist/2-core/styles/ds-gap.css +0 -93
  25. package/dist/2-core/styles/ds-icon.css +0 -30
  26. package/dist/2-core/styles/ds-input.css +0 -46
  27. package/dist/2-core/styles/ds-pagedots.css +0 -26
  28. package/dist/2-core/styles/ds-text.css +0 -29
  29. package/dist/2-core/styles/ds-tooltip.css +0 -49
  30. package/dist/3-unit/styles/ds-accordion.css +0 -46
  31. package/dist/3-unit/styles/ds-list.css +0 -9
  32. package/dist/3-unit/styles/ds-row.css +0 -19
  33. package/dist/3-unit/styles/ds-table.css +0 -80
  34. package/dist/4-page/styles/ds-container.css +0 -35
  35. package/dist/4-page/styles/ds-grid.css +0 -56
  36. package/dist/4-page/styles/ds-layout.css +0 -251
  37. package/dist/ds-one.bundle.css +0 -700
  38. package/dist/ds-one.bundle.css.map +0 -7
  39. package/dist/ds-one.bundle.min.css +0 -2
  40. package/dist/ds-one.bundle.min.css.map +0 -7
@@ -1,5 +1,11 @@
1
- // 2025-04-23-device.ts
2
- // Device detection and context utilities
1
+ // device.ts
2
+ // Device detection, context utilities, and responsive scaling
3
+
4
+ import { signal } from "@lit-labs/signals";
5
+
6
+ // ============================================================================
7
+ // Types
8
+ // ============================================================================
3
9
 
4
10
  export type DeviceType = "mobile" | "tablet" | "desktop";
5
11
 
@@ -14,6 +20,36 @@ export interface DeviceInfo {
14
20
  screenHeight: number;
15
21
  }
16
22
 
23
+ export type ScalingMode = "auto" | "fixed" | "fluid";
24
+
25
+ export interface ScalingConfig {
26
+ mode: ScalingMode;
27
+ baseWidth: number;
28
+ minScale: number;
29
+ maxScale: number;
30
+ }
31
+
32
+ // ============================================================================
33
+ // Configuration & Signals
34
+ // ============================================================================
35
+
36
+ const defaultScalingConfig: ScalingConfig = {
37
+ mode: "auto",
38
+ baseWidth: 280,
39
+ minScale: 0.75,
40
+ maxScale: 2.0,
41
+ };
42
+
43
+ /** Reactive scaling factor signal */
44
+ export const scalingFactor = signal<number>(1);
45
+
46
+ /** Current scaling configuration */
47
+ export const scalingConfig = signal<ScalingConfig>(defaultScalingConfig);
48
+
49
+ // ============================================================================
50
+ // Device Detection
51
+ // ============================================================================
52
+
17
53
  /**
18
54
  * Comprehensive mobile device detection
19
55
  * Combines user agent detection, touch capability, and viewport size
@@ -80,48 +116,148 @@ export function getDeviceInfo(): DeviceInfo {
80
116
  };
81
117
  }
82
118
 
119
+ // ============================================================================
120
+ // Scaling
121
+ // ============================================================================
122
+
123
+ /**
124
+ * Calculate the scaling factor based on viewport width
125
+ * @param viewportWidth - Current viewport width in pixels
126
+ * @param config - Scaling configuration
127
+ * @returns The calculated scaling factor
128
+ */
129
+ export function calculateScalingFactor(
130
+ viewportWidth: number,
131
+ config: ScalingConfig = scalingConfig.get()
132
+ ): number {
133
+ if (config.mode === "fixed") {
134
+ return 1;
135
+ }
136
+
137
+ const rawScale = viewportWidth / config.baseWidth;
138
+ const clampedScale = Math.max(
139
+ config.minScale,
140
+ Math.min(config.maxScale, rawScale)
141
+ );
142
+
143
+ return Number(clampedScale.toFixed(3));
144
+ }
145
+
146
+ /**
147
+ * Set the scaling configuration
148
+ * @param config - Partial scaling configuration to apply
149
+ */
150
+ export function setScalingConfig(config: Partial<ScalingConfig>): void {
151
+ const currentConfig = scalingConfig.get();
152
+ const newConfig = { ...currentConfig, ...config };
153
+ scalingConfig.set(newConfig);
154
+
155
+ // Recalculate scaling factor if in browser
156
+ if (typeof window !== "undefined") {
157
+ updateScalingFactor();
158
+ }
159
+ }
160
+
83
161
  /**
84
- * Initialize device detection and log to console
162
+ * Update the scaling factor based on current viewport
163
+ * Desktop always uses factor 1; mobile uses computed factor
164
+ */
165
+ export function updateScalingFactor(): void {
166
+ if (typeof window === "undefined" || typeof document === "undefined") {
167
+ return;
168
+ }
169
+
170
+ const isMobile = detectMobileDevice();
171
+
172
+ // Desktop: always use factor 1
173
+ if (!isMobile) {
174
+ const factor = 1;
175
+ scalingFactor.set(factor);
176
+ document.documentElement.style.setProperty("--sf", factor.toString());
177
+ window.dispatchEvent(
178
+ new CustomEvent("scaling-changed", {
179
+ detail: { scalingFactor: factor, config: scalingConfig.get() },
180
+ })
181
+ );
182
+ return;
183
+ }
184
+
185
+ // Mobile: compute scaling based on viewport
186
+ const viewportWidth = document.documentElement.clientWidth;
187
+ const config = scalingConfig.get();
188
+ const newFactor = calculateScalingFactor(viewportWidth, config);
189
+
190
+ scalingFactor.set(newFactor);
191
+ document.documentElement.style.setProperty("--sf", newFactor.toString());
192
+
193
+ window.dispatchEvent(
194
+ new CustomEvent("scaling-changed", {
195
+ detail: { scalingFactor: newFactor, config },
196
+ })
197
+ );
198
+ }
199
+
200
+ /**
201
+ * Get the current scaling factor
202
+ * @returns The current scaling factor
203
+ */
204
+ export function getScalingFactor(): number {
205
+ return scalingFactor.get();
206
+ }
207
+
208
+ /**
209
+ * Convert a design pixel value to scaled pixels
210
+ * @param designPx - The design pixel value (based on 280px width)
211
+ * @returns The scaled pixel value
212
+ */
213
+ export function scale(designPx: number): number {
214
+ return designPx * scalingFactor.get();
215
+ }
216
+
217
+ /**
218
+ * Convert a scaled pixel value back to design pixels
219
+ * @param scaledPx - The scaled pixel value
220
+ * @returns The design pixel value
221
+ */
222
+ export function unscale(scaledPx: number): number {
223
+ const factor = scalingFactor.get();
224
+ return factor === 0 ? scaledPx : scaledPx / factor;
225
+ }
226
+
227
+ // ============================================================================
228
+ // Unified Initialization
229
+ // ============================================================================
230
+
231
+ /**
232
+ * Initialize device detection and scaling
233
+ * Sets CSS classes (.mobile/.desktop) and --sf custom property
85
234
  */
86
235
  export function initDeviceDetection(): DeviceInfo {
87
236
  const deviceInfo = getDeviceInfo();
88
237
 
89
- // Calculate and set scaling factor for mobile
90
- if (deviceInfo.isMobile && typeof document !== "undefined") {
91
- // Design width: 280px (14 columns × 20px)
92
- const designWidth = 280;
93
- const actualWidth = deviceInfo.screenWidth;
94
- const scalingFactor = actualWidth / designWidth;
95
-
96
- // Set CSS custom property for scaling on html element
97
- document.documentElement.style.setProperty(
98
- "--sf",
99
- scalingFactor.toFixed(3)
100
- );
101
- // Also set --sf for backwards compatibility
102
- document.documentElement.style.setProperty(
103
- "--sf",
104
- scalingFactor.toFixed(3)
105
- );
238
+ if (typeof document === "undefined") {
239
+ return deviceInfo;
240
+ }
106
241
 
107
- // Add .mobile class to html element for CSS targeting
242
+ // Set device class on html element
243
+ if (deviceInfo.isMobile) {
108
244
  document.documentElement.classList.add("mobile");
109
245
  document.documentElement.classList.remove("desktop");
246
+ } else {
247
+ document.documentElement.classList.add("desktop");
248
+ document.documentElement.classList.remove("mobile");
249
+ }
110
250
 
251
+ // Update scaling factor (handles --sf CSS property)
252
+ updateScalingFactor();
253
+
254
+ // Log device info
255
+ const factor = scalingFactor.get();
256
+ if (deviceInfo.isMobile) {
111
257
  console.log(
112
- `[DS one] Mobile device detected - ${deviceInfo.deviceType} (${deviceInfo.screenWidth}x${deviceInfo.screenHeight}), scaling factor: ${scalingFactor.toFixed(2)}`
258
+ `[DS one] Mobile device detected - ${deviceInfo.deviceType} (${deviceInfo.screenWidth}x${deviceInfo.screenHeight}), scaling factor: ${factor.toFixed(2)}`
113
259
  );
114
260
  } else {
115
- // Desktop - no scaling
116
- if (typeof document !== "undefined") {
117
- document.documentElement.style.setProperty("--sf", "1");
118
- // Also set --sf for backwards compatibility
119
- document.documentElement.style.setProperty("--sf", "1");
120
-
121
- // Add .desktop class and remove .mobile class
122
- document.documentElement.classList.add("desktop");
123
- document.documentElement.classList.remove("mobile");
124
- }
125
261
  console.log(
126
262
  `[DS one] Desktop device detected (${deviceInfo.screenWidth}x${deviceInfo.screenHeight})`
127
263
  );
@@ -136,6 +272,7 @@ export function initDeviceDetection(): DeviceInfo {
136
272
  isDesktop: deviceInfo.isDesktop,
137
273
  isTouchCapable: deviceInfo.isTouchCapable,
138
274
  viewport: `${deviceInfo.screenWidth}x${deviceInfo.screenHeight}`,
275
+ scalingFactor: factor,
139
276
  userAgent: deviceInfo.userAgent,
140
277
  });
141
278
  }
@@ -155,16 +292,25 @@ if (typeof window !== "undefined") {
155
292
  initDeviceDetection();
156
293
  }
157
294
 
158
- // Recalculate on resize (debounced)
159
- let resizeTimeout: any;
295
+ // Single debounced resize handler for both device detection + scaling
296
+ let resizeTimeout: ReturnType<typeof setTimeout>;
160
297
  window.addEventListener("resize", () => {
161
298
  clearTimeout(resizeTimeout);
162
299
  resizeTimeout = setTimeout(() => {
163
300
  initDeviceDetection();
164
301
  }, 100);
165
302
  });
303
+
304
+ // Also handle orientation change
305
+ window.addEventListener("orientationchange", () => {
306
+ setTimeout(initDeviceDetection, 100);
307
+ });
166
308
  }
167
309
 
310
+ // ============================================================================
311
+ // App-like Behavior
312
+ // ============================================================================
313
+
168
314
  /**
169
315
  * Disable double-tap to zoom in the browser (app-like behavior)
170
316
  * Prevents all zoom gestures including double-tap and pinch-to-zoom
@@ -1,4 +1,4 @@
1
- /* version 0.3.0-alpha.1 */
1
+ /* version 0.3.0-alpha.2 */
2
2
 
3
3
  @import url("https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@200");
4
4
  @import url("https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@800");
package/DS1/index.ts CHANGED
@@ -23,7 +23,6 @@ export * from "./0-face/device";
23
23
  export * from "./0-face/i18n";
24
24
  export * from "./0-face/preferences";
25
25
  export * from "./0-face/pricing";
26
- export * from "./0-face/scaling";
27
26
  export * from "./0-face/theme";
28
27
 
29
28
  // ============================================================================
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # DS one (0.3.0-alpha.1)
1
+ # DS one (0.3.0-alpha.2)
2
2
 
3
3
  A plug and play design system
4
4
 
@@ -20,7 +20,7 @@ yarn add ds-one@alpha
20
20
 
21
21
  ```
22
22
 
23
- **Note**: Currently published as alpha version `0.3.0-alpha.1`
23
+ **Note**: Currently published as alpha version `0.3.0-alpha.2`
24
24
 
25
25
  ## Quick Start
26
26
 
@@ -9,6 +9,17 @@ export interface DeviceInfo {
9
9
  screenWidth: number;
10
10
  screenHeight: number;
11
11
  }
12
+ export type ScalingMode = "auto" | "fixed" | "fluid";
13
+ export interface ScalingConfig {
14
+ mode: ScalingMode;
15
+ baseWidth: number;
16
+ minScale: number;
17
+ maxScale: number;
18
+ }
19
+ /** Reactive scaling factor signal */
20
+ export declare const scalingFactor: import("@lit-labs/signals").Signal.State<number>;
21
+ /** Current scaling configuration */
22
+ export declare const scalingConfig: import("@lit-labs/signals").Signal.State<ScalingConfig>;
12
23
  /**
13
24
  * Comprehensive mobile device detection
14
25
  * Combines user agent detection, touch capability, and viewport size
@@ -19,7 +30,42 @@ export declare function detectMobileDevice(): boolean;
19
30
  */
20
31
  export declare function getDeviceInfo(): DeviceInfo;
21
32
  /**
22
- * Initialize device detection and log to console
33
+ * Calculate the scaling factor based on viewport width
34
+ * @param viewportWidth - Current viewport width in pixels
35
+ * @param config - Scaling configuration
36
+ * @returns The calculated scaling factor
37
+ */
38
+ export declare function calculateScalingFactor(viewportWidth: number, config?: ScalingConfig): number;
39
+ /**
40
+ * Set the scaling configuration
41
+ * @param config - Partial scaling configuration to apply
42
+ */
43
+ export declare function setScalingConfig(config: Partial<ScalingConfig>): void;
44
+ /**
45
+ * Update the scaling factor based on current viewport
46
+ * Desktop always uses factor 1; mobile uses computed factor
47
+ */
48
+ export declare function updateScalingFactor(): void;
49
+ /**
50
+ * Get the current scaling factor
51
+ * @returns The current scaling factor
52
+ */
53
+ export declare function getScalingFactor(): number;
54
+ /**
55
+ * Convert a design pixel value to scaled pixels
56
+ * @param designPx - The design pixel value (based on 280px width)
57
+ * @returns The scaled pixel value
58
+ */
59
+ export declare function scale(designPx: number): number;
60
+ /**
61
+ * Convert a scaled pixel value back to design pixels
62
+ * @param scaledPx - The scaled pixel value
63
+ * @returns The design pixel value
64
+ */
65
+ export declare function unscale(scaledPx: number): number;
66
+ /**
67
+ * Initialize device detection and scaling
68
+ * Sets CSS classes (.mobile/.desktop) and --sf custom property
23
69
  */
24
70
  export declare function initDeviceDetection(): DeviceInfo;
25
71
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../DS1/0-face/device.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEzD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CA0B5C;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,UAAU,CA6B1C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,UAAU,CA0DhD;AAwBD;;;GAGG;AACH,wBAAgB,OAAO,IAAI,IAAI,CA4H9B"}
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../DS1/0-face/device.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEzD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAaD,qCAAqC;AACrC,eAAO,MAAM,aAAa,kDAAoB,CAAC;AAE/C,oCAAoC;AACpC,eAAO,MAAM,aAAa,yDAA8C,CAAC;AAMzE;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CA0B5C;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,UAAU,CA6B1C;AAMD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,EACrB,MAAM,GAAE,aAAmC,GAC1C,MAAM,CAYR;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CASrE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAiC1C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGhD;AAMD;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,UAAU,CA8ChD;AAiCD;;;GAGG;AACH,wBAAgB,OAAO,IAAI,IAAI,CA4H9B"}
@@ -1,5 +1,22 @@
1
- // 2025-04-23-device.ts
2
- // Device detection and context utilities
1
+ // device.ts
2
+ // Device detection, context utilities, and responsive scaling
3
+ import { signal } from "@lit-labs/signals";
4
+ // ============================================================================
5
+ // Configuration & Signals
6
+ // ============================================================================
7
+ const defaultScalingConfig = {
8
+ mode: "auto",
9
+ baseWidth: 280,
10
+ minScale: 0.75,
11
+ maxScale: 2.0,
12
+ };
13
+ /** Reactive scaling factor signal */
14
+ export const scalingFactor = signal(1);
15
+ /** Current scaling configuration */
16
+ export const scalingConfig = signal(defaultScalingConfig);
17
+ // ============================================================================
18
+ // Device Detection
19
+ // ============================================================================
3
20
  /**
4
21
  * Comprehensive mobile device detection
5
22
  * Combines user agent detection, touch capability, and viewport size
@@ -50,36 +67,118 @@ export function getDeviceInfo() {
50
67
  screenHeight,
51
68
  };
52
69
  }
70
+ // ============================================================================
71
+ // Scaling
72
+ // ============================================================================
53
73
  /**
54
- * Initialize device detection and log to console
74
+ * Calculate the scaling factor based on viewport width
75
+ * @param viewportWidth - Current viewport width in pixels
76
+ * @param config - Scaling configuration
77
+ * @returns The calculated scaling factor
78
+ */
79
+ export function calculateScalingFactor(viewportWidth, config = scalingConfig.get()) {
80
+ if (config.mode === "fixed") {
81
+ return 1;
82
+ }
83
+ const rawScale = viewportWidth / config.baseWidth;
84
+ const clampedScale = Math.max(config.minScale, Math.min(config.maxScale, rawScale));
85
+ return Number(clampedScale.toFixed(3));
86
+ }
87
+ /**
88
+ * Set the scaling configuration
89
+ * @param config - Partial scaling configuration to apply
90
+ */
91
+ export function setScalingConfig(config) {
92
+ const currentConfig = scalingConfig.get();
93
+ const newConfig = { ...currentConfig, ...config };
94
+ scalingConfig.set(newConfig);
95
+ // Recalculate scaling factor if in browser
96
+ if (typeof window !== "undefined") {
97
+ updateScalingFactor();
98
+ }
99
+ }
100
+ /**
101
+ * Update the scaling factor based on current viewport
102
+ * Desktop always uses factor 1; mobile uses computed factor
103
+ */
104
+ export function updateScalingFactor() {
105
+ if (typeof window === "undefined" || typeof document === "undefined") {
106
+ return;
107
+ }
108
+ const isMobile = detectMobileDevice();
109
+ // Desktop: always use factor 1
110
+ if (!isMobile) {
111
+ const factor = 1;
112
+ scalingFactor.set(factor);
113
+ document.documentElement.style.setProperty("--sf", factor.toString());
114
+ window.dispatchEvent(new CustomEvent("scaling-changed", {
115
+ detail: { scalingFactor: factor, config: scalingConfig.get() },
116
+ }));
117
+ return;
118
+ }
119
+ // Mobile: compute scaling based on viewport
120
+ const viewportWidth = document.documentElement.clientWidth;
121
+ const config = scalingConfig.get();
122
+ const newFactor = calculateScalingFactor(viewportWidth, config);
123
+ scalingFactor.set(newFactor);
124
+ document.documentElement.style.setProperty("--sf", newFactor.toString());
125
+ window.dispatchEvent(new CustomEvent("scaling-changed", {
126
+ detail: { scalingFactor: newFactor, config },
127
+ }));
128
+ }
129
+ /**
130
+ * Get the current scaling factor
131
+ * @returns The current scaling factor
132
+ */
133
+ export function getScalingFactor() {
134
+ return scalingFactor.get();
135
+ }
136
+ /**
137
+ * Convert a design pixel value to scaled pixels
138
+ * @param designPx - The design pixel value (based on 280px width)
139
+ * @returns The scaled pixel value
140
+ */
141
+ export function scale(designPx) {
142
+ return designPx * scalingFactor.get();
143
+ }
144
+ /**
145
+ * Convert a scaled pixel value back to design pixels
146
+ * @param scaledPx - The scaled pixel value
147
+ * @returns The design pixel value
148
+ */
149
+ export function unscale(scaledPx) {
150
+ const factor = scalingFactor.get();
151
+ return factor === 0 ? scaledPx : scaledPx / factor;
152
+ }
153
+ // ============================================================================
154
+ // Unified Initialization
155
+ // ============================================================================
156
+ /**
157
+ * Initialize device detection and scaling
158
+ * Sets CSS classes (.mobile/.desktop) and --sf custom property
55
159
  */
56
160
  export function initDeviceDetection() {
57
161
  const deviceInfo = getDeviceInfo();
58
- // Calculate and set scaling factor for mobile
59
- if (deviceInfo.isMobile && typeof document !== "undefined") {
60
- // Design width: 280px (14 columns × 20px)
61
- const designWidth = 280;
62
- const actualWidth = deviceInfo.screenWidth;
63
- const scalingFactor = actualWidth / designWidth;
64
- // Set CSS custom property for scaling on html element
65
- document.documentElement.style.setProperty("--sf", scalingFactor.toFixed(3));
66
- // Also set --sf for backwards compatibility
67
- document.documentElement.style.setProperty("--sf", scalingFactor.toFixed(3));
68
- // Add .mobile class to html element for CSS targeting
162
+ if (typeof document === "undefined") {
163
+ return deviceInfo;
164
+ }
165
+ // Set device class on html element
166
+ if (deviceInfo.isMobile) {
69
167
  document.documentElement.classList.add("mobile");
70
168
  document.documentElement.classList.remove("desktop");
71
- console.log(`[DS one] Mobile device detected - ${deviceInfo.deviceType} (${deviceInfo.screenWidth}x${deviceInfo.screenHeight}), scaling factor: ${scalingFactor.toFixed(2)}`);
72
169
  }
73
170
  else {
74
- // Desktop - no scaling
75
- if (typeof document !== "undefined") {
76
- document.documentElement.style.setProperty("--sf", "1");
77
- // Also set --sf for backwards compatibility
78
- document.documentElement.style.setProperty("--sf", "1");
79
- // Add .desktop class and remove .mobile class
80
- document.documentElement.classList.add("desktop");
81
- document.documentElement.classList.remove("mobile");
82
- }
171
+ document.documentElement.classList.add("desktop");
172
+ document.documentElement.classList.remove("mobile");
173
+ }
174
+ // Update scaling factor (handles --sf CSS property)
175
+ updateScalingFactor();
176
+ // Log device info
177
+ const factor = scalingFactor.get();
178
+ if (deviceInfo.isMobile) {
179
+ console.log(`[DS one] Mobile device detected - ${deviceInfo.deviceType} (${deviceInfo.screenWidth}x${deviceInfo.screenHeight}), scaling factor: ${factor.toFixed(2)}`);
180
+ }
181
+ else {
83
182
  console.log(`[DS one] Desktop device detected (${deviceInfo.screenWidth}x${deviceInfo.screenHeight})`);
84
183
  }
85
184
  // Log additional details in development mode
@@ -91,6 +190,7 @@ export function initDeviceDetection() {
91
190
  isDesktop: deviceInfo.isDesktop,
92
191
  isTouchCapable: deviceInfo.isTouchCapable,
93
192
  viewport: `${deviceInfo.screenWidth}x${deviceInfo.screenHeight}`,
193
+ scalingFactor: factor,
94
194
  userAgent: deviceInfo.userAgent,
95
195
  });
96
196
  }
@@ -108,7 +208,7 @@ if (typeof window !== "undefined") {
108
208
  // DOM is already ready
109
209
  initDeviceDetection();
110
210
  }
111
- // Recalculate on resize (debounced)
211
+ // Single debounced resize handler for both device detection + scaling
112
212
  let resizeTimeout;
113
213
  window.addEventListener("resize", () => {
114
214
  clearTimeout(resizeTimeout);
@@ -116,7 +216,14 @@ if (typeof window !== "undefined") {
116
216
  initDeviceDetection();
117
217
  }, 100);
118
218
  });
219
+ // Also handle orientation change
220
+ window.addEventListener("orientationchange", () => {
221
+ setTimeout(initDeviceDetection, 100);
222
+ });
119
223
  }
224
+ // ============================================================================
225
+ // App-like Behavior
226
+ // ============================================================================
120
227
  /**
121
228
  * Disable double-tap to zoom in the browser (app-like behavior)
122
229
  * Prevents all zoom gestures including double-tap and pinch-to-zoom