Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Begin site setup for www tko io #140

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/observable/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@
"url": "https://opensource.org/licenses/MIT"
}
]
}
}
6 changes: 6 additions & 0 deletions packages/observable/spec/subscribableBehaviors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ describe('Subscribable', function () {
expect(isSubscribable(null)).toEqual(false)
})

it('creates/has a Symbol.observable', () => {
const sub = new subscribable()
expect(Symbol.observable).toEqual(Symbol.for('@tko/Symbol.observable'))
expect(sub[Symbol.observable]()).toBe(sub)
})

it('Should be able to notify subscribers', function () {
var instance = new subscribable()
var notifiedValue
Expand Down
4 changes: 4 additions & 0 deletions packages/observable/src/subscribable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export { isSubscribable } from './subscribableSymbol'
// subscribed.
export const LATEST_VALUE = Symbol('Knockout latest value')

if (!Symbol.observable) {
Symbol.observable = Symbol.for('@tko/Symbol.observable')
}

export function subscribable () {
Object.setPrototypeOf(this, ko_subscribable_fn)
ko_subscribable_fn.init(this)
Expand Down
2 changes: 2 additions & 0 deletions sites/minimum-esm/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

include ../../tools/site.mk
9 changes: 9 additions & 0 deletions sites/minimum-esm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Sample Site

This is a trival setup, exhibiting a minimal configuration.

## Startup

```bash
$ make serve
```
49 changes: 49 additions & 0 deletions sites/minimum-esm/src/entry.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Builder } from '@tko/builder'

import { ComponentProvider } from '@tko/provider.component'
import { MultiProvider } from '@tko/provider.multi'
import {
NativeProvider
} from '@tko/provider.native'

import { bindings as coreBindings } from '@tko/binding.core'
import { bindings as componentBindings } from '@tko/binding.component'

import { filters } from '@tko/filter.punches'

import components from '@tko/utils.component'
import { createElement, Fragment } from '@tko/utils.jsx'


const builder = new Builder({
filters,
provider: new MultiProvider({
providers: [
new ComponentProvider(),
new NativeProvider(),
]
}),
bindings: [
coreBindings,
componentBindings,
],
extenders: [],
options: {},
})

const tko = builder.create({
jsx: {
createElement,
Fragment,
},
components,
version: 'live',
Component: components.ComponentABC,
})

class TestComponent extends components.ComponentABC {
get template () { return <span>hello ${new Date().toISOString()}</span> }
}
TestComponent.register()

tko.applyBindings()
7 changes: 7 additions & 0 deletions sites/minimum-esm/src/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

declare namespace JSX {
interface IntrinsicElements {
[elemName: string]: any;
}
}

8 changes: 8 additions & 0 deletions sites/minimum-esm/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html>
<head>
</head>
<body>
<test-component />
<script src='entry.js'></script>
</body>
</html>
21 changes: 21 additions & 0 deletions sites/minimum-esm/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"downlevelIteration": true,
"target": "ES2015",
"module": "ES2015",
"moduleResolution": "node",
"allowJs": true,
"importHelpers": true,
"strict": true,
"jsx": "react",
"jsxFactory": "tko.jsx.createElement",
"jsxFragmentFactory": "tko.jsx.Fragment",
"baseUrl": ".",
"paths": {
"*": [
"*",
"../../packages/*",
]
}
}
}
7 changes: 7 additions & 0 deletions sites/www.tko.io/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

include ../../tools/site.mk

dist/esbuild.wasm: node_modules
cp node_modules/esbuild-wasm/esbuild.wasm dist

build:: dist/esbuild.wasm
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
15 changes: 15 additions & 0 deletions sites/www.tko.io/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "www.tko.io",
"version": "1.0.0",
"description": "www.tko.io",
"repository": "https://github.com/knockout/tko",
"author": "The Knockout Team",
"license": "MIT",
"dependencies": {
"@monaco-editor/loader": "^1.1.1",
"@types/css-font-loading-module": "^0.0.5",
"esbuild-wasm": "^0.12.12",
"jss": "^10.6.0",
"jss-preset-default": "^10.6.0"
}
}
42 changes: 42 additions & 0 deletions sites/www.tko.io/src/EsbuildComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

import * as esbuild from 'esbuild-wasm'
import { observable, observableArray } from '@tko/observable'

import {TkoComponent} from './TkoComponent'


const wasmURL = './esbuild.wasm'

export class EsbuildComponent extends TkoComponent {
private esbuildInitialized: Promise<void>
protected code = observable('')
protected warnings = observableArray([])
protected errors = observableArray([])

constructor () {
super()
this.esbuildInitialized = Promise.resolve(this.initializeEsbuild())
}

async initializeEsbuild () {
await esbuild.initialize({ wasmURL })
}

protected async compile (code: string) {
try {
await this.esbuildInitialized
} catch (err) {
this.errors.push(err)
}
try {
const r = await esbuild.transform(code)
this.warnings(r.warnings)
this.errors([])
return r
} catch (err: esbuild.TransformFailure) {
this.warnings(err.warnings)
this.errors(err.errors)
return { code: '' }
}
}
}
119 changes: 119 additions & 0 deletions sites/www.tko.io/src/TkoComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { default as jss, StyleSheet } from 'jss'
import preset from "jss-preset-default"

