@davidsouther/jiffies 1.1.0 → 2.0.2
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/build/pico.css +2466 -0
- package/build/pico.css.map +1 -0
- package/{build → lib/cjs}/assert.d.ts +23 -23
- package/lib/cjs/assert.js +40 -0
- package/{build → lib/cjs}/case.d.ts +1 -1
- package/lib/cjs/case.js +9 -0
- package/{build → lib/cjs}/components/button_bar.d.ts +8 -8
- package/lib/cjs/components/button_bar.js +29 -0
- package/{build → lib/cjs}/components/inline_edit.d.ts +12 -12
- package/lib/cjs/components/inline_edit.js +51 -0
- package/{build → lib/cjs}/components/logger.d.ts +6 -6
- package/lib/cjs/components/logger.js +27 -0
- package/lib/cjs/components/select.d.ts +10 -0
- package/lib/cjs/components/select.js +6 -0
- package/lib/cjs/components/test.d.ts +1 -0
- package/lib/cjs/components/test.js +7 -0
- package/{build → lib/cjs}/components/virtual_scroll.d.ts +40 -40
- package/lib/cjs/components/virtual_scroll.js +102 -0
- package/{build → lib/cjs}/components/virtual_scroll.test.d.ts +1 -1
- package/lib/cjs/components/virtual_scroll.test.js +22 -0
- package/{build → lib/cjs}/context.d.ts +15 -15
- package/lib/cjs/context.js +48 -0
- package/{build → lib/cjs}/context.test.d.ts +1 -1
- package/lib/cjs/context.test.js +48 -0
- package/lib/cjs/debounce.d.ts +1 -0
- package/lib/cjs/debounce.js +12 -0
- package/lib/cjs/diff.d.ts +15 -0
- package/lib/cjs/diff.js +58 -0
- package/{build/components/test.d.ts → lib/cjs/diff.test.d.ts} +1 -1
- package/lib/cjs/diff.test.js +41 -0
- package/{build → lib/cjs}/display.d.ts +5 -5
- package/lib/cjs/display.js +16 -0
- package/{build → lib/cjs}/dom/css/border.d.ts +11 -11
- package/lib/cjs/dom/css/border.js +33 -0
- package/{build → lib/cjs}/dom/css/constants.d.ts +31 -31
- package/lib/cjs/dom/css/constants.js +31 -0
- package/{build → lib/cjs}/dom/css/core.d.ts +5 -5
- package/lib/cjs/dom/css/core.js +31 -0
- package/{build → lib/cjs}/dom/css/fstyle.d.ts +5 -5
- package/lib/cjs/dom/css/fstyle.js +36 -0
- package/{build → lib/cjs}/dom/css/sizing.d.ts +5 -5
- package/lib/cjs/dom/css/sizing.js +14 -0
- package/{build → lib/cjs}/dom/dom.d.ts +27 -26
- package/lib/cjs/dom/dom.js +110 -0
- package/{build → lib/cjs}/dom/fc.d.ts +14 -14
- package/lib/cjs/dom/fc.js +39 -0
- package/{build → lib/cjs}/dom/fc.test.d.ts +1 -1
- package/lib/cjs/dom/fc.test.js +23 -0
- package/{build → lib/cjs}/dom/form/form.app.d.ts +1 -1
- package/lib/cjs/dom/form/form.app.js +27 -0
- package/{build → lib/cjs}/dom/form/form.d.ts +26 -26
- package/lib/cjs/dom/form/form.js +49 -0
- package/{build → lib/cjs}/dom/form/form.test.d.ts +0 -0
- package/{build → lib/cjs}/dom/form/form.test.js +1 -1
- package/{build → lib/cjs}/dom/html.d.ts +113 -113
- package/lib/cjs/dom/html.js +119 -0
- package/{build → lib/cjs}/dom/html.test.d.ts +1 -1
- package/lib/cjs/dom/html.test.js +60 -0
- package/lib/cjs/dom/observable.d.ts +2 -0
- package/lib/cjs/dom/observable.js +10 -0
- package/{build/observable → lib/cjs/dom}/observable.test.d.ts +1 -1
- package/lib/cjs/dom/observable.test.js +35 -0
- package/{build → lib/cjs}/dom/provide.d.ts +3 -3
- package/lib/cjs/dom/provide.js +12 -0
- package/{build → lib/cjs}/dom/router/link.d.ts +6 -6
- package/lib/cjs/dom/router/link.js +7 -0
- package/{build → lib/cjs}/dom/router/router.d.ts +12 -12
- package/lib/cjs/dom/router/router.js +52 -0
- package/{build → lib/cjs}/dom/svg.d.ts +64 -64
- package/lib/cjs/dom/svg.js +69 -0
- package/lib/cjs/dom/test.d.ts +1 -0
- package/lib/cjs/dom/test.js +13 -0
- package/{build → lib/cjs}/dom/types/css.d.ts +6612 -6612
- package/lib/cjs/dom/types/css.js +24 -0
- package/{build → lib/cjs}/dom/types/dom.d.ts +0 -0
- package/{build → lib/cjs}/dom/types/dom.js +1 -1
- package/{build → lib/cjs}/dom/types/html.d.ts +616 -616
- package/lib/cjs/dom/types/html.js +2 -0
- package/{build → lib/cjs}/dom/xml.d.ts +1 -1
- package/lib/cjs/dom/xml.js +8 -0
- package/{build → lib/cjs}/equal.d.ts +5 -5
- package/lib/cjs/equal.js +43 -0
- package/{build → lib/cjs}/equal.test.d.ts +1 -1
- package/lib/cjs/equal.test.js +22 -0
- package/{build → lib/cjs}/flags.d.ts +7 -7
- package/lib/cjs/flags.js +52 -0
- package/{build → lib/cjs}/flags.test.d.ts +1 -1
- package/lib/cjs/flags.test.js +37 -0
- package/{build → lib/cjs}/fs.d.ts +48 -48
- package/lib/cjs/fs.js +152 -0
- package/{build → lib/cjs}/fs.test.d.ts +1 -1
- package/lib/cjs/fs.test.js +45 -0
- package/{build → lib/cjs}/generator.d.ts +1 -1
- package/lib/cjs/generator.js +14 -0
- package/{build → lib/cjs}/generator.test.d.ts +1 -1
- package/lib/cjs/generator.test.js +26 -0
- package/{build → lib/cjs}/is_browser.d.ts +1 -1
- package/lib/cjs/is_browser.js +4 -0
- package/{build → lib/cjs}/loader.d.mts +22 -22
- package/lib/cjs/loader.mjs +40 -0
- package/{build → lib/cjs}/lock.d.ts +1 -1
- package/lib/cjs/lock.js +27 -0
- package/{build → lib/cjs}/lock.test.d.ts +1 -1
- package/lib/cjs/lock.test.js +18 -0
- package/{build → lib/cjs}/log.d.ts +26 -26
- package/lib/cjs/log.js +54 -0
- package/lib/cjs/observable/event.d.ts +35 -0
- package/lib/cjs/observable/event.js +61 -0
- package/lib/cjs/observable/observable.d.ts +132 -0
- package/lib/cjs/observable/observable.js +363 -0
- package/lib/cjs/observable/observable.test.d.ts +1 -0
- package/lib/cjs/observable/observable.test.js +65 -0
- package/{build → lib/cjs}/range.d.ts +1 -1
- package/lib/cjs/range.js +11 -0
- package/{build → lib/cjs}/result.d.ts +31 -31
- package/lib/cjs/result.js +80 -0
- package/{build → lib/cjs}/result.test.d.ts +1 -1
- package/lib/cjs/result.test.js +73 -0
- package/{build → lib/cjs}/safe.d.ts +1 -1
- package/lib/cjs/safe.js +14 -0
- package/{build → lib/cjs}/scope/describe.d.ts +18 -18
- package/lib/cjs/scope/describe.js +73 -0
- package/{build → lib/cjs}/scope/display/console.d.ts +2 -2
- package/lib/cjs/scope/display/console.js +25 -0
- package/{build → lib/cjs}/scope/display/dom.d.ts +3 -3
- package/lib/cjs/scope/display/dom.js +30 -0
- package/{build → lib/cjs}/scope/display/junit.d.ts +2 -2
- package/lib/cjs/scope/display/junit.js +21 -0
- package/{build → lib/cjs}/scope/execute.d.ts +12 -12
- package/lib/cjs/scope/execute.js +91 -0
- package/{build → lib/cjs}/scope/expect.d.ts +23 -23
- package/lib/cjs/scope/expect.js +114 -0
- package/{build → lib/cjs}/scope/fix.d.ts +4 -4
- package/lib/cjs/scope/fix.js +26 -0
- package/{build → lib/cjs}/scope/index.d.ts +3 -3
- package/lib/cjs/scope/index.js +15 -0
- package/{build → lib/cjs}/scope/scope.d.ts +17 -17
- package/lib/cjs/scope/scope.js +2 -0
- package/lib/cjs/scope/state.d.ts +1 -0
- package/lib/cjs/scope/state.js +11 -0
- package/{build → lib/cjs}/server/http/apps.d.ts +5 -5
- package/lib/cjs/server/http/apps.js +27 -0
- package/{build → lib/cjs}/server/http/css.d.ts +5 -5
- package/lib/cjs/server/http/css.js +54 -0
- package/{build → lib/cjs}/server/http/index.d.ts +21 -21
- package/lib/cjs/server/http/index.js +77 -0
- package/{build → lib/cjs}/server/http/response.d.ts +4 -4
- package/lib/cjs/server/http/response.js +45 -0
- package/{build → lib/cjs}/server/http/sitemap.d.ts +2 -2
- package/lib/cjs/server/http/sitemap.js +46 -0
- package/{build → lib/cjs}/server/http/static.d.ts +2 -2
- package/lib/cjs/server/http/static.js +25 -0
- package/{build → lib/cjs}/server/http/typescript.d.ts +5 -5
- package/lib/cjs/server/http/typescript.js +44 -0
- package/{build → lib/cjs}/server/main.d.ts +2 -2
- package/lib/cjs/server/main.js +14 -0
- package/{build → lib/cjs}/test.d.mts +2 -2
- package/lib/cjs/test.mjs +28 -0
- package/{build → lib/cjs}/test_all.d.ts +9 -7
- package/lib/cjs/test_all.js +30 -0
- package/{build → lib/cjs}/transpile.d.mts +3 -3
- package/lib/cjs/transpile.mjs +22 -0
- package/lib/cjs/tsconfig.tsbuildinfo +1 -0
- package/lib/esm/assert.d.ts +23 -0
- package/{build → lib/esm}/assert.js +33 -33
- package/lib/esm/case.d.ts +1 -0
- package/{build → lib/esm}/case.js +5 -5
- package/lib/esm/components/button_bar.d.ts +8 -0
- package/{build → lib/esm}/components/button_bar.js +27 -27
- package/lib/esm/components/inline_edit.d.ts +12 -0
- package/{build → lib/esm}/components/inline_edit.js +48 -48
- package/lib/esm/components/logger.d.ts +6 -0
- package/{build → lib/esm}/components/logger.js +22 -22
- package/lib/esm/components/select.d.ts +10 -0
- package/{build → lib/esm}/components/select.js +3 -3
- package/lib/esm/components/test.d.ts +1 -0
- package/lib/esm/components/test.js +3 -0
- package/lib/esm/components/virtual_scroll.d.ts +40 -0
- package/{build → lib/esm}/components/virtual_scroll.js +94 -94
- package/lib/esm/components/virtual_scroll.test.d.ts +1 -0
- package/{build → lib/esm}/components/virtual_scroll.test.js +20 -21
- package/lib/esm/context.d.ts +15 -0
- package/{build → lib/esm}/context.js +43 -43
- package/lib/esm/context.test.d.ts +1 -0
- package/{build → lib/esm}/context.test.js +46 -46
- package/lib/esm/debounce.d.ts +1 -0
- package/{build → lib/esm}/debounce.js +8 -7
- package/lib/esm/diff.d.ts +15 -0
- package/lib/esm/diff.js +54 -0
- package/lib/esm/diff.test.d.ts +1 -0
- package/lib/esm/diff.test.js +39 -0
- package/lib/esm/display.d.ts +5 -0
- package/{build → lib/esm}/display.js +11 -11
- package/lib/esm/dom/css/border.d.ts +11 -0
- package/{build → lib/esm}/dom/css/border.js +27 -27
- package/lib/esm/dom/css/constants.d.ts +31 -0
- package/{build → lib/esm}/dom/css/constants.js +28 -28
- package/lib/esm/dom/css/core.d.ts +5 -0
- package/{build → lib/esm}/dom/css/core.js +24 -24
- package/lib/esm/dom/css/fstyle.d.ts +5 -0
- package/{build → lib/esm}/dom/css/fstyle.js +32 -32
- package/lib/esm/dom/css/sizing.d.ts +5 -0
- package/{build → lib/esm}/dom/css/sizing.js +10 -10
- package/lib/esm/dom/dom.d.ts +27 -0
- package/{build → lib/esm}/dom/dom.js +104 -95
- package/lib/esm/dom/fc.d.ts +14 -0
- package/{build → lib/esm}/dom/fc.js +35 -36
- package/lib/esm/dom/fc.test.d.ts +1 -0
- package/{build → lib/esm}/dom/fc.test.js +21 -21
- package/lib/esm/dom/form/form.app.d.ts +1 -0
- package/{build → lib/esm}/dom/form/form.app.js +23 -23
- package/lib/esm/dom/form/form.d.ts +26 -0
- package/{build → lib/esm}/dom/form/form.js +34 -34
- package/lib/esm/dom/form/form.test.d.ts +0 -0
- package/lib/esm/dom/form/form.test.js +1 -0
- package/lib/esm/dom/html.d.ts +113 -0
- package/{build → lib/esm}/dom/html.js +114 -114
- package/lib/esm/dom/html.test.d.ts +1 -0
- package/{build → lib/esm}/dom/html.test.js +58 -58
- package/lib/esm/dom/observable.d.ts +2 -0
- package/lib/esm/dom/observable.js +6 -0
- package/lib/esm/dom/observable.test.d.ts +1 -0
- package/lib/esm/dom/observable.test.js +33 -0
- package/lib/esm/dom/provide.d.ts +3 -0
- package/{build → lib/esm}/dom/provide.js +7 -7
- package/lib/esm/dom/router/link.d.ts +6 -0
- package/{build → lib/esm}/dom/router/link.js +3 -3
- package/lib/esm/dom/router/router.d.ts +12 -0
- package/{build → lib/esm}/dom/router/router.js +49 -49
- package/lib/esm/dom/svg.d.ts +64 -0
- package/{build → lib/esm}/dom/svg.js +65 -65
- package/lib/esm/dom/test.d.ts +1 -0
- package/lib/esm/dom/test.js +9 -0
- package/lib/esm/dom/types/css.d.ts +6612 -0
- package/{build → lib/esm}/dom/types/css.js +23 -23
- package/lib/esm/dom/types/dom.d.ts +0 -0
- package/lib/esm/dom/types/dom.js +1 -0
- package/lib/esm/dom/types/html.d.ts +616 -0
- package/{build → lib/esm}/dom/types/html.js +1 -1
- package/lib/esm/dom/xml.d.ts +1 -0
- package/{build → lib/esm}/dom/xml.js +4 -4
- package/lib/esm/equal.d.ts +5 -0
- package/{build → lib/esm}/equal.js +37 -37
- package/lib/esm/equal.test.d.ts +1 -0
- package/{build → lib/esm}/equal.test.js +20 -20
- package/lib/esm/flags.d.ts +7 -0
- package/{build → lib/esm}/flags.js +48 -48
- package/lib/esm/flags.test.d.ts +1 -0
- package/{build → lib/esm}/flags.test.js +35 -35
- package/lib/esm/fs.d.ts +48 -0
- package/{build → lib/esm}/fs.js +145 -144
- package/lib/esm/fs.test.d.ts +1 -0
- package/{build → lib/esm}/fs.test.js +43 -43
- package/lib/esm/generator.d.ts +1 -0
- package/{build → lib/esm}/generator.js +10 -10
- package/lib/esm/generator.test.d.ts +1 -0
- package/{build → lib/esm}/generator.test.js +24 -24
- package/lib/esm/is_browser.d.ts +1 -0
- package/{build → lib/esm}/is_browser.js +1 -1
- package/lib/esm/loader.d.mts +22 -0
- package/{build → lib/esm}/loader.mjs +35 -35
- package/lib/esm/lock.d.ts +1 -0
- package/{build → lib/esm}/lock.js +23 -23
- package/lib/esm/lock.test.d.ts +1 -0
- package/{build → lib/esm}/lock.test.js +16 -16
- package/lib/esm/log.d.ts +26 -0
- package/{build → lib/esm}/log.js +46 -46
- package/lib/esm/observable/event.d.ts +35 -0
- package/lib/esm/observable/event.js +46 -0
- package/lib/esm/observable/observable.d.ts +132 -0
- package/lib/esm/observable/observable.js +343 -0
- package/lib/esm/observable/observable.test.d.ts +1 -0
- package/lib/esm/observable/observable.test.js +63 -0
- package/lib/esm/range.d.ts +1 -0
- package/{build → lib/esm}/range.js +7 -7
- package/lib/esm/result.d.ts +31 -0
- package/{build → lib/esm}/result.js +65 -65
- package/lib/esm/result.test.d.ts +1 -0
- package/{build → lib/esm}/result.test.js +71 -71
- package/lib/esm/safe.d.ts +1 -0
- package/{build → lib/esm}/safe.js +10 -10
- package/lib/esm/scope/describe.d.ts +18 -0
- package/{build → lib/esm}/scope/describe.js +60 -61
- package/lib/esm/scope/display/console.d.ts +2 -0
- package/{build → lib/esm}/scope/display/console.js +21 -21
- package/lib/esm/scope/display/dom.d.ts +3 -0
- package/{build → lib/esm}/scope/display/dom.js +26 -26
- package/lib/esm/scope/display/junit.d.ts +2 -0
- package/{build → lib/esm}/scope/display/junit.js +17 -17
- package/lib/esm/scope/execute.d.ts +12 -0
- package/{build → lib/esm}/scope/execute.js +85 -85
- package/lib/esm/scope/expect.d.ts +23 -0
- package/{build → lib/esm}/scope/expect.js +108 -108
- package/lib/esm/scope/fix.d.ts +4 -0
- package/{build → lib/esm}/scope/fix.js +22 -22
- package/lib/esm/scope/index.d.ts +3 -0
- package/{build → lib/esm}/scope/index.js +3 -3
- package/lib/esm/scope/scope.d.ts +17 -0
- package/{build → lib/esm}/scope/scope.js +1 -1
- package/lib/esm/scope/state.d.ts +1 -0
- package/lib/esm/scope/state.js +7 -0
- package/lib/esm/server/http/apps.d.ts +5 -0
- package/{build → lib/esm}/server/http/apps.js +23 -23
- package/lib/esm/server/http/css.d.ts +5 -0
- package/{build → lib/esm}/server/http/css.js +50 -50
- package/lib/esm/server/http/index.d.ts +21 -0
- package/{build → lib/esm}/server/http/index.js +73 -73
- package/lib/esm/server/http/response.d.ts +4 -0
- package/{build → lib/esm}/server/http/response.js +40 -40
- package/lib/esm/server/http/sitemap.d.ts +2 -0
- package/{build → lib/esm}/server/http/sitemap.js +42 -42
- package/lib/esm/server/http/static.d.ts +2 -0
- package/{build → lib/esm}/server/http/static.js +21 -21
- package/lib/esm/server/http/typescript.d.ts +5 -0
- package/{build → lib/esm}/server/http/typescript.js +40 -40
- package/lib/esm/server/main.d.ts +2 -0
- package/{build → lib/esm}/server/main.js +12 -9
- package/lib/esm/test.d.mts +2 -0
- package/lib/esm/test.mjs +26 -0
- package/lib/esm/test_all.d.ts +9 -0
- package/{build → lib/esm}/test_all.js +28 -18
- package/lib/esm/transpile.d.mts +3 -0
- package/{build → lib/esm}/transpile.mjs +18 -18
- package/lib/esm/tsconfig.tsbuildinfo +1 -0
- package/package.json +16 -17
- package/src/assert.ts +1 -1
- package/src/components/button_bar.ts +3 -3
- package/src/components/inline_edit.ts +3 -3
- package/src/components/logger.ts +3 -3
- package/src/components/select.ts +3 -3
- package/src/components/test.js +3 -2
- package/src/context.ts +3 -3
- package/src/debounce.ts +2 -1
- package/src/diff.ts +2 -2
- package/src/display.ts +2 -2
- package/src/dom/css/border.ts +3 -3
- package/src/dom/css/core.ts +1 -1
- package/src/dom/css/fstyle.ts +2 -2
- package/src/dom/css/sizing.ts +1 -1
- package/src/dom/dom.ts +1 -1
- package/src/dom/fc.test.ts +3 -3
- package/src/dom/fc.ts +1 -1
- package/src/dom/form/form.app.ts +2 -2
- package/src/dom/form/form.ts +3 -3
- package/src/dom/html.test.ts +3 -3
- package/src/dom/html.ts +1 -1
- package/src/dom/observable.test.ts +6 -6
- package/src/dom/observable.ts +1 -1
- package/src/dom/provide.ts +1 -1
- package/src/dom/router/link.ts +2 -2
- package/src/dom/router/router.ts +2 -2
- package/src/dom/svg.ts +1 -1
- package/src/dom/test.ts +8 -6
- package/src/dom/types/html.ts +1 -1
- package/src/equal.ts +1 -1
- package/src/flags.ts +1 -1
- package/src/fs.ts +5 -4
- package/src/index.html +6 -6
- package/src/observable/event.ts +2 -2
- package/src/observable/observable.test.ts +2 -2
- package/src/observable/observable.ts +72 -12
- package/src/pico/_variables.scss +1 -1
- package/src/pico/layout/_sectioning.scss +2 -0
- package/src/result.ts +1 -1
- package/src/scope/describe.ts +2 -5
- package/src/scope/display/console.ts +4 -4
- package/src/scope/display/dom.ts +6 -6
- package/src/scope/display/junit.ts +3 -3
- package/src/scope/execute.ts +2 -2
- package/src/scope/expect.ts +3 -3
- package/src/scope/state.ts +10 -0
- package/src/server/http/sitemap.ts +1 -1
- package/src/server/main.ts +9 -2
- package/src/test.mjs +22 -18
- package/src/test_all.ts +10 -0
- package/build/components/select.d.ts +0 -13
- package/build/components/test.js +0 -2
- package/build/debounce.d.ts +0 -1
- package/build/dom/test.d.ts +0 -1
- package/build/dom/test.js +0 -2
- package/build/observable/observable.d.ts +0 -83
- package/build/observable/observable.js +0 -148
- package/build/observable/observable.test.js +0 -21
- package/build/test.mjs +0 -23
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
declare type AssertMessage = string | (() => string);
|
|
2
|
+
/**
|
|
3
|
+
* Throw an error when a condition is not met.
|
|
4
|
+
*/
|
|
5
|
+
export declare function assert(condition: boolean, message?: AssertMessage): void | never;
|
|
6
|
+
/**
|
|
7
|
+
* Given a value, return it if it is not null nor undefined. Otherwise throw an
|
|
8
|
+
* error.
|
|
9
|
+
*
|
|
10
|
+
* @template T
|
|
11
|
+
* @returns {NonNullable<T>}
|
|
12
|
+
*/
|
|
13
|
+
export declare function assertExists<T>(t: T, message?: AssertMessage): NonNullable<T>;
|
|
14
|
+
/**
|
|
15
|
+
* @param {*} n
|
|
16
|
+
* @returns string
|
|
17
|
+
*/
|
|
18
|
+
export declare function assertString(n: unknown, message?: AssertMessage): string;
|
|
19
|
+
/**
|
|
20
|
+
* Compile time assertion that no value will used at this point in control flow.
|
|
21
|
+
*/
|
|
22
|
+
export declare function checkExhaustive(value: never, message?: AssertMessage): never;
|
|
23
|
+
export {};
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Throw an error when a condition is not met.
|
|
3
|
-
*/
|
|
4
|
-
export function assert(condition, message = "Assertion failed") {
|
|
5
|
-
if (!condition) {
|
|
6
|
-
throw new Error(message instanceof Function ? message() : message);
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Given a value, return it if it is not null nor undefined. Otherwise throw an
|
|
11
|
-
* error.
|
|
12
|
-
*
|
|
13
|
-
* @template T
|
|
14
|
-
* @returns {NonNullable<T>}
|
|
15
|
-
*/
|
|
16
|
-
export function assertExists(t, message = "Assertion failed: value does not exist") {
|
|
17
|
-
assert(t != null, message);
|
|
18
|
-
return t;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* @param {*} n
|
|
22
|
-
* @returns string
|
|
23
|
-
*/
|
|
24
|
-
export function assertString(n, message = () => `Assertion failed: ${n} is not a string`) {
|
|
25
|
-
assert(typeof n
|
|
26
|
-
return n;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Compile time assertion that no value will used at this point in control flow.
|
|
30
|
-
*/
|
|
31
|
-
export function checkExhaustive(value, message = `Unexpected value ${value}`) {
|
|
32
|
-
throw new Error(message instanceof Function ? message() : message);
|
|
33
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Throw an error when a condition is not met.
|
|
3
|
+
*/
|
|
4
|
+
export function assert(condition, message = "Assertion failed") {
|
|
5
|
+
if (!condition) {
|
|
6
|
+
throw new Error(message instanceof Function ? message() : message);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Given a value, return it if it is not null nor undefined. Otherwise throw an
|
|
11
|
+
* error.
|
|
12
|
+
*
|
|
13
|
+
* @template T
|
|
14
|
+
* @returns {NonNullable<T>}
|
|
15
|
+
*/
|
|
16
|
+
export function assertExists(t, message = "Assertion failed: value does not exist") {
|
|
17
|
+
assert(t != null, message);
|
|
18
|
+
return t;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* @param {*} n
|
|
22
|
+
* @returns string
|
|
23
|
+
*/
|
|
24
|
+
export function assertString(n, message = () => `Assertion failed: ${n} is not a string`) {
|
|
25
|
+
assert(typeof n === "string", message);
|
|
26
|
+
return n;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Compile time assertion that no value will used at this point in control flow.
|
|
30
|
+
*/
|
|
31
|
+
export function checkExhaustive(value, message = `Unexpected value ${value}`) {
|
|
32
|
+
throw new Error(message instanceof Function ? message() : message);
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function dashCase(identifier: string): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export function dashCase(identifier) {
|
|
2
|
-
return identifier
|
|
3
|
-
.replace(/([a-z])([A-Z])/g, (_, a, b) => `${a}-${b.toLowerCase()}`)
|
|
4
|
-
.replace(/ ([A-Z])/g, (_, b) => `-${b.toLowerCase()}`);
|
|
5
|
-
}
|
|
1
|
+
export function dashCase(identifier) {
|
|
2
|
+
return identifier
|
|
3
|
+
.replace(/([a-z])([A-Z])/g, (_, a, b) => `${a}-${b.toLowerCase()}`)
|
|
4
|
+
.replace(/ ([A-Z])/g, (_, b) => `-${b.toLowerCase()}`);
|
|
5
|
+
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { display } from "../display
|
|
2
|
-
import { FC } from "../dom/fc
|
|
3
|
-
import { fieldset, input, label } from "../dom/html
|
|
4
|
-
let buttonBarId = 1;
|
|
5
|
-
let nextId = () => buttonBarId++;
|
|
6
|
-
const ButtonBar = FC("button-bar", (el, { value, values, events }) => {
|
|
7
|
-
const name = `button-bar-${nextId()}`;
|
|
8
|
-
return fieldset({ class: "input-group" }, ...values
|
|
9
|
-
.map((option) => {
|
|
10
|
-
const opt = `${option}`.replace(/\s+/g, "_").toLowerCase();
|
|
11
|
-
const id = `${name}-${opt}`;
|
|
12
|
-
return [
|
|
13
|
-
label({ role: "button", htmlFor: id }, input({
|
|
14
|
-
type: "radio",
|
|
15
|
-
id,
|
|
16
|
-
name,
|
|
17
|
-
value: option,
|
|
18
|
-
checked: option === value,
|
|
19
|
-
events: {
|
|
20
|
-
change: () => events.onSelect(option),
|
|
21
|
-
},
|
|
22
|
-
}), display(option)),
|
|
23
|
-
];
|
|
24
|
-
})
|
|
25
|
-
.flat());
|
|
26
|
-
});
|
|
27
|
-
export default ButtonBar;
|
|
1
|
+
import { display } from "../display";
|
|
2
|
+
import { FC } from "../dom/fc";
|
|
3
|
+
import { fieldset, input, label } from "../dom/html";
|
|
4
|
+
let buttonBarId = 1;
|
|
5
|
+
let nextId = () => buttonBarId++;
|
|
6
|
+
const ButtonBar = FC("button-bar", (el, { value, values, events }) => {
|
|
7
|
+
const name = `button-bar-${nextId()}`;
|
|
8
|
+
return fieldset({ class: "input-group" }, ...values
|
|
9
|
+
.map((option) => {
|
|
10
|
+
const opt = `${option}`.replace(/\s+/g, "_").toLowerCase();
|
|
11
|
+
const id = `${name}-${opt}`;
|
|
12
|
+
return [
|
|
13
|
+
label({ role: "button", htmlFor: id }, input({
|
|
14
|
+
type: "radio",
|
|
15
|
+
id,
|
|
16
|
+
name,
|
|
17
|
+
value: option,
|
|
18
|
+
checked: option === value,
|
|
19
|
+
events: {
|
|
20
|
+
change: () => events.onSelect(option),
|
|
21
|
+
},
|
|
22
|
+
}), display(option)),
|
|
23
|
+
];
|
|
24
|
+
})
|
|
25
|
+
.flat());
|
|
26
|
+
});
|
|
27
|
+
export default ButtonBar;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface InlineEditState {
|
|
2
|
+
mode: number;
|
|
3
|
+
value: string;
|
|
4
|
+
}
|
|
5
|
+
export declare const InlineEdit: import("../dom/fc").FCComponentCtor<{
|
|
6
|
+
mode?: number | undefined;
|
|
7
|
+
value: string;
|
|
8
|
+
events: {
|
|
9
|
+
change: (value: string) => void;
|
|
10
|
+
};
|
|
11
|
+
}, InlineEditState>;
|
|
12
|
+
export default InlineEdit;
|
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
import { width } from "../dom/css/sizing
|
|
2
|
-
import { FC, State } from "../dom/fc
|
|
3
|
-
import { input, span } from "../dom/html
|
|
4
|
-
const Mode = { VIEW: 0, EDIT: 1 };
|
|
5
|
-
export const InlineEdit = FC("inline-edit", (el, { mode = Mode.VIEW, value, events }) => {
|
|
6
|
-
const state = (el[State] ??= { mode, value });
|
|
7
|
-
const render = () => {
|
|
8
|
-
switch (state.mode) {
|
|
9
|
-
case Mode.EDIT:
|
|
10
|
-
return edit();
|
|
11
|
-
case Mode.VIEW:
|
|
12
|
-
return view();
|
|
13
|
-
default:
|
|
14
|
-
return span();
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
const view = () => span({
|
|
18
|
-
style: { cursor: "text", ...width("full", "inline") },
|
|
19
|
-
events: {
|
|
20
|
-
click: () => {
|
|
21
|
-
state.mode = Mode.EDIT;
|
|
22
|
-
el.update(render());
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
}, state.value ?? "");
|
|
26
|
-
const edit = () => {
|
|
27
|
-
const edit = span({ style: { display: "block", position: "relative" } }, input({
|
|
28
|
-
style: {
|
|
29
|
-
zIndex: "10",
|
|
30
|
-
position: "absolute",
|
|
31
|
-
left: "0",
|
|
32
|
-
marginTop: "-0.375rem",
|
|
33
|
-
},
|
|
34
|
-
events: {
|
|
35
|
-
blur: ({ target }) => events.change(target?.value ?? ""),
|
|
36
|
-
},
|
|
37
|
-
type: "text",
|
|
38
|
-
value: state.value,
|
|
39
|
-
}), "\u00a0" // Hack to get the span to take up space
|
|
40
|
-
);
|
|
41
|
-
setTimeout(() => {
|
|
42
|
-
edit.dispatchEvent(new Event("focus"));
|
|
43
|
-
});
|
|
44
|
-
return edit;
|
|
45
|
-
};
|
|
46
|
-
return render();
|
|
47
|
-
});
|
|
48
|
-
export default InlineEdit;
|
|
1
|
+
import { width } from "../dom/css/sizing";
|
|
2
|
+
import { FC, State } from "../dom/fc";
|
|
3
|
+
import { input, span } from "../dom/html";
|
|
4
|
+
const Mode = { VIEW: 0, EDIT: 1 };
|
|
5
|
+
export const InlineEdit = FC("inline-edit", (el, { mode = Mode.VIEW, value, events }) => {
|
|
6
|
+
const state = (el[State] ??= { mode, value });
|
|
7
|
+
const render = () => {
|
|
8
|
+
switch (state.mode) {
|
|
9
|
+
case Mode.EDIT:
|
|
10
|
+
return edit();
|
|
11
|
+
case Mode.VIEW:
|
|
12
|
+
return view();
|
|
13
|
+
default:
|
|
14
|
+
return span();
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const view = () => span({
|
|
18
|
+
style: { cursor: "text", ...width("full", "inline") },
|
|
19
|
+
events: {
|
|
20
|
+
click: () => {
|
|
21
|
+
state.mode = Mode.EDIT;
|
|
22
|
+
el.update(render());
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
}, state.value ?? "");
|
|
26
|
+
const edit = () => {
|
|
27
|
+
const edit = span({ style: { display: "block", position: "relative" } }, input({
|
|
28
|
+
style: {
|
|
29
|
+
zIndex: "10",
|
|
30
|
+
position: "absolute",
|
|
31
|
+
left: "0",
|
|
32
|
+
marginTop: "-0.375rem",
|
|
33
|
+
},
|
|
34
|
+
events: {
|
|
35
|
+
blur: ({ target }) => events.change(target?.value ?? ""),
|
|
36
|
+
},
|
|
37
|
+
type: "text",
|
|
38
|
+
value: state.value,
|
|
39
|
+
}), "\u00a0" // Hack to get the span to take up space
|
|
40
|
+
);
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
edit.dispatchEvent(new Event("focus"));
|
|
43
|
+
});
|
|
44
|
+
return edit;
|
|
45
|
+
};
|
|
46
|
+
return render();
|
|
47
|
+
});
|
|
48
|
+
export default InlineEdit;
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { display } from "../display
|
|
2
|
-
import { div, span, ul, li, pre, code } from "../dom/html
|
|
3
|
-
import { LEVEL } from "../log
|
|
4
|
-
export function isHTMLLogger(logger) {
|
|
5
|
-
return logger.root != undefined;
|
|
6
|
-
}
|
|
7
|
-
export function makeHTMLLogger(name) {
|
|
8
|
-
let log;
|
|
9
|
-
const root = div(div(span(name)), (log = ul()));
|
|
10
|
-
const logger = { level: LEVEL.INFO, root };
|
|
11
|
-
function append(message) {
|
|
12
|
-
log.appendChild(li(pre(code(message))));
|
|
13
|
-
}
|
|
14
|
-
const logAt = (level) => (message) => level >= (logger.level ?? LEVEL.ERROR)
|
|
15
|
-
? append(display(message))
|
|
16
|
-
: undefined;
|
|
17
|
-
logger.debug = logAt(LEVEL.VERBOSE);
|
|
18
|
-
logger.info = logAt(LEVEL.INFO);
|
|
19
|
-
logger.warn = logAt(LEVEL.WARN);
|
|
20
|
-
logger.error = logAt(LEVEL.ERROR);
|
|
21
|
-
return logger;
|
|
22
|
-
}
|
|
1
|
+
import { display } from "../display";
|
|
2
|
+
import { div, span, ul, li, pre, code } from "../dom/html";
|
|
3
|
+
import { LEVEL } from "../log";
|
|
4
|
+
export function isHTMLLogger(logger) {
|
|
5
|
+
return logger.root != undefined;
|
|
6
|
+
}
|
|
7
|
+
export function makeHTMLLogger(name) {
|
|
8
|
+
let log;
|
|
9
|
+
const root = div(div(span(name)), (log = ul()));
|
|
10
|
+
const logger = { level: LEVEL.INFO, root };
|
|
11
|
+
function append(message) {
|
|
12
|
+
log.appendChild(li(pre(code(message))));
|
|
13
|
+
}
|
|
14
|
+
const logAt = (level) => (message) => level >= (logger.level ?? LEVEL.ERROR)
|
|
15
|
+
? append(display(message))
|
|
16
|
+
: undefined;
|
|
17
|
+
logger.debug = logAt(LEVEL.VERBOSE);
|
|
18
|
+
logger.info = logAt(LEVEL.INFO);
|
|
19
|
+
logger.warn = logAt(LEVEL.WARN);
|
|
20
|
+
logger.error = logAt(LEVEL.ERROR);
|
|
21
|
+
return logger;
|
|
22
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { FC } from "../dom/fc
|
|
2
|
-
import { option, select } from "../dom/html
|
|
3
|
-
export const Select = FC("jiffies-select", (el, { name, events: { change }, disabled, value, options }) => select({ name, events: { change }, disabled }, ...options.map(([v, name]) => option({ value: v, selected: value === v }, `${name}`))));
|
|
1
|
+
import { FC } from "../dom/fc";
|
|
2
|
+
import { option, select } from "../dom/html";
|
|
3
|
+
export const Select = FC("jiffies-select", (el, { name, events: { change }, disabled, value, options }) => select({ name, events: { change }, disabled }, ...options.map(([v, name]) => option({ value: v, selected: value === v }, `${name}`))));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function loadTests(): Promise<void>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface VirtualScrollSettings {
|
|
2
|
+
minIndex: number;
|
|
3
|
+
maxIndex: number;
|
|
4
|
+
startIndex: number;
|
|
5
|
+
itemHeight: number;
|
|
6
|
+
count: number;
|
|
7
|
+
tolerance: number;
|
|
8
|
+
}
|
|
9
|
+
export interface VirtualScrollDataAdapter<T> {
|
|
10
|
+
(offset: number, limit: number): Iterable<T>;
|
|
11
|
+
}
|
|
12
|
+
export declare function arrayAdapter<T>(data: T[]): VirtualScrollDataAdapter<T>;
|
|
13
|
+
export interface VirtualScrollProps<T, U extends HTMLElement> {
|
|
14
|
+
settings: Partial<VirtualScrollSettings>;
|
|
15
|
+
get: VirtualScrollDataAdapter<T>;
|
|
16
|
+
row: (t: T) => U;
|
|
17
|
+
}
|
|
18
|
+
export declare function fillVirtualScrollSettings(settings: Partial<VirtualScrollSettings>): VirtualScrollSettings;
|
|
19
|
+
export declare function initialState<T>(settings: VirtualScrollSettings): VirtualScrollState<T>;
|
|
20
|
+
export declare function getData<T>(minIndex: number, maxIndex: number, offset: number, limit: number, get: VirtualScrollDataAdapter<T>): T[];
|
|
21
|
+
export declare function doScroll<T>(scrollTop: number, state: VirtualScrollState<T>, get: VirtualScrollDataAdapter<T>): {
|
|
22
|
+
scrollTop: number;
|
|
23
|
+
topPaddingHeight: number;
|
|
24
|
+
bottomPaddingHeight: number;
|
|
25
|
+
data: T[];
|
|
26
|
+
};
|
|
27
|
+
interface VirtualScrollState<T, U extends HTMLElement = HTMLElement> {
|
|
28
|
+
settings: VirtualScrollSettings;
|
|
29
|
+
scrollTop: number;
|
|
30
|
+
bufferedItems: number;
|
|
31
|
+
totalHeight: number;
|
|
32
|
+
viewportHeight: number;
|
|
33
|
+
topPaddingHeight: number;
|
|
34
|
+
bottomPaddingHeight: number;
|
|
35
|
+
toleranceHeight: number;
|
|
36
|
+
data: T[];
|
|
37
|
+
rows: U[];
|
|
38
|
+
}
|
|
39
|
+
export declare const VirtualScroll: import("../dom/fc.js").FCComponentCtor<VirtualScrollProps<any, HTMLElement>, VirtualScrollState<any, HTMLElement>>;
|
|
40
|
+
export default VirtualScroll;
|
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
import { debounce } from "../debounce.js";
|
|
2
|
-
import { FC, State } from "../dom/fc.js";
|
|
3
|
-
import { div } from "../dom/html.js";
|
|
4
|
-
export function arrayAdapter(data) {
|
|
5
|
-
return (offset, limit) => data.slice(offset, offset + limit);
|
|
6
|
-
}
|
|
7
|
-
export function fillVirtualScrollSettings(settings) {
|
|
8
|
-
const { minIndex = 0, maxIndex =
|
|
9
|
-
return { minIndex, maxIndex, startIndex, itemHeight, count, tolerance };
|
|
10
|
-
}
|
|
11
|
-
export function initialState(settings) {
|
|
12
|
-
// From Denis Hilt, https://blog.logrocket.com/virtual-scrolling-core-principles-and-basic-implementation-in-react/
|
|
13
|
-
const { minIndex, maxIndex, startIndex, itemHeight, count, tolerance } = settings;
|
|
14
|
-
const bufferedItems = count + 2 * tolerance;
|
|
15
|
-
const itemsAbove = Math.max(0, startIndex - tolerance - minIndex);
|
|
16
|
-
const viewportHeight = count * itemHeight;
|
|
17
|
-
const totalHeight = (maxIndex - minIndex + 1) * itemHeight;
|
|
18
|
-
const toleranceHeight = tolerance * itemHeight;
|
|
19
|
-
const bufferHeight = viewportHeight + 2 * toleranceHeight;
|
|
20
|
-
const topPaddingHeight = itemsAbove * itemHeight;
|
|
21
|
-
const bottomPaddingHeight = totalHeight - (topPaddingHeight + bufferHeight);
|
|
22
|
-
return {
|
|
23
|
-
scrollTop: 0,
|
|
24
|
-
settings,
|
|
25
|
-
viewportHeight,
|
|
26
|
-
totalHeight,
|
|
27
|
-
toleranceHeight,
|
|
28
|
-
bufferedItems,
|
|
29
|
-
topPaddingHeight,
|
|
30
|
-
bottomPaddingHeight,
|
|
31
|
-
data: [],
|
|
32
|
-
rows: [],
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
export function getData(minIndex, maxIndex, offset, limit, get) {
|
|
36
|
-
const start = Math.max(0, minIndex, offset);
|
|
37
|
-
const end = Math.min(maxIndex, offset + limit - 1);
|
|
38
|
-
const data = get(start, end - start);
|
|
39
|
-
return [...data];
|
|
40
|
-
}
|
|
41
|
-
export function doScroll(scrollTop, state, get) {
|
|
42
|
-
const { totalHeight, toleranceHeight, bufferedItems, settings: { itemHeight, minIndex, maxIndex }, } = state;
|
|
43
|
-
const index = minIndex + Math.floor((scrollTop - toleranceHeight) / itemHeight);
|
|
44
|
-
const data = getData(minIndex, maxIndex, index, bufferedItems, get);
|
|
45
|
-
const topPaddingHeight = Math.max((index - minIndex) * itemHeight, 0);
|
|
46
|
-
const bottomPaddingHeight = Math.max(totalHeight - (topPaddingHeight + data.length * itemHeight), 0);
|
|
47
|
-
return { scrollTop, topPaddingHeight, bottomPaddingHeight, data };
|
|
48
|
-
}
|
|
49
|
-
// export interface VirtualScroll<T, U extends HTMLElement> {
|
|
50
|
-
// state: VirtualScrollState<T>;
|
|
51
|
-
// rows: UHTMLElement<U>[];
|
|
52
|
-
// }
|
|
53
|
-
export const VirtualScroll = FC("virtual-scroll", (element, props) => {
|
|
54
|
-
const settings = fillVirtualScrollSettings(props.settings);
|
|
55
|
-
const state = (element[State] = {
|
|
56
|
-
...initialState(settings),
|
|
57
|
-
...element[State],
|
|
58
|
-
});
|
|
59
|
-
const scrollTo = ({ target } = { target: state }) => {
|
|
60
|
-
const scrollTop = target?.scrollTop ?? state.topPaddingHeight;
|
|
61
|
-
const updatedSate = {
|
|
62
|
-
...state,
|
|
63
|
-
...doScroll(scrollTop, state, props.get),
|
|
64
|
-
};
|
|
65
|
-
setState(updatedSate);
|
|
66
|
-
};
|
|
67
|
-
const viewportElement = div({
|
|
68
|
-
style: { height: `${state.viewportHeight}px`, overflowY: "scroll" },
|
|
69
|
-
events: { scroll: debounce(scrollTo, 0) },
|
|
70
|
-
});
|
|
71
|
-
setTimeout(() => {
|
|
72
|
-
viewportElement.scroll({ top: state.scrollTop });
|
|
73
|
-
});
|
|
74
|
-
const setState = (newState) => {
|
|
75
|
-
state.scrollTop = newState.scrollTop;
|
|
76
|
-
state.topPaddingHeight = newState.topPaddingHeight;
|
|
77
|
-
state.bottomPaddingHeight = newState.bottomPaddingHeight;
|
|
78
|
-
state.data = newState.data;
|
|
79
|
-
state.rows = state.data.map(props.row);
|
|
80
|
-
viewportElement.update(div({
|
|
81
|
-
class: "VirtualScroll__topPadding",
|
|
82
|
-
style: { height: `${state.topPaddingHeight}px` },
|
|
83
|
-
}), ...(state.rows ?? []).map((row, i) => div({
|
|
84
|
-
class: `VirtualScroll__item_${i}`,
|
|
85
|
-
style: { height: `${settings.itemHeight}px` },
|
|
86
|
-
}, row)), div({
|
|
87
|
-
class: "VirtualScroll__bottomPadding",
|
|
88
|
-
style: { height: `${state.bottomPaddingHeight}px` },
|
|
89
|
-
}));
|
|
90
|
-
};
|
|
91
|
-
scrollTo();
|
|
92
|
-
return viewportElement;
|
|
93
|
-
});
|
|
94
|
-
export default VirtualScroll;
|
|
1
|
+
import { debounce } from "../debounce.js";
|
|
2
|
+
import { FC, State } from "../dom/fc.js";
|
|
3
|
+
import { div } from "../dom/html.js";
|
|
4
|
+
export function arrayAdapter(data) {
|
|
5
|
+
return (offset, limit) => data.slice(offset, offset + limit);
|
|
6
|
+
}
|
|
7
|
+
export function fillVirtualScrollSettings(settings) {
|
|
8
|
+
const { minIndex = 0, maxIndex = Number.MAX_SAFE_INTEGER, startIndex = 0, itemHeight = 20, count = maxIndex - minIndex + 1, tolerance = count, } = settings;
|
|
9
|
+
return { minIndex, maxIndex, startIndex, itemHeight, count, tolerance };
|
|
10
|
+
}
|
|
11
|
+
export function initialState(settings) {
|
|
12
|
+
// From Denis Hilt, https://blog.logrocket.com/virtual-scrolling-core-principles-and-basic-implementation-in-react/
|
|
13
|
+
const { minIndex, maxIndex, startIndex, itemHeight, count, tolerance } = settings;
|
|
14
|
+
const bufferedItems = count + 2 * tolerance;
|
|
15
|
+
const itemsAbove = Math.max(0, startIndex - tolerance - minIndex);
|
|
16
|
+
const viewportHeight = count * itemHeight;
|
|
17
|
+
const totalHeight = (maxIndex - minIndex + 1) * itemHeight;
|
|
18
|
+
const toleranceHeight = tolerance * itemHeight;
|
|
19
|
+
const bufferHeight = viewportHeight + 2 * toleranceHeight;
|
|
20
|
+
const topPaddingHeight = itemsAbove * itemHeight;
|
|
21
|
+
const bottomPaddingHeight = totalHeight - (topPaddingHeight + bufferHeight);
|
|
22
|
+
return {
|
|
23
|
+
scrollTop: 0,
|
|
24
|
+
settings,
|
|
25
|
+
viewportHeight,
|
|
26
|
+
totalHeight,
|
|
27
|
+
toleranceHeight,
|
|
28
|
+
bufferedItems,
|
|
29
|
+
topPaddingHeight,
|
|
30
|
+
bottomPaddingHeight,
|
|
31
|
+
data: [],
|
|
32
|
+
rows: [],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function getData(minIndex, maxIndex, offset, limit, get) {
|
|
36
|
+
const start = Math.max(0, minIndex, offset);
|
|
37
|
+
const end = Math.min(maxIndex, offset + limit - 1);
|
|
38
|
+
const data = get(start, end - start);
|
|
39
|
+
return [...data];
|
|
40
|
+
}
|
|
41
|
+
export function doScroll(scrollTop, state, get) {
|
|
42
|
+
const { totalHeight, toleranceHeight, bufferedItems, settings: { itemHeight, minIndex, maxIndex }, } = state;
|
|
43
|
+
const index = minIndex + Math.floor((scrollTop - toleranceHeight) / itemHeight);
|
|
44
|
+
const data = getData(minIndex, maxIndex, index, bufferedItems, get);
|
|
45
|
+
const topPaddingHeight = Math.max((index - minIndex) * itemHeight, 0);
|
|
46
|
+
const bottomPaddingHeight = Math.max(totalHeight - (topPaddingHeight + data.length * itemHeight), 0);
|
|
47
|
+
return { scrollTop, topPaddingHeight, bottomPaddingHeight, data };
|
|
48
|
+
}
|
|
49
|
+
// export interface VirtualScroll<T, U extends HTMLElement> {
|
|
50
|
+
// state: VirtualScrollState<T>;
|
|
51
|
+
// rows: UHTMLElement<U>[];
|
|
52
|
+
// }
|
|
53
|
+
export const VirtualScroll = FC("virtual-scroll", (element, props) => {
|
|
54
|
+
const settings = fillVirtualScrollSettings(props.settings);
|
|
55
|
+
const state = (element[State] = {
|
|
56
|
+
...initialState(settings),
|
|
57
|
+
...element[State],
|
|
58
|
+
});
|
|
59
|
+
const scrollTo = ({ target } = { target: state }) => {
|
|
60
|
+
const scrollTop = target?.scrollTop ?? state.topPaddingHeight;
|
|
61
|
+
const updatedSate = {
|
|
62
|
+
...state,
|
|
63
|
+
...doScroll(scrollTop, state, props.get),
|
|
64
|
+
};
|
|
65
|
+
setState(updatedSate);
|
|
66
|
+
};
|
|
67
|
+
const viewportElement = div({
|
|
68
|
+
style: { height: `${state.viewportHeight}px`, overflowY: "scroll" },
|
|
69
|
+
events: { scroll: debounce(scrollTo, 0) },
|
|
70
|
+
});
|
|
71
|
+
setTimeout(() => {
|
|
72
|
+
viewportElement.scroll({ top: state.scrollTop });
|
|
73
|
+
});
|
|
74
|
+
const setState = (newState) => {
|
|
75
|
+
state.scrollTop = newState.scrollTop;
|
|
76
|
+
state.topPaddingHeight = newState.topPaddingHeight;
|
|
77
|
+
state.bottomPaddingHeight = newState.bottomPaddingHeight;
|
|
78
|
+
state.data = newState.data;
|
|
79
|
+
state.rows = state.data.map(props.row);
|
|
80
|
+
viewportElement.update(div({
|
|
81
|
+
class: "VirtualScroll__topPadding",
|
|
82
|
+
style: { height: `${state.topPaddingHeight}px` },
|
|
83
|
+
}), ...(state.rows ?? []).map((row, i) => div({
|
|
84
|
+
class: `VirtualScroll__item_${i}`,
|
|
85
|
+
style: { height: `${settings.itemHeight}px` },
|
|
86
|
+
}, row)), div({
|
|
87
|
+
class: "VirtualScroll__bottomPadding",
|
|
88
|
+
style: { height: `${state.bottomPaddingHeight}px` },
|
|
89
|
+
}));
|
|
90
|
+
};
|
|
91
|
+
scrollTo();
|
|
92
|
+
return viewportElement;
|
|
93
|
+
});
|
|
94
|
+
export default VirtualScroll;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import { State } from "../dom/fc.js";
|
|
2
|
-
import { div } from "../dom/html.js";
|
|
3
|
-
import { describe, it, expect } from "../scope/index.js";
|
|
4
|
-
import VirtualScroll, { arrayAdapter, } from "./virtual_scroll.js";
|
|
5
|
-
describe("VirtualScroll", () => {
|
|
6
|
-
it("tracks scroll position", () => {
|
|
7
|
-
const data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
8
|
-
const props = {
|
|
9
|
-
settings: { count: 3, startIndex: 2 },
|
|
10
|
-
get: arrayAdapter(data),
|
|
11
|
-
row: (i) => div(`${i}`),
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
expect(scroll[State]?.
|
|
16
|
-
expect(scroll
|
|
17
|
-
|
|
18
|
-
expect(scroll
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
});
|
|
1
|
+
import { State } from "../dom/fc.js";
|
|
2
|
+
import { div } from "../dom/html.js";
|
|
3
|
+
import { describe, it, expect } from "../scope/index.js";
|
|
4
|
+
import VirtualScroll, { arrayAdapter, } from "./virtual_scroll.js";
|
|
5
|
+
describe("VirtualScroll", () => {
|
|
6
|
+
it("tracks scroll position", () => {
|
|
7
|
+
const data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
8
|
+
const props = {
|
|
9
|
+
settings: { count: 3, startIndex: 2 },
|
|
10
|
+
get: arrayAdapter(data),
|
|
11
|
+
row: (i) => div(`${i}`),
|
|
12
|
+
};
|
|
13
|
+
const scroll = VirtualScroll(props);
|
|
14
|
+
expect(scroll[State]?.bufferedItems).toBe(9);
|
|
15
|
+
expect(scroll[State]?.data).toEqual([0, 1, 2, 3, 4]);
|
|
16
|
+
//expect(scroll.state.topPaddingHeight).toBe(0);
|
|
17
|
+
expect(scroll[State]?.viewportHeight).toBe(60);
|
|
18
|
+
//expect(scroll.state.totalHeight).toBe(200);
|
|
19
|
+
});
|
|
20
|
+
});
|