sunpeak 0.17.2 → 0.17.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/bin/commands/build.mjs +4 -0
- package/bin/commands/dev.mjs +2 -0
- package/bin/lib/css.mjs +13 -0
- package/dist/chatgpt/globals.css +0 -85
- package/package.json +1 -1
- package/template/dist/albums/albums.json +1 -1
- package/template/dist/carousel/carousel.json +1 -1
- package/template/dist/map/map.json +1 -1
- package/template/dist/review/review.json +1 -1
- package/template/playwright.config.ts +4 -25
- package/template/tests/e2e/review.spec.ts +7 -5
package/bin/commands/build.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { createRequire } from 'module';
|
|
|
5
5
|
import { pathToFileURL } from 'url';
|
|
6
6
|
import { toPascalCase } from '../lib/patterns.mjs';
|
|
7
7
|
import { extractResourceExport } from '../lib/extract-resource.mjs';
|
|
8
|
+
import { lightningcssConfig } from '../lib/css.mjs';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Resolve the ESM entry point for a package from a specific project directory.
|
|
@@ -237,6 +238,9 @@ export async function build(projectRoot = process.cwd(), { quiet = false } = {})
|
|
|
237
238
|
define: {
|
|
238
239
|
'process.env.NODE_ENV': JSON.stringify('production'),
|
|
239
240
|
},
|
|
241
|
+
css: {
|
|
242
|
+
lightningcss: lightningcssConfig,
|
|
243
|
+
},
|
|
240
244
|
resolve: {
|
|
241
245
|
conditions: ['style', 'import', 'module', 'browser', 'default'],
|
|
242
246
|
alias: {
|
package/bin/commands/dev.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { pathToFileURL } from 'url';
|
|
|
8
8
|
import { spawn } from 'child_process';
|
|
9
9
|
import { getPort } from '../lib/get-port.mjs';
|
|
10
10
|
import { startSandboxServer } from '../lib/sandbox-server.mjs';
|
|
11
|
+
import { lightningcssConfig } from '../lib/css.mjs';
|
|
11
12
|
import { inspectServer } from './inspect.mjs';
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -422,6 +423,7 @@ if (import.meta.hot) {
|
|
|
422
423
|
root: projectRoot,
|
|
423
424
|
cacheDir: 'node_modules/.vite-mcp',
|
|
424
425
|
plugins: [react(), tailwindcss(), sunpeakEntryPlugin()],
|
|
426
|
+
css: { lightningcss: lightningcssConfig },
|
|
425
427
|
resolve: {
|
|
426
428
|
alias: {
|
|
427
429
|
'@': path.resolve(projectRoot, 'src'),
|
package/bin/lib/css.mjs
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared lightningcss configuration for all Vite instances that process Tailwind CSS.
|
|
3
|
+
*
|
|
4
|
+
* Tailwind v4's `@source` directive is consumed by `@tailwindcss/vite` but may
|
|
5
|
+
* still be visible to lightningcss during parsing/minification, producing
|
|
6
|
+
* "Unknown at rule: @source" warnings. Declaring it as a custom at-rule
|
|
7
|
+
* tells lightningcss the rule is intentional.
|
|
8
|
+
*/
|
|
9
|
+
export const lightningcssConfig = {
|
|
10
|
+
customAtRules: {
|
|
11
|
+
source: { prelude: '<string>' },
|
|
12
|
+
},
|
|
13
|
+
};
|
package/dist/chatgpt/globals.css
CHANGED
|
@@ -1,88 +1,3 @@
|
|
|
1
|
-
@import "tailwindcss";
|
|
2
|
-
|
|
3
|
-
/* Scan simulator source files for Tailwind classes */
|
|
4
|
-
@source "./**/*.{ts,tsx}";
|
|
5
|
-
|
|
6
|
-
/* Also scan host-specific shell components */
|
|
7
|
-
@source "../chatgpt/**/*.{ts,tsx}";
|
|
8
|
-
@source "../claude/**/*.{ts,tsx}";
|
|
9
|
-
|
|
10
|
-
/* Configure dark mode to use data-theme attribute */
|
|
11
|
-
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
|
|
12
|
-
|
|
13
|
-
/* Sidebar utility — host-overridable via --sim-bg-sidebar */
|
|
14
|
-
@utility bg-sidebar {
|
|
15
|
-
background-color: var(--sim-bg-sidebar, var(--color-background-secondary));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/* Sidebar form elements — match SDK look */
|
|
19
|
-
.sunpeak-simulator-root select,
|
|
20
|
-
.sunpeak-simulator-root input:not([type="checkbox"]),
|
|
21
|
-
.sunpeak-simulator-root textarea {
|
|
22
|
-
border: 0;
|
|
23
|
-
box-shadow: inset 0 0 0 1px var(--color-border-primary);
|
|
24
|
-
transition: box-shadow 150ms ease, color 150ms ease, background-color 150ms ease;
|
|
25
|
-
}
|
|
26
|
-
.sunpeak-simulator-root select:hover,
|
|
27
|
-
.sunpeak-simulator-root input:not([type="checkbox"]):hover,
|
|
28
|
-
.sunpeak-simulator-root textarea:hover {
|
|
29
|
-
box-shadow: inset 0 0 0 1px var(--color-border-secondary);
|
|
30
|
-
}
|
|
31
|
-
.sunpeak-simulator-root select:focus-visible,
|
|
32
|
-
.sunpeak-simulator-root input:not([type="checkbox"]):focus-visible,
|
|
33
|
-
.sunpeak-simulator-root textarea:focus-visible {
|
|
34
|
-
box-shadow: inset 0 0 0 1px var(--color-border-secondary);
|
|
35
|
-
outline: 2px solid var(--color-ring-primary);
|
|
36
|
-
outline-offset: -1px;
|
|
37
|
-
}
|
|
38
|
-
.sunpeak-simulator-root button:focus-visible {
|
|
39
|
-
outline: 2px solid var(--color-ring-primary);
|
|
40
|
-
outline-offset: -1px;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/* Custom checkbox */
|
|
44
|
-
.sunpeak-simulator-root input[type="checkbox"] {
|
|
45
|
-
appearance: none;
|
|
46
|
-
-webkit-appearance: none;
|
|
47
|
-
width: 16px;
|
|
48
|
-
height: 16px;
|
|
49
|
-
border-radius: 4px;
|
|
50
|
-
border: 1px solid var(--color-border-secondary);
|
|
51
|
-
background-color: transparent;
|
|
52
|
-
background-size: 10px;
|
|
53
|
-
background-position: center;
|
|
54
|
-
background-repeat: no-repeat;
|
|
55
|
-
cursor: pointer;
|
|
56
|
-
flex-shrink: 0;
|
|
57
|
-
transition: border-color 150ms ease, background-color 150ms ease;
|
|
58
|
-
}
|
|
59
|
-
.sunpeak-simulator-root input[type="checkbox"]:hover {
|
|
60
|
-
border-color: var(--color-text-tertiary);
|
|
61
|
-
}
|
|
62
|
-
.sunpeak-simulator-root input[type="checkbox"]:checked {
|
|
63
|
-
border-color: var(--color-background-inverse);
|
|
64
|
-
background-color: var(--color-background-inverse);
|
|
65
|
-
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 10 10' fill='none' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M2 5L4.25 7L8 3' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e");
|
|
66
|
-
}
|
|
67
|
-
[data-theme="dark"] .sunpeak-simulator-root input[type="checkbox"]:checked {
|
|
68
|
-
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 10 10' fill='none' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M2 5L4.25 7L8 3' stroke='%23111' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e");
|
|
69
|
-
}
|
|
70
|
-
.sunpeak-simulator-root input[type="checkbox"]:focus-visible {
|
|
71
|
-
outline: 2px solid var(--color-ring-primary);
|
|
72
|
-
outline-offset: 2px;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/* Hide native number input spinners */
|
|
76
|
-
.sunpeak-simulator-root input[type="number"]::-webkit-inner-spin-button,
|
|
77
|
-
.sunpeak-simulator-root input[type="number"]::-webkit-outer-spin-button {
|
|
78
|
-
-webkit-appearance: none;
|
|
79
|
-
margin: 0;
|
|
80
|
-
}
|
|
81
|
-
.sunpeak-simulator-root input[type="number"] {
|
|
82
|
-
-moz-appearance: textfield;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/* Bundled component styles */
|
|
86
1
|
/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
|
|
87
2
|
@layer properties {
|
|
88
3
|
@supports (((-webkit-hyphens: none)) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color: rgb(from red r g b)))) {
|
package/package.json
CHANGED
|
@@ -1,30 +1,9 @@
|
|
|
1
1
|
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
-
import { execSync } from 'child_process';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function getPortSync(preferred: number): number {
|
|
9
|
-
const script = `
|
|
10
|
-
const s = require("net").createServer();
|
|
11
|
-
s.listen(${preferred}, () => {
|
|
12
|
-
process.stdout.write(String(s.address().port));
|
|
13
|
-
s.close();
|
|
14
|
-
});
|
|
15
|
-
s.on("error", () => {
|
|
16
|
-
const f = require("net").createServer();
|
|
17
|
-
f.listen(0, () => {
|
|
18
|
-
process.stdout.write(String(f.address().port));
|
|
19
|
-
f.close();
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
`;
|
|
23
|
-
return Number(execSync(`node -e '${script}'`, { encoding: 'utf-8' }).trim());
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const port = Number(process.env.SUNPEAK_TEST_PORT) || getPortSync(6776);
|
|
27
|
-
const sandboxPort = Number(process.env.SUNPEAK_SANDBOX_PORT) || getPortSync(24680);
|
|
3
|
+
// Use fixed preferred ports. If in use, `reuseExistingServer` (local) reuses
|
|
4
|
+
// the running server. In CI, validate.mjs assigns unique ports via env vars.
|
|
5
|
+
const port = Number(process.env.SUNPEAK_TEST_PORT) || 6776;
|
|
6
|
+
const sandboxPort = Number(process.env.SUNPEAK_SANDBOX_PORT) || 24680;
|
|
28
7
|
|
|
29
8
|
export default defineConfig({
|
|
30
9
|
globalSetup: './tests/e2e/global-setup.ts',
|
|
@@ -318,7 +318,9 @@ for (const host of hosts) {
|
|
|
318
318
|
const iframe = page.frameLocator('iframe').frameLocator('iframe');
|
|
319
319
|
const publishButton = iframe.locator('button:has-text("Publish")');
|
|
320
320
|
await expect(publishButton).toBeVisible();
|
|
321
|
-
|
|
321
|
+
// Use evaluate to dispatch click directly — Playwright's coordinate-based
|
|
322
|
+
// click can miss the target inside the double cross-origin iframe.
|
|
323
|
+
await publishButton.evaluate((el) => (el as HTMLElement).click());
|
|
322
324
|
|
|
323
325
|
// Should show the server's success message from serverTools mock
|
|
324
326
|
await expect(iframe.locator('text=Completed.')).toBeVisible({ timeout: 10000 });
|
|
@@ -338,7 +340,7 @@ for (const host of hosts) {
|
|
|
338
340
|
const iframe = page.frameLocator('iframe').frameLocator('iframe');
|
|
339
341
|
const cancelButton = iframe.locator('button:has-text("Cancel")');
|
|
340
342
|
await expect(cancelButton).toBeVisible();
|
|
341
|
-
await cancelButton.click();
|
|
343
|
+
await cancelButton.evaluate((el) => (el as HTMLElement).click());
|
|
342
344
|
|
|
343
345
|
// Server returned cancelled status via serverTools when condition
|
|
344
346
|
await expect(iframe.locator('text=Cancelled.')).toBeVisible({ timeout: 10000 });
|
|
@@ -378,7 +380,7 @@ for (const host of hosts) {
|
|
|
378
380
|
const iframe = page.frameLocator('iframe').frameLocator('iframe');
|
|
379
381
|
const placeOrderButton = iframe.locator('button:has-text("Place Order")');
|
|
380
382
|
await expect(placeOrderButton).toBeVisible();
|
|
381
|
-
await placeOrderButton.click();
|
|
383
|
+
await placeOrderButton.evaluate((el) => (el as HTMLElement).click());
|
|
382
384
|
|
|
383
385
|
// After server responds, should show what the user clicked and the server result
|
|
384
386
|
await expect(iframe.locator('text=Placing order...')).toBeVisible({ timeout: 10000 });
|
|
@@ -399,7 +401,7 @@ for (const host of hosts) {
|
|
|
399
401
|
const iframe = page.frameLocator('iframe').frameLocator('iframe');
|
|
400
402
|
const applyButton = iframe.locator('button:has-text("Apply Changes")');
|
|
401
403
|
await expect(applyButton).toBeVisible();
|
|
402
|
-
await applyButton.click();
|
|
404
|
+
await applyButton.evaluate((el) => (el as HTMLElement).click());
|
|
403
405
|
|
|
404
406
|
// Should show the decision label and server response
|
|
405
407
|
await expect(iframe.locator('text=Applying changes...')).toBeVisible({ timeout: 10000 });
|
|
@@ -418,7 +420,7 @@ for (const host of hosts) {
|
|
|
418
420
|
const iframe = page.frameLocator('iframe').frameLocator('iframe');
|
|
419
421
|
const cancelButton = iframe.locator('button:has-text("Cancel")');
|
|
420
422
|
await expect(cancelButton).toBeVisible();
|
|
421
|
-
await cancelButton.click();
|
|
423
|
+
await cancelButton.evaluate((el) => (el as HTMLElement).click());
|
|
422
424
|
|
|
423
425
|
// Server returned cancelled status via when condition matching
|
|
424
426
|
await expect(iframe.locator('text=Cancelled.')).toBeVisible({ timeout: 10000 });
|