import { tko } from './tko'

jss.setup(preset())

const JSS = Symbol('Memoized ViewComponent.jss')
const staticStyles: Record<string, StyleSheet> = {}

/**
* TkoComponent is a Knockout web-component base-class for all view components.
*
* It has builtin JSS styles.
*/
export abstract class TkoComponent extends tko.components.ComponentABC {
private static customElementName: string

dispose () {
super.dispose()
if (this._styles) { jss.removeStyleSheet(this._styles) }
}

/**
* @return {object|null} containing JSS-style classes that are specific to
* the instance.
*
* This offers more dynamic options than `static get css`, but at a
* substantial performance cost. Use sparingly.
*/
get css () { return {} as const }

/**
* @return {object} containing JSS-style classes that apply to every
* instance of this class.
*
* This is higher performance than `get css`
*/
static get css () { return {} as const }

/**
* Lazy getter, so subclass constructors can refer to observables and
* computeds added to the class in the constructor
* after `super` has been called.
*/
get styles () : StyleSheet {
if (!this.css) { return { classes: {} } as StyleSheet }
const options = {
meta: `⚙️ Dynamic Classes for ${this.constructor.name}>`,
link: true,
classNamePrefix: `${this.constructor.name}--`
}
const sheet = jss.createStyleSheet(this.css, options).attach()
return this._styles || (this._styles = sheet)
}

/**
* Static styles are created for each class (not each instance).
*/
static get styles () : StyleSheet {
if (this.name in staticStyles) { return staticStyles[this.name] }
if (!this.css) { return { classes: {} } as StyleSheet }
const options = {
meta: `🎨 Static Classes for ${this.name}`,
link: true, // Warning: [JSS] Failed to execute 'insertRule' on 'CSSStyleSheet': Failed to insert the rule.
classNamePrefix: `${this.name}__`
}
const sheet = jss.createStyleSheet(this.css, options).attach()
return (staticStyles[this.name] = sheet)
}

/**
* Return the classes object for our JSS/CSS.
*/
get jss (): Record<string, string> {
return this[JSS] || (this[JSS] = {
...(this.constructor as typeof TkoComponent).styles.classes,
...this.styles.classes,
})
}

/**
* Called when the component is removed from the DOM. Must be on the
* prototype (for performance we don't add a callback for every component).
*/
disconnectedCallback? (node: HTMLElement): void

get template () { return Symbol('No template') }

/**
* We overload the Register to create a custom element that
* triggers a `disconnectedCallback`. This is simpler and faster
* than using MutationObserver to trigger when an element
* is removed from the DOM.
*/
static register (name = this.customElementName) {
const wantsCallback = 'disconnectedCallback' in this.prototype
if (wantsCallback) { this.defineCustomElementForDisconnectCallback(name) }
return super.register(name)
}

/**
* Define customElement that triggers a disconnection callback when the
* element is removed from the DOM.
*/
private static defineCustomElementForDisconnectCallback (name: string) {
if (globalThis.customElements) {
customElements.define(name, class extends HTMLElement {
disconnectedCallback (this: HTMLElement) {
const component = tko.dataFor(this.children[0])
if (component) { component.disconnectedCallback(this) }
}
})
} else if (!globalThis.process) {
console.warn(`"window.customElements" is not available. Unable to
register life-cycle disconnection callback.`)
}
}
}
42 changes: 42 additions & 0 deletions sites/www.tko.io/src/WithFontsView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { observable } from '@tko/observable'
import { computed } from '@tko/computed'

import { TkoComponent } from './TkoComponent'

export abstract class WithFontsView extends TkoComponent {
static fontsLoaded = observable(false)

protected abstract bodyHTML: any

/**
* document.fonts.ready is a promise that resolves when all
* the fonts on the screen are loaded.
*/
private async monitorFontsLoading () {
const waitForFontsToBeOnScreen = Promise.resolve()
await waitForFontsToBeOnScreen
await document.fonts.ready
WithFontsView.fontsLoaded(true)
}

static get css () {
const { fontsLoaded } = this
const opacityUntilFontsLoaded = computed(() => fontsLoaded() ? 1 : 0)

return {
...super.css,


'@global': {
body: {
opacity: opacityUntilFontsLoaded,
},
},
}
}

get template () {
this.monitorFontsLoading()
return <>{this.bodyHTML()}</>
}
}
5 changes: 5 additions & 0 deletions sites/www.tko.io/src/entry.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { tko } from './tko'

import './www-tko-io'

tko.applyBindings()
13 changes: 13 additions & 0 deletions sites/www.tko.io/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<html>
<head>
<title>TKO.io</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto&family=Pacifico&display=swap" rel="stylesheet">

</head>
<body>
<script async type="module" src='entry.js'></script>
<www-tko-io />
</body>
</html>
Loading