Skip to content

Commit d22b857

Browse files
Init vite playground server
1 parent 8e0d4c0 commit d22b857

File tree

7 files changed

+884
-410
lines changed

7 files changed

+884
-410
lines changed

packages/devextreme/eslint.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export default [
3838
'themebuilder-scss/src/data/metadata/*',
3939
'js/bundles/dx.custom.js',
4040
'testing/jest/utils/transformers/*',
41+
'vite.config.ts',
4142
'**/ts/',
4243
'js/common/core/localization/cldr-data/*',
4344
'js/common/core/localization/default_messages.js',

packages/devextreme/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@
209209
"uuid": "9.0.1",
210210
"vinyl": "2.2.1",
211211
"vinyl-named": "1.1.0",
212+
"vite": "^7.1.3",
213+
"vite-plugin-inferno": "^0.0.1",
212214
"webpack": "5.94.0",
213215
"webpack-stream": "7.0.0",
214216
"yaml": "2.5.0",
@@ -247,6 +249,7 @@
247249
"validate-ts": "gulp validate-ts",
248250
"validate-declarations": "dx-tools validate-declarations --sources ./js --exclude \"js/(renovation|__internal|.eslintrc.js)\" --compiler-options \"{ \\\"typeRoots\\\": [] }\"",
249251
"testcafe-in-docker": "docker build -f ./testing/testcafe/docker/Dockerfile -t testcafe-testing . && docker run -it testcafe-testing",
252+
"dev:playground": "vite",
250253
"test-jest": "cross-env NODE_OPTIONS='--expose-gc' jest --no-coverage --runInBand --selectProjects jsdom-tests",
251254
"test-jest:watch": "jest --watch",
252255
"test-jest:node": "jest --no-coverage --runInBand --selectProjects node-tests",
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>DevExtreme HMR Playground</title>
7+
</head>
8+
<body>
9+
<div id="app">
10+
<select id="theme-selector" style="display: block;">
11+
</select>
12+
<div id="container"></div>
13+
</div>
14+
<script type="module" src="./scheduler-example.ts"></script>
15+
<script type="module">
16+
if (import.meta.hot) {
17+
import.meta.hot.accept('./scheduler-example.ts', () => {
18+
console.log('HMR: Scheduler example updated');
19+
location.reload();
20+
});
21+
console.log('HMR enabled for playground');
22+
}
23+
</script>
24+
</body>
25+
</html>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
const themeKey = 'currentThemeId';
2+
3+
const themeLoaders = import.meta.glob('../artifacts/css/dx.*.css', { as: 'url' });
4+
5+
const themeList = Object.keys(themeLoaders).map((path) => {
6+
const match = path.match(/dx\.(.+)\.css$/);
7+
return match ? match[1] : null;
8+
}).filter(Boolean) as string[];
9+
10+
function groupThemes(themes: string[]) {
11+
const groups: Record<string, string[]> = {};
12+
themes.forEach((theme) => {
13+
const [group] = theme.split('.');
14+
const groupName = group.charAt(0).toUpperCase() + group.slice(1);
15+
if (!groups[groupName]) groups[groupName] = [];
16+
groups[groupName].push(theme);
17+
});
18+
return groups;
19+
}
20+
21+
const groupedThemes = groupThemes(themeList);
22+
23+
function initThemes(dropDownList: HTMLSelectElement) {
24+
Object.entries(groupedThemes).forEach(([group, themes]) => {
25+
const parent = document.createElement('optgroup');
26+
parent.label = group;
27+
28+
themes.forEach((theme) => {
29+
const child = document.createElement('option');
30+
child.value = theme;
31+
child.text = theme.replaceAll('.', ' ');
32+
parent.appendChild(child);
33+
});
34+
35+
dropDownList.appendChild(parent);
36+
});
37+
}
38+
39+
function loadThemeCss(themeId: string): Promise<void> {
40+
return new Promise((resolve, reject) => {
41+
const oldLink = document.getElementById('theme-stylesheet');
42+
if (oldLink) oldLink.remove();
43+
44+
const key = Object.keys(themeLoaders).find((p) => p.includes(`dx.${themeId}.css`));
45+
if (!key) {
46+
reject(new Error(`Theme not found: ${themeId}`));
47+
return;
48+
}
49+
50+
themeLoaders[key]().then((cssUrl: string) => {
51+
const link = document.createElement('link');
52+
link.id = 'theme-stylesheet';
53+
link.rel = 'stylesheet';
54+
link.href = cssUrl;
55+
56+
link.onload = () => resolve();
57+
link.onerror = () => reject(new Error(`Failed to load theme: ${themeId}`));
58+
59+
document.head.appendChild(link);
60+
});
61+
});
62+
}
63+
64+
export function setupThemeSelector(selectorId: string): Promise<void> {
65+
return new Promise((resolve) => {
66+
const dropDownList = document.querySelector<HTMLSelectElement>(`#${selectorId}`);
67+
if (!dropDownList) {
68+
resolve();
69+
return;
70+
}
71+
72+
initThemes(dropDownList);
73+
74+
const savedTheme = window.localStorage.getItem(themeKey) || themeList[0];
75+
dropDownList.value = savedTheme;
76+
77+
loadThemeCss(savedTheme).then(() => {
78+
dropDownList.addEventListener('change', () => {
79+
const newTheme = dropDownList.value;
80+
window.localStorage.setItem(themeKey, newTheme);
81+
loadThemeCss(newTheme);
82+
});
83+
84+
resolve();
85+
});
86+
});
87+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import $ from 'jquery';
2+
import { setupThemeSelector } from './newthemeSelector';
3+
import Scheduler from '../js/__internal/scheduler/m_scheduler';
4+
5+
const dataSource = [
6+
{
7+
text: "Meeting with John",
8+
startDate: new Date(2024, 0, 10, 9, 0),
9+
endDate: new Date(2024, 0, 10, 10, 30),
10+
allDay: false
11+
},
12+
{
13+
text: "Conference Call",
14+
startDate: new Date(2024, 0, 10, 14, 0),
15+
endDate: new Date(2024, 0, 10, 15, 0),
16+
allDay: false
17+
},
18+
{
19+
text: "Team Building Event",
20+
startDate: new Date(2024, 0, 11, 10, 0),
21+
endDate: new Date(2024, 0, 11, 17, 0),
22+
allDay: false
23+
}
24+
];
25+
26+
window.addEventListener('load', () =>
27+
setupThemeSelector('theme-selector').then(() => {
28+
29+
30+
new (Scheduler as any)($('#container'), {
31+
dataSource,
32+
views: ['day', 'week', 'workWeek', 'month'],
33+
currentView: 'week',
34+
currentDate: new Date(2024, 0, 10),
35+
startDayHour: 8,
36+
endDayHour: 18,
37+
height: 600,
38+
editing: {
39+
allowAdding: true,
40+
allowDeleting: true,
41+
allowUpdating: true,
42+
allowResizing: true,
43+
allowDragging: true
44+
},
45+
onAppointmentAdded: (e) => {
46+
console.log('Appointment added:', e.appointmentData);
47+
},
48+
onAppointmentUpdated: (e) => {
49+
console.log('Appointment updated:', e.appointmentData);
50+
},
51+
onAppointmentDeleted: (e) => {
52+
console.log('Appointment deleted:', e.appointmentData);
53+
}
54+
});
55+
}));

packages/devextreme/vite.config.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import path from 'path';
2+
import { defineConfig } from 'vite';
3+
import inferno from 'vite-plugin-inferno'
4+
5+
export default defineConfig(() => {
6+
return {
7+
root: './playground',
8+
plugins: [inferno()],
9+
server: {
10+
port: 3000,
11+
fs: {
12+
allow: ['..', '.', './testing', '../..']
13+
},
14+
hmr: true
15+
},
16+
resolve: {
17+
alias: {
18+
'core': path.resolve(__dirname, './js/core'),
19+
'common': path.resolve(__dirname, './js/common'),
20+
'data': path.resolve(__dirname, './js/data'),
21+
'ui': path.resolve(__dirname, './js/ui'),
22+
'@js': path.resolve(__dirname, './js'),
23+
'@ts': path.resolve(__dirname, './js/__internal'),
24+
'__internal': path.resolve(__dirname, './js/__internal'),
25+
}
26+
},
27+
esbuild: {
28+
jsxFactory: 'Inferno.createVNode',
29+
jsxFragment: 'Inferno.Fragment',
30+
}
31+
};
32+
});

0 commit comments

Comments
 (0)