Skip to content

Commit 40e09e0

Browse files
committed
Allow importing json and images
1 parent 582d4ad commit 40e09e0

File tree

3 files changed

+34
-116
lines changed

3 files changed

+34
-116
lines changed

apps/components_guide_web/lib/components_guide_web/templates/react_typescript/_top.html.eex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<li hidden><%= link("Event Handlers", to: '/react+typescript/event-handlers') %>
1515
<li><%= link("Logical Clocks", to: '/react+typescript/logical-clocks') %>
1616
<li><%= link("Forms", to: '/react+typescript/forms') %>
17+
<li><%= link("Playground", to: '/react+typescript/editor') %>
1718
</ul>
1819
</nav>
1920
</div>

apps/components_guide_web/lib/components_guide_web/templates/react_typescript/editor.html.eex

Lines changed: 30 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,16 @@ export function Example() {
9393

9494
value = `
9595
import { flavors } from "https://gist.githubusercontent.com/BurntCaramel/d9d2ca7ed6f056632696709a2ae3c413/raw/0234322cf854d52e2f2bd33aa37e8c8b00f9df0a/1.js";
96+
import reactDownloads from "https://api.npmjs.org/downloads/point/last-week/react";
97+
import image from "https://embed.filekitcdn.com/e/fEiVX4E3EdQhij4RMaw92W/pziZhFNQLKJtwNHMTkDnTD";
9698

9799
const a = 1 + 1 + flavors.length;
98100

99101
function useTick() {
100102
return useReducer(n => n + 1, 0);
101103
}
102104

103-
function useDebouncer(duration) {
105+
function useDebouncedTick(duration) {
104106
const [count, tick] = useTick();
105107

106108
const callback = useMemo(() => {
@@ -121,122 +123,19 @@ function useDebouncer(duration) {
121123
return [count, callback];
122124
}
123125

124-
export default function App() {
125-
const [count, tick] = useDebouncer(1000);
126-
return <>
127-
<div>Hello!! {flavors.join(" ")}</div>
128-
<button onClick={tick}>Click</button>
129-
<div>{count}</div>
130-
</>;
131-
}
132-
`.trim();
133-
134-
value = `
135-
import { flavors } from "https://gist.githubusercontent.com/BurntCaramel/d9d2ca7ed6f056632696709a2ae3c413/raw/0234322cf854d52e2f2bd33aa37e8c8b00f9df0a/1.js";
136-
137-
const a = 1 + 1 + flavors.length;
138-
139-
function useTick() {
140-
return useReducer(n => n + 1, 0);
141-
}
142-
143-
function useDebouncer(duration) {
144-
const [count, tick] = useTick();
145-
146-
const callback = useMemo(() => {
147-
let timeout = null;
148-
function clear() {
149-
if (timeout) {
150-
clearTimeout(timeout);
151-
timeout = null;
152-
}
153-
}
154-
return () => {
155-
clear()
156-
timeout = setTimeout(tick, duration);
157-
return clear;
158-
};
159-
}, [duration, tick]);
160-
161-
return [count, callback];
162-
}
163-
164-
const cache = new Map();
165-
function cachedWork(key, work) {
166-
const existing = cache.get(key);
167-
if (existing) return existing;
168-
169-
const created = work();
170-
cache.set(key, created);
171-
return created;
172-
}
173-
174-
function useCacheKey() {
175-
const [key] = useState(() => Object(Symbol(Math.random())));
176-
console.log('key', key);;
177-
return key;
178-
}
179-
180-
function useCached(work) {
181-
const key = useCacheKey();
182-
return cachedWork(key, work);
183-
}
184-
185-
function useAsyncCached(work) {
186-
const key = useCacheKey();
187-
console.log(key);
188-
189-
let record = cache.get(key);
190-
191-
console.log('record', record)
192-
193-
if (record === undefined) {
194-
record = {
195-
status: 'pending',
196-
result: undefined
197-
};
198-
cache.set(key, record);
199-
200-
const promise = work()
201-
.then(result => {
202-
record.status = 'succeeded';
203-
record.result = result;
204-
})
205-
.catch(error => {
206-
record.status = 'failed';
207-
record.result = error;
208-
});
209-
record.promise = promise;
210-
}
211-
212-
if (record.status === 'pending') {
213-
throw record.promise;
214-
}
215-
216-
if (record.status === 'failed') {
217-
throw record.result;
218-
}
219-
220-
return record.result;
221-
}
222-
223-
function SHAComponent() {
224-
const sha = useAsyncCached(() =>
225-
crypto.subtle.digest('SHA-256', new TextEncoder().encode('abc'))
226-
.then(arrayBuffer => {
227-
return Array.from(new Uint8Array(arrayBuffer), chunk => chunk.toString(16).padStart(2, '0')).join('');
228-
})
229-
);
230-
231-
return <div>{sha}</div>;
126+
const decimalFormatter = new Intl.NumberFormat();
127+
function Decimal({ children }) {
128+
return decimalFormatter.format(children);
232129
}
233130

234131
export default function App() {
235-
const [count, tick] = useDebouncer(1000);
132+
const [count, tick] = useDebouncedTick(1000);
236133
return <>
237134
<div>Hello!! {flavors.join(" ")}</div>
238135
<button onClick={tick}>Click</button>
239136
<div>{count}</div>
137+
<div>React was downloaded <Decimal>{reactDownloads.downloads}</Decimal> times last week.</div>
138+
<img src={image} />
240139
</>;
241140
}
242141
`.trim();
@@ -319,9 +218,26 @@ require(["vs/editor/editor.main"], function () {
319218
// would probably need to be more complex.
320219
build.onLoad({ filter: /.*/, namespace: 'http-url' }, async (args) => {
321220
//console.log('loading', args.path);
322-
let contents = await fetch(args.path).then(res => res.text());
323-
//console.log('loaded', args.path, contents);
324-
return { contents }
221+
return await fetch(args.path).then(res => {
222+
const contentType = res.headers.get('content-type') || '';
223+
224+
if (contentType.startsWith('image/')) {
225+
return res.arrayBuffer().then(buffer => {
226+
const url = URL.createObjectURL(new Blob([buffer], { type: contentType }));
227+
return { contents: url, loader: 'text' };
228+
})
229+
} else {
230+
return res.text().then(contents => {
231+
if (contents[0] === '{') {
232+
// Likely JSON.
233+
return { contents: `export default ${contents};` };
234+
}
235+
236+
return { contents };
237+
})
238+
}
239+
240+
});
325241
})
326242
},
327243
}
@@ -331,6 +247,7 @@ require(["vs/editor/editor.main"], function () {
331247
//return esbuild.transform(body, { loader: 'jsx', format: 'iife', globalName: 'exports', plugins: [exampleOnResolvePlugin] }).then(content => content.code);
332248
return esbuild.build({
333249
bundle: true,
250+
minify: true,
334251
stdin: {
335252
contents: `${prefix}\n${body ?? ""}\n${suffix}`,
336253
loader: 'jsx',

apps/components_guide_web/lib/components_guide_web/templates/react_typescript/logical-clocks.html.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function useTick() {
1919
## Debouncing
2020

2121
```ts
22-
export function useDebouncer(duration: number): readonly [number, EffectCallback] {
22+
export function useDebouncedTick(duration: number): readonly [number, EffectCallback] {
2323
const [count, tick] = useTick();
2424

2525
const callback = useMemo(() => {
@@ -43,8 +43,8 @@ export function useDebouncer(duration: number): readonly [number, EffectCallback
4343

4444
```ts
4545
export function useDebouncedEffect(effect: EffectCallback, duration: number, deps: DependencyList): void {
46-
const [count, didChange] = useDebouncer(duration);
47-
useEffect(didChange, deps); // When our deps change, notify our debouncer.
46+
const [count, tick] = useDebouncedTick(duration);
47+
useEffect(tick, deps); // When our deps change, notify our debouncer.
4848
useEffect(effect, [count]); // When our debouncer finishes, run our effect.
4949
}
5050
```

0 commit comments

Comments
 (0)