create-qwik 0.0.18-7 → 0.0.18-dev20220422050522
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/README.md +1 -1
- package/create-qwik +1 -0
- package/index.js +1 -0
- package/package.json +1 -1
- package/starters/apps/base/README.md +1 -1
- package/starters/apps/base/index.html +1 -1
- package/starters/apps/base/package.json +1 -1
- package/starters/apps/starter/src/components/logo/logo.tsx +3 -3
- package/starters/apps/starter/src/main.tsx +4 -5
- package/starters/apps/starter-builder/src/components/footer/footer.tsx +3 -3
- package/starters/apps/starter-builder/src/components/header/header.tsx +3 -3
- package/starters/apps/starter-builder/src/main.tsx +3 -3
- package/starters/apps/starter-partytown/src/main.tsx +82 -85
- package/starters/apps/todo/src/components/body/body.tsx +14 -18
- package/starters/apps/todo/src/components/footer/footer.tsx +45 -47
- package/starters/apps/todo/src/components/header/header.tsx +23 -26
- package/starters/apps/todo/src/components/item/item.tsx +60 -59
- package/starters/apps/todo/src/main.tsx +8 -10
- package/starters/features/eslint/.eslintignore +0 -1
- package/starters/features/prettier/.prettierignore +0 -1
- package/starters/servers/cloudflare/.node-version +1 -0
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ console.log(result);
|
|
|
41
41
|
## Community
|
|
42
42
|
|
|
43
43
|
- Ping us at [@QwikDev](https://twitter.com/QwikDev)
|
|
44
|
-
- Join our [Discord](https://discord.gg/
|
|
44
|
+
- Join our [Discord](https://discord.gg/bNVSQmPzqy) community.
|
|
45
45
|
- Join our [weekly office hours](https://calendar.google.com/calendar/u/0?cid=Y180ZG91YjR2NTZ1cW43YmgzbW1oZGJ2M3R2c0Bncm91cC5jYWxlbmRhci5nb29nbGUuY29t)
|
|
46
46
|
|
|
47
47
|
## Related
|
package/create-qwik
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* @license
|
|
4
|
+
* create-qwik
|
|
4
5
|
* Copyright Builder.io, Inc. All Rights Reserved.
|
|
5
6
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
7
|
* found in the LICENSE file at https://github.com/BuilderIO/qwik/blob/main/LICENSE
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@ npm run build
|
|
|
22
22
|
|
|
23
23
|
- [Qwik Github](https://github.com/BuilderIO/qwik)
|
|
24
24
|
- [@QwikDev](https://twitter.com/QwikDev)
|
|
25
|
-
- [Discord](https://discord.gg/
|
|
25
|
+
- [Discord](https://discord.gg/bNVSQmPzqy)
|
|
26
26
|
- [Vite](https://vitejs.dev/)
|
|
27
27
|
- [Partytown](https://partytown.builder.io/)
|
|
28
28
|
- [Builder.io](https://www.builder.io/)
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
<head>
|
|
6
6
|
<meta charset="utf-8" />
|
|
7
7
|
<title>Qwik Client Dev Mode</title>
|
|
8
|
+
<meta name="viewport" content="width=device-width" />
|
|
8
9
|
</head>
|
|
9
10
|
<body>
|
|
10
11
|
<script type="module">
|
|
11
12
|
// Vite Dev Mode Only
|
|
12
|
-
import '@builder.io/qwik/qwikloader.debug.js';
|
|
13
13
|
import { render, jsx } from '@builder.io/qwik';
|
|
14
14
|
import { Main } from '/src/main.tsx';
|
|
15
15
|
render(document.body, jsx(Main, {}));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { component$, Host } from '@builder.io/qwik';
|
|
2
2
|
|
|
3
3
|
export const Logo = component$(() => {
|
|
4
|
-
return
|
|
4
|
+
return (
|
|
5
5
|
<Host style={{ 'text-align': 'center' }}>
|
|
6
6
|
<a href="https://github.com/builderio/qwik">
|
|
7
7
|
<img
|
|
@@ -11,5 +11,5 @@ export const Logo = component$(() => {
|
|
|
11
11
|
/>
|
|
12
12
|
</a>
|
|
13
13
|
</Host>
|
|
14
|
-
)
|
|
14
|
+
);
|
|
15
15
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { useStore,
|
|
1
|
+
import { useStore, component$, Host } from '@builder.io/qwik';
|
|
2
2
|
import { Logo } from './components/logo/logo';
|
|
3
3
|
|
|
4
4
|
import './global.css';
|
|
5
5
|
|
|
6
6
|
export const Main = component$(() => {
|
|
7
7
|
const state = useStore({ name: 'World' });
|
|
8
|
-
return
|
|
8
|
+
return (
|
|
9
9
|
<Host class="my-app p-20">
|
|
10
10
|
<Logo class="mb-10" />
|
|
11
11
|
|
|
@@ -23,8 +23,7 @@ export const Main = component$(() => {
|
|
|
23
23
|
value={state.name}
|
|
24
24
|
class="border-2 border-solid border-blue-500"
|
|
25
25
|
placeholder="Write some text"
|
|
26
|
-
|
|
27
|
-
const event = useEvent<KeyboardEvent>();
|
|
26
|
+
onInput$={(event) => {
|
|
28
27
|
const input = event.target as HTMLInputElement;
|
|
29
28
|
state.name = input.value;
|
|
30
29
|
}}
|
|
@@ -53,5 +52,5 @@ export const Main = component$(() => {
|
|
|
53
52
|
</a>
|
|
54
53
|
</p>
|
|
55
54
|
</Host>
|
|
56
|
-
)
|
|
55
|
+
);
|
|
57
56
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { component
|
|
1
|
+
import { component$ } from '@builder.io/qwik';
|
|
2
2
|
|
|
3
3
|
export const Footer = component$(() => {
|
|
4
|
-
return
|
|
4
|
+
return (
|
|
5
5
|
<>
|
|
6
6
|
<hr />
|
|
7
7
|
<p style={{ 'text-align': 'center' }}>
|
|
@@ -11,5 +11,5 @@ export const Footer = component$(() => {
|
|
|
11
11
|
</a>
|
|
12
12
|
</p>
|
|
13
13
|
</>
|
|
14
|
-
)
|
|
14
|
+
);
|
|
15
15
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { component
|
|
1
|
+
import { component$ } from '@builder.io/qwik';
|
|
2
2
|
|
|
3
3
|
export const Header = component$(() => {
|
|
4
|
-
return
|
|
4
|
+
return (
|
|
5
5
|
<p style={{ 'text-align': 'center' }}>
|
|
6
6
|
<a href="https://github.com/builderio/qwik">
|
|
7
7
|
<img
|
|
@@ -11,5 +11,5 @@ export const Header = component$(() => {
|
|
|
11
11
|
/>
|
|
12
12
|
</a>
|
|
13
13
|
</p>
|
|
14
|
-
)
|
|
14
|
+
);
|
|
15
15
|
});
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { component
|
|
1
|
+
import { component$ } from '@builder.io/qwik';
|
|
2
2
|
import { Footer } from './components/footer/footer';
|
|
3
3
|
import { Header } from './components/header/header';
|
|
4
4
|
|
|
5
5
|
import './global.css';
|
|
6
6
|
|
|
7
7
|
export const Main = component$(() => {
|
|
8
|
-
return
|
|
8
|
+
return (
|
|
9
9
|
<>
|
|
10
10
|
<Header />
|
|
11
11
|
<div id="my-content"></div>
|
|
12
12
|
<Footer />
|
|
13
13
|
</>
|
|
14
|
-
)
|
|
14
|
+
);
|
|
15
15
|
});
|
|
@@ -1,92 +1,89 @@
|
|
|
1
|
-
import { component$,
|
|
1
|
+
import { component$, useStore } from '@builder.io/qwik';
|
|
2
2
|
import './global.css';
|
|
3
3
|
|
|
4
4
|
export const Main = component$(() => {
|
|
5
5
|
const state = useStore({ name: 'World', running: true });
|
|
6
|
-
return
|
|
7
|
-
|
|
8
|
-
<
|
|
9
|
-
<
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
</p>
|
|
6
|
+
return (
|
|
7
|
+
<div id="my-app" onDocumentExpensiveComputationDone$={() => (state.running = false)}>
|
|
8
|
+
<p style={{ 'text-align': 'center' }}>
|
|
9
|
+
<a href="https://github.com/builderio/qwik">
|
|
10
|
+
<img
|
|
11
|
+
alt="Qwik Logo"
|
|
12
|
+
width={400}
|
|
13
|
+
src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F667ab6c2283d4c4d878fb9083aacc10f"
|
|
14
|
+
/>
|
|
15
|
+
</a>
|
|
16
|
+
</p>
|
|
17
|
+
<p class="congrats">
|
|
18
|
+
Congratulations <a href="https://github.com/builderio/qwik">Qwik</a> with{' '}
|
|
19
|
+
<a href="https://partytown.builder.io/">Partytown</a> is working!
|
|
20
|
+
</p>
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
22
|
+
<p>
|
|
23
|
+
Expensive script running in <a href="https://partytown.builder.io/">Partytown</a> is{' '}
|
|
24
|
+
{state.running ? (
|
|
25
|
+
<span style={{ 'background-color': 'red', color: 'white', padding: '.1em' }}>
|
|
26
|
+
running
|
|
27
|
+
</span>
|
|
28
|
+
) : (
|
|
29
|
+
<span style={{ 'background-color': 'green', color: 'white', padding: '.1em' }}>
|
|
30
|
+
finished
|
|
31
|
+
</span>
|
|
32
|
+
)}
|
|
33
|
+
.
|
|
34
|
+
</p>
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
);
|
|
91
|
-
});
|
|
36
|
+
<p>Next steps:</p>
|
|
37
|
+
<ol>
|
|
38
|
+
<li>
|
|
39
|
+
Open dev-tools network tab and notice that no JavaScript was downloaded by the main thread
|
|
40
|
+
to render this page. (<code>partytown.js</code> is used to execute things of main thread
|
|
41
|
+
and not for rendering the application.)
|
|
42
|
+
</li>
|
|
43
|
+
<li>
|
|
44
|
+
Partytown executes <code><script></code> tag that contains a simulation of expensive
|
|
45
|
+
script. The expensive script simplation keeps the web-worker thread busy for 2.5 seconds,
|
|
46
|
+
leaving main-thread free for user interactions. (Without Partytown the script would block
|
|
47
|
+
the main thread resulting in poor user experience.)
|
|
48
|
+
</li>
|
|
49
|
+
<li>
|
|
50
|
+
Once the expensive operation is finished it dispatches custom event (
|
|
51
|
+
<code>expensiveComputationDone</code>) that this component listens on. It is only at that
|
|
52
|
+
time that Qwik lazy-loads the component render function and updates the UI. (See network
|
|
53
|
+
tab.)
|
|
54
|
+
</li>
|
|
55
|
+
<li>
|
|
56
|
+
Try interacting with this component by changing{' '}
|
|
57
|
+
<input
|
|
58
|
+
value={state.name}
|
|
59
|
+
onKeyup$={(event) => {
|
|
60
|
+
const input = event.target as HTMLInputElement;
|
|
61
|
+
state.name = input.value;
|
|
62
|
+
}}
|
|
63
|
+
></input>
|
|
64
|
+
.
|
|
65
|
+
</li>
|
|
66
|
+
<li>
|
|
67
|
+
Observe that the binding changes: <code>Hello {state.name}!</code>
|
|
68
|
+
</li>
|
|
69
|
+
<li>
|
|
70
|
+
Notice that Qwik automatically lazily-loaded and resumed the component upon interaction
|
|
71
|
+
without the developer having to code that behavior. (Lazy hydration is what gives even
|
|
72
|
+
large apps instant on behavior.)
|
|
73
|
+
</li>
|
|
74
|
+
<li>
|
|
75
|
+
Read the docs <a href="https://github.com/builderio/qwik">here</a>.
|
|
76
|
+
</li>
|
|
77
|
+
<li>Replace the content of this component with your code.</li>
|
|
78
|
+
<li>Build amazing web-sites with unbeatable startup performance.</li>
|
|
79
|
+
</ol>
|
|
80
|
+
<hr />
|
|
81
|
+
<p style={{ 'text-align': 'center' }}>
|
|
82
|
+
Made with ❤️ by{' '}
|
|
83
|
+
<a target="_blank" href="https://www.builder.io/">
|
|
84
|
+
Builder.io
|
|
85
|
+
</a>
|
|
86
|
+
</p>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
92
89
|
});
|
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
import { component$, Host
|
|
1
|
+
import { component$, Host } from '@builder.io/qwik';
|
|
2
2
|
import { FILTERS, Todos } from '../../state/state';
|
|
3
3
|
import { Item } from '../item/item';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
</ul>
|
|
19
|
-
</Host>
|
|
20
|
-
);
|
|
21
|
-
});
|
|
5
|
+
interface BodyProps {
|
|
6
|
+
todos: Todos;
|
|
7
|
+
}
|
|
8
|
+
export const Body = component$(({ todos }: BodyProps) => {
|
|
9
|
+
return (
|
|
10
|
+
<Host class="main">
|
|
11
|
+
<ul class="todo-list">
|
|
12
|
+
{todos.items.filter(FILTERS[todos.filter]).map((key) => (
|
|
13
|
+
<Item item={key} todos={todos} />
|
|
14
|
+
))}
|
|
15
|
+
</ul>
|
|
16
|
+
</Host>
|
|
17
|
+
);
|
|
22
18
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { component$, Host
|
|
1
|
+
import { component$, Host } from '@builder.io/qwik';
|
|
2
2
|
import { FILTERS, FilterStates, Todos } from '../../state/state';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -8,54 +8,52 @@ import { FILTERS, FilterStates, Todos } from '../../state/state';
|
|
|
8
8
|
*/
|
|
9
9
|
export const Footer = component$(
|
|
10
10
|
(props: { todos: Todos }) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const lMode = filter.toLowerCase();
|
|
17
|
-
return (
|
|
18
|
-
<li>
|
|
19
|
-
<a
|
|
20
|
-
class={{ selected: props.todos.filter == lMode }}
|
|
21
|
-
onClick$={() => {
|
|
22
|
-
props.todos.filter = filter;
|
|
23
|
-
}}
|
|
24
|
-
>
|
|
25
|
-
{filter[0].toUpperCase() + filter.slice(1)}
|
|
26
|
-
</a>
|
|
27
|
-
</li>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
const remaining = props.todos.items.filter(FILTERS.active).length;
|
|
11
|
+
/**
|
|
12
|
+
* Example of lite-component (it will always be included with the parent component)
|
|
13
|
+
*/
|
|
14
|
+
function Filter({ filter }: { filter: FilterStates }) {
|
|
15
|
+
const lMode = filter.toLowerCase();
|
|
31
16
|
return (
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
))}
|
|
43
|
-
</ul>
|
|
44
|
-
{remaining > 0 ? (
|
|
45
|
-
<button
|
|
46
|
-
class="clear-completed"
|
|
47
|
-
onClick$={() => {
|
|
48
|
-
props.todos.items = props.todos.items.filter(FILTERS.active);
|
|
49
|
-
}}
|
|
50
|
-
>
|
|
51
|
-
Clear completed
|
|
52
|
-
</button>
|
|
53
|
-
) : null}
|
|
54
|
-
</>
|
|
55
|
-
) : null}
|
|
56
|
-
</Host>
|
|
17
|
+
<li>
|
|
18
|
+
<a
|
|
19
|
+
class={{ selected: props.todos.filter == lMode }}
|
|
20
|
+
onClick$={() => {
|
|
21
|
+
props.todos.filter = filter;
|
|
22
|
+
}}
|
|
23
|
+
>
|
|
24
|
+
{filter[0].toUpperCase() + filter.slice(1)}
|
|
25
|
+
</a>
|
|
26
|
+
</li>
|
|
57
27
|
);
|
|
58
|
-
}
|
|
28
|
+
}
|
|
29
|
+
const remaining = props.todos.items.filter(FILTERS.active).length;
|
|
30
|
+
return (
|
|
31
|
+
<Host class="footer">
|
|
32
|
+
{props.todos.items.length > 0 ? (
|
|
33
|
+
<>
|
|
34
|
+
<span class="todo-count">
|
|
35
|
+
<strong>{remaining}</strong>
|
|
36
|
+
{remaining == 1 ? ' item' : ' items'} left
|
|
37
|
+
</span>
|
|
38
|
+
<ul class="filters">
|
|
39
|
+
{FilterStates.map((f) => (
|
|
40
|
+
<Filter filter={f} />
|
|
41
|
+
))}
|
|
42
|
+
</ul>
|
|
43
|
+
{remaining > 0 ? (
|
|
44
|
+
<button
|
|
45
|
+
class="clear-completed"
|
|
46
|
+
onClick$={() => {
|
|
47
|
+
props.todos.items = props.todos.items.filter(FILTERS.active);
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
Clear completed
|
|
51
|
+
</button>
|
|
52
|
+
) : null}
|
|
53
|
+
</>
|
|
54
|
+
) : null}
|
|
55
|
+
</Host>
|
|
56
|
+
);
|
|
59
57
|
},
|
|
60
58
|
{
|
|
61
59
|
tagName: 'footer',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { component$, useStore
|
|
1
|
+
import { component$, useStore } from '@builder.io/qwik';
|
|
2
2
|
import type { Todos } from '../../state/state';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -9,31 +9,28 @@ import type { Todos } from '../../state/state';
|
|
|
9
9
|
export const Header = component$(
|
|
10
10
|
(props: { todos: Todos }) => {
|
|
11
11
|
const state = useStore({ text: '' });
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
</>
|
|
35
|
-
);
|
|
36
|
-
});
|
|
12
|
+
return (
|
|
13
|
+
<>
|
|
14
|
+
<h1>todos</h1>
|
|
15
|
+
<input
|
|
16
|
+
class="new-todo"
|
|
17
|
+
placeholder="What needs to be done?"
|
|
18
|
+
autoFocus
|
|
19
|
+
value={state.text}
|
|
20
|
+
onKeyup$={(event: any) => {
|
|
21
|
+
const inputValue = (event.target as HTMLInputElement).value;
|
|
22
|
+
state.text = inputValue;
|
|
23
|
+
if (event.key === 'Enter' && inputValue) {
|
|
24
|
+
props.todos.items.push({
|
|
25
|
+
completed: false,
|
|
26
|
+
title: state.text,
|
|
27
|
+
});
|
|
28
|
+
state.text = '';
|
|
29
|
+
}
|
|
30
|
+
}}
|
|
31
|
+
/>
|
|
32
|
+
</>
|
|
33
|
+
);
|
|
37
34
|
},
|
|
38
35
|
{
|
|
39
36
|
tagName: 'header',
|
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
component$,
|
|
3
|
-
useStore,
|
|
4
|
-
Host,
|
|
5
|
-
notifyRender,
|
|
6
|
-
$,
|
|
7
|
-
useEvent,
|
|
8
|
-
useHostElement,
|
|
9
|
-
} from '@builder.io/qwik';
|
|
1
|
+
import { component$, useStore, Host, useRef, useEffect$ } from '@builder.io/qwik';
|
|
10
2
|
import type { TodoItem, Todos } from '../../state/state';
|
|
11
3
|
|
|
12
4
|
/**
|
|
@@ -14,59 +6,68 @@ import type { TodoItem, Todos } from '../../state/state';
|
|
|
14
6
|
*
|
|
15
7
|
* It only rerenders if the user infarcts with it or if the item itself changes.
|
|
16
8
|
*/
|
|
9
|
+
|
|
10
|
+
export interface ItemProps {
|
|
11
|
+
item: TodoItem;
|
|
12
|
+
todos: Todos;
|
|
13
|
+
}
|
|
14
|
+
|
|
17
15
|
export const Item = component$(
|
|
18
|
-
(props:
|
|
16
|
+
(props: ItemProps) => {
|
|
19
17
|
const state = useStore({ editing: false });
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
onClick$={() => {
|
|
29
|
-
props.item.completed = !props.item.completed;
|
|
30
|
-
}}
|
|
31
|
-
/>
|
|
32
|
-
<label
|
|
33
|
-
onDblclick$={async () => {
|
|
34
|
-
state.editing = true;
|
|
35
|
-
const hostElement = useHostElement()!;
|
|
36
|
-
await notifyRender(hostElement);
|
|
37
|
-
const inputEl = hostElement.querySelector('input.edit') as HTMLInputElement;
|
|
38
|
-
inputEl.focus();
|
|
39
|
-
inputEl.selectionStart = inputEl.selectionEnd = inputEl.value.length;
|
|
40
|
-
}}
|
|
41
|
-
>
|
|
42
|
-
{props.item.title}
|
|
43
|
-
</label>
|
|
44
|
-
<button
|
|
45
|
-
class="destroy"
|
|
46
|
-
onClick$={() => {
|
|
47
|
-
const todoItem = props.item;
|
|
48
|
-
props.todos.items = props.todos.items.filter((i) => i != todoItem);
|
|
49
|
-
}}
|
|
50
|
-
/>
|
|
51
|
-
</div>
|
|
52
|
-
{state.editing ? (
|
|
53
|
-
<input
|
|
54
|
-
class="edit"
|
|
55
|
-
value={props.item.title}
|
|
56
|
-
onBlur$={() => (state.editing = false)}
|
|
57
|
-
onKeyup$={() => {
|
|
58
|
-
const event = useEvent<KeyboardEvent>();
|
|
59
|
-
const inputValue = (event.target as HTMLInputElement).value;
|
|
60
|
-
props.item.title = inputValue;
|
|
61
|
-
if (event.key === 'Enter') {
|
|
62
|
-
state.editing = false;
|
|
63
|
-
}
|
|
64
|
-
}}
|
|
65
|
-
/>
|
|
66
|
-
) : null}
|
|
67
|
-
</Host>
|
|
68
|
-
);
|
|
18
|
+
const editInput = useRef<HTMLInputElement>();
|
|
19
|
+
|
|
20
|
+
useEffect$((obs) => {
|
|
21
|
+
const { current } = obs(editInput);
|
|
22
|
+
if (current) {
|
|
23
|
+
current.focus();
|
|
24
|
+
current.selectionStart = current.selectionEnd = current.value.length;
|
|
25
|
+
}
|
|
69
26
|
});
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Host class={{ completed: props.item.completed, editing: state.editing }}>
|
|
30
|
+
<div class="view">
|
|
31
|
+
<input
|
|
32
|
+
class="toggle"
|
|
33
|
+
type="checkbox"
|
|
34
|
+
checked={props.item.completed}
|
|
35
|
+
onClick$={() => {
|
|
36
|
+
props.item.completed = !props.item.completed;
|
|
37
|
+
}}
|
|
38
|
+
/>
|
|
39
|
+
<label
|
|
40
|
+
onDblclick$={async () => {
|
|
41
|
+
state.editing = true;
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
{props.item.title}
|
|
45
|
+
</label>
|
|
46
|
+
<button
|
|
47
|
+
class="destroy"
|
|
48
|
+
onClick$={() => {
|
|
49
|
+
const todoItem = props.item;
|
|
50
|
+
props.todos.items = props.todos.items.filter((i) => i != todoItem);
|
|
51
|
+
}}
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
{state.editing ? (
|
|
55
|
+
<input
|
|
56
|
+
class="edit"
|
|
57
|
+
ref={editInput}
|
|
58
|
+
value={props.item.title}
|
|
59
|
+
onBlur$={() => (state.editing = false)}
|
|
60
|
+
onKeyup$={(event: any) => {
|
|
61
|
+
const inputValue = (event.target as HTMLInputElement).value;
|
|
62
|
+
props.item.title = inputValue;
|
|
63
|
+
if (event.key === 'Enter') {
|
|
64
|
+
state.editing = false;
|
|
65
|
+
}
|
|
66
|
+
}}
|
|
67
|
+
/>
|
|
68
|
+
) : null}
|
|
69
|
+
</Host>
|
|
70
|
+
);
|
|
70
71
|
},
|
|
71
72
|
{
|
|
72
73
|
tagName: 'li',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { component$,
|
|
1
|
+
import { component$, useStore } from '@builder.io/qwik';
|
|
2
2
|
import { Footer } from './components/footer/footer';
|
|
3
3
|
import { Header } from './components/header/header';
|
|
4
4
|
import { Body } from './components/body/body';
|
|
@@ -23,13 +23,11 @@ export const Main = component$(() => {
|
|
|
23
23
|
{ completed: false, title: 'Profit' },
|
|
24
24
|
],
|
|
25
25
|
});
|
|
26
|
-
return
|
|
27
|
-
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
);
|
|
34
|
-
});
|
|
26
|
+
return (
|
|
27
|
+
<section class="todoapp">
|
|
28
|
+
<Header todos={todos} />
|
|
29
|
+
<Body todos={todos} />
|
|
30
|
+
<Footer todos={todos} />
|
|
31
|
+
</section>
|
|
32
|
+
);
|
|
35
33
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
16
|