@litejs/ui 21.11.0 → 22.12.0

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.
@@ -115,20 +115,22 @@
115
115
  }
116
116
  }
117
117
 
118
- bindings.is = function bindingIs(node, model, path, list, state) {
118
+ bindings.is = function bindingIs(node, model, path, list, state, prefix) {
119
119
  var match
120
120
  , scope = this
121
121
  if (typeof model === "string") {
122
+ prefix = state
122
123
  state = list
123
124
  list = path
124
125
  path = model
125
126
  model = scope.model
126
127
  }
127
128
  if (model && path) {
129
+ if (!prefix) prefix = "is-"
128
130
  match = i18n.pick(state !== match ? state : model.get(path), list)
129
131
  path += "-" + list
130
- El.cls(node, node["_is-" + path], 0)
131
- El.cls(node, node["_is-" + path] = match && "is-" + match)
132
+ El.cls(node, node[prefix + path], 0)
133
+ El.cls(node, node[prefix + path] = match && prefix + match)
132
134
  }
133
135
  }
134
136
 
@@ -0,0 +1,16 @@
1
+
2
+ // .sticky { position: sticky; top: -1px; }
3
+ // .sticky.is-stuck { color: red; }
4
+
5
+ El.bindings.sticky = function sticky(el) {
6
+ ;(sticky._ob || (sticky._ob = new IntersectionObserver(function(entries) {
7
+ entries.forEach(function(entry) {
8
+ El.cls(entry.target, "is-stuck", entry.intersectionRatio < 1)
9
+ })
10
+ }, { threshold: 1 }))).observe(el)
11
+ El.cls(el, "sticky")
12
+ }
13
+
14
+ El.bindings.sticky.once = 1
15
+
16
+
@@ -0,0 +1,25 @@
1
+
2
+ /* https://www.tpgi.com/short-note-on-making-your-mark-more-accessible/ */
3
+
4
+ @media screen and (-ms-high-contrast: active) {
5
+ mark {
6
+ color: HighlightText;
7
+ background-color: Highlight;
8
+ }
9
+ }
10
+
11
+ mark::before, mark::after {
12
+ content:" [highlight start] ";
13
+ clip-path: inset(100%);
14
+ clip: rect(1px, 1px, 1px, 1px);
15
+ height: 1px;
16
+ width: 1px;
17
+ overflow: hidden;
18
+ position: absolute;
19
+ white-space: nowrap;
20
+ }
21
+
22
+ mark::after {
23
+ content:" [highlight end] ";
24
+ }
25
+
package/css/grid.css CHANGED
@@ -7,8 +7,14 @@ Expects box-sizing: border-box;
7
7
  .row {
8
8
  display: block;
9
9
  clear: both;
10
+ contain: content;
11
+ *zoom: 1;
10
12
  }
11
- .row {
13
+
14
+ .grid:after,
15
+ .row:after {
16
+ content: " ";
17
+ display: block;
12
18
  clear: both;
13
19
  }
14
20
 
@@ -21,13 +27,6 @@ Expects box-sizing: border-box;
21
27
  clear: none;
22
28
  }
23
29
 
24
- .grid:after,
25
- .row:after {
26
- content: " ";
27
- display: block;
28
- clear: both;
29
- }
30
-
31
30
  .col,
32
31
  .w12, .md .md-w12, .lg .md-w12, .lg .lg-w12 { width: 100%; }
33
32
  .w11, .md .md-w11, .lg .md-w11, .lg .lg-w11 { width: 91.6667%; }
@@ -0,0 +1,19 @@
1
+
2
+ @media (prefers-color-scheme: dark) {
3
+ .day.dark-scheme { background: #333; color: white; }
4
+ .night.dark-scheme { background: black; color: #ddd; }
5
+ }
6
+
7
+ @media (prefers-contrast: more) {
8
+ .contrast { outline: 2px solid black; }
9
+ }
10
+
11
+ @media screen and (prefers-reduced-motion: reduce), (update: slow) {
12
+ * {
13
+ animation-duration: 0.001ms !important;
14
+ /* Hat tip Nick/cssremedy (https://css-tricks.com/revisiting-prefers-reduced-motion-the-reduced-motion-media-query/#comment-1700170) */
15
+ animation-iteration-count: 1 !important;
16
+ transition-duration: 0.001ms !important;
17
+ }
18
+ }
19
+
package/css/print.css ADDED
@@ -0,0 +1,33 @@
1
+
2
+ /*
3
+ * Ensure you use dark text on a white background
4
+ * Use Borders Instead of Background Colors
5
+ */
6
+
7
+
8
+ @media print {
9
+ table, img, svg {
10
+ break-inside: avoid;
11
+ }
12
+ img.dark {
13
+ filter: invert(100%) hue-rotate(180deg) brightness(120%) contrast(150%);
14
+ }
15
+
16
+ /* Not all printers will print in color, add some other style that isn’t too disruptive. */
17
+ mark {
18
+ border: 1pt dotted #000;
19
+ }
20
+ q:after {
21
+ content: " (Source: " attr(cite) ")";
22
+ }
23
+ a {
24
+ color: #000;
25
+ }
26
+ p a {
27
+ word-wrap: break-word;
28
+ }
29
+ p a[href^="https://"]:after, a[href^="https://"]:after {
30
+ content: " (" attr(href) ")";
31
+ }
32
+ }
33
+
@@ -0,0 +1,10 @@
1
+ .striped45 {
2
+ background-color: currentColor;
3
+ background-image: repeating-linear-gradient(
4
+ 45deg,
5
+ rgba(255, 255, 255, .5),
6
+ rgba(255, 255, 255, .5) 4px,
7
+ transparent 4px,
8
+ transparent 8px
9
+ );
10
+ }
File without changes
File without changes
@@ -220,7 +220,7 @@
220
220
  }
221
221
  function set(val, e, pos) {
222
222
  load()
223
- val = (val < min ? min : val > max ? max : val).step(step)
223
+ val = (val < min ? min : val > max ? max : val || 0).step(step)
224
224
  if (value !== void 0 && (!drag || pos !== void 0)) {
225
225
  El.css(fill, vert ? "height" : "width", ((pos || (val-min)*px)+knobLen) + "px", 0)
226
226
  }
@@ -13,7 +13,7 @@
13
13
  right: 0;
14
14
  margin: 0 auto;
15
15
  top: 4%;
16
- width: 400px;
16
+ width: 600px;
17
17
  background-color: #fff;
18
18
  box-shadow: 0 2px 10px 2px rgba(255,255,255,.5);
19
19
  }
@@ -73,7 +73,7 @@
73
73
  Object.assign(scope, opts)
74
74
  scope.title = title || "Confirm?"
75
75
  if (!scope.actions) scope.actions = [
76
- { action: "close", title: "Close" }
76
+ { action: "close", title: "Close", key: "esc" }
77
77
  ]
78
78
  for (var a, i = 0; a = scope.actions[i++]; ) {
79
79
  if (typeof a == "string") a = scope.actions[i-1] = {title:a,action:a}
@@ -106,23 +106,31 @@
106
106
  var num = _num == void 0 ? e.target[El.T] : _num
107
107
  code += num
108
108
  if (num == "CLEAR" || num == "del" || num == "backspace") code = ""
109
- El.txt(El.find(el, ".js-body"), code.replace(/./g, "•") || opts.body)
110
- // if (code.length == 4 && id && !sent) next(sent = code, id, resolve, reject)
109
+ El.md(El.find(el, ".js-body"), code.replace(/./g, "•") || opts.body)
110
+ if (typeof scope.code == "number" && code.length == scope.code && id && !sent) next(sent = code, id, resolve, reject)
111
111
  }
112
112
  function resolve(e, key) {
113
113
  if (el) {
114
+ var action = key || El.attr(this, "data-action")
115
+ , result = {
116
+ code: code,
117
+ input: El.val(El.find(el, ".js-input")),
118
+ inputMd: El.val(El.find(el, ".js-inputMd")),
119
+ select: El.val(El.find(el, ".js-select"))
120
+ }
114
121
  El.kill(el, "transparent")
115
122
  El.cls(blurEl, "Confirm--blur", el = 0)
116
- var action = key || El.attr(this, "data-action")
117
123
  if (action && next) {
118
- if (typeof next === "function") next(action, code)
119
- else if (typeof next[action] === "function") next[action](code)
120
- else if (next[action]) View.emit(next[action], code)
124
+ if (typeof next === "function") next(action, result)
125
+ else if (typeof next[action] === "function") next[action](result)
126
+ else if (next[action]) View.emit(next[action], result)
121
127
  }
122
128
  if (vibrate) navigator.vibrate(0)
123
129
  if (sound) sound.pause()
124
130
  }
125
131
  }
132
+ scope.resolve = resolve
133
+ View.emit("confirm:open", scope)
126
134
  })
127
135
 
128
136
  %el Confirm
@@ -130,11 +138,31 @@
130
138
  .Confirm-bg.max.abs
131
139
  .Confirm-content.Confirm--blur.grid.p2.anim
132
140
  .col.ts3 ;txt:: _(title, map)
133
- .col.js-body ;txt:: _(body, map)
141
+ .col.js-body ;md:: _(body, map)
134
142
  .row.js-numpad
135
143
  ;if: code
136
144
  ;each: num in [1,2,3,4,5,6,7,8,9,"CLEAR",0]
137
145
  .col.w4>.btn {num}
146
+ .row
147
+ ;if: input
148
+ .col>input.field.js-input
149
+ .row
150
+ ;if: data.inputMd!=null
151
+ .col
152
+ textarea.field.js-inputMd
153
+ @keyup [this.parentNode.nextSibling.nextSibling], "renderMd"
154
+ ;val: inputMd
155
+ .col.ts3 Preview
156
+ .p4
157
+ ;md: inputMd
158
+ .row
159
+ ;if: select
160
+ .col
161
+ select.field.js-select
162
+ ;list: select, [""]
163
+ option
164
+ ;val:: item.id
165
+ ;txt:: _(item.name)
138
166
  .col
139
167
  .group ;each: action in actions
140
168
  .btn.js-btn
@@ -3,12 +3,14 @@
3
3
  border: 0;
4
4
  padding: 0;
5
5
  }
6
- .Form1-del {
6
+ .Form1-del.right {
7
7
  display: block;
8
8
  margin: -10px -10px 0 0;
9
+ opacity: .2;
10
+ }
11
+ .Form1-del {
9
12
  font-size: 20px;
10
13
  font-weight: 700;
11
- opacity: .2;
12
14
  border: 1px solid transparent;
13
15
  line-height: 16px;
14
16
  width: 20px;
@@ -28,7 +30,6 @@
28
30
  display: block;
29
31
  border-radius: 4px;
30
32
  border: 1px solid #aaa;
31
- overflow: auto;
32
33
  }
33
34
  .field {
34
35
  width: 100%;
@@ -93,9 +94,11 @@
93
94
  opacity: .6;
94
95
  pointer-events: none;
95
96
  }
97
+ .group {
98
+ overflow: auto;
99
+ }
96
100
  .group > .btn {
97
101
  border-radius: 0;
98
- margin-left: -1px;
99
102
  float: left;
100
103
  }
101
104
  .group > .btn:first-child {
@@ -225,7 +228,7 @@
225
228
 
226
229
  %el form1-array
227
230
  .col
228
- .input.p13
231
+ .input.p13.cf
229
232
  .left
230
233
  = _(title||name)
231
234
  .input__hint
@@ -237,10 +240,11 @@
237
240
  @click: data.add
238
241
 
239
242
  %el form1-array-item
240
- .input.p3.m2b.js-del
243
+ .input.p3.m2b.cf.js-del
241
244
  a.right.Form1-del.hand ×
242
245
  ;if: !data.noAdd
243
- ;on: "click", data.del
246
+ ;data:: "tooltip", _("Delete")
247
+ @click: data.del
244
248
  b
245
249
  ;if: title
246
250
  ;txt: title
@@ -202,8 +202,8 @@
202
202
  El.near = near
203
203
  function near(source, target, x, y, margin) {
204
204
  var rect = target.getBoundingClientRect()
205
- , top = rect.top
206
- , left = rect.left
205
+ , top = rect.top + El.scrollTop()
206
+ , left = rect.left + El.scrollLeft()
207
207
  // svg elements dont have offsetWidth, IE8 does not have rect.width
208
208
  , width = rect.width || target.offsetWidth || 0
209
209
  , height = rect.height || target.offsetHeight || 0
@@ -229,12 +229,15 @@
229
229
  } else if (y == "bottom") {
230
230
  top += height + margin
231
231
  y = " -50%"
232
+ setTimeout(function(){
233
+ //document.scrollingElement.scrollHeight
234
+ var overflow = top + source.offsetHeight - El.scrollTop() - document.documentElement.offsetHeight
235
+ if (overflow > 0) scrollBy({ top: overflow, left: 0, behavior: "smooth" })
236
+ }, 400)
232
237
  } else {
233
238
  top += (height / 2) - (source.offsetHeight/2)
234
239
  y = " 50%"
235
240
  }
236
- left += El.scrollLeft()
237
- top += El.scrollTop()
238
241
  El.css(source, {
239
242
  "transform-origin": x + y,
240
243
  top: (top < 0 ? 0 : top) + "px",
@@ -271,7 +274,8 @@
271
274
  }
272
275
  function openVisible(tag, target) {
273
276
  var el = typeof tag == "string" ? El(tag) : tag
274
- El.scope(el, El.scope(target))
277
+ , scope = El.scope(el, El.scope(target))
278
+ scope.openTarget = target
275
279
  El.render(el)
276
280
  El.append(document.body, el)
277
281
  El.cls(el, "is-visible", 1, 5)
@@ -296,7 +300,7 @@
296
300
  El.cls(menuTarget, "is-active", menuEl = menuTarget = null)
297
301
  }
298
302
  }
299
- View.on("resize", closeMenu)
303
+ View.on("ping", closeMenu)
300
304
  View.on("closeMenu", closeMenu)
301
305
  View.on("showMenu", function(e, target, menu, x, y, margin) {
302
306
  Event.stop(e)
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * @version 21.11.0
2
+ * @version 22.12.0
3
3
  * @author Lauri Rooden <lauri@rooden.ee>
4
4
  * @license MIT License
5
5
  */
@@ -329,10 +329,9 @@
329
329
  var undef
330
330
  , P = "prototype"
331
331
  , A = Array[P]
332
- , F = Function[P]
333
332
  , S = String[P]
334
333
  , N = Number[P]
335
- , slice = F.call.bind(A.slice)
334
+ , slice = Function[P].call.bind(A.slice)
336
335
  , fns = {}
337
336
  , hasOwn = fns.hasOwnProperty
338
337
  , fnRe = /('|")(?:\\?.)*?\1|\/(?:\\?.)+?\/[gim]*|\b(?:false|in|new|null|this|true|typeof|void|function|var|if|else|return)\b|\.\w+|\w+:/g
@@ -347,26 +346,6 @@
347
346
  Fn.wait = wait
348
347
 
349
348
 
350
- // Function extensions
351
- // -------------------
352
-
353
- F.extend = function() {
354
- var arg
355
- , fn = this
356
- , i = 0
357
-
358
- function wrapper() {
359
- return fn.apply(this, arguments)
360
- }
361
-
362
- for (wrapper[P] = Object.create(fn[P]); arg = arguments[i++]; ) {
363
- Object.assign(wrapper[P], arg)
364
- }
365
- wrapper[P].constructor = wrapper
366
- return wrapper
367
- }
368
-
369
-
370
349
  // Non-standard
371
350
  Object.each = function(obj, fn, scope, key) {
372
351
  if (obj) for (key in obj) {
@@ -403,6 +382,13 @@
403
382
  return this.indexOf(item) < 0 && this.push(item)
404
383
  }
405
384
 
385
+ A.pluck = function(name) {
386
+ for (var arr = this, i = arr.length, out = []; i--; ) {
387
+ out[i] = arr[i][name]
388
+ }
389
+ return out
390
+ }
391
+
406
392
  // THANKS: Oliver Steele - Functional Javascript [http://www.osteele.com/sources/javascript/functional/]
407
393
  function Fn(expr /*, scope, mask1, ..maskN */) {
408
394
  var args = []
@@ -453,21 +439,6 @@
453
439
  return "" + this
454
440
  }
455
441
 
456
- S.safe = function() {
457
- return this
458
- .replace(/&/g, "&amp;")
459
- .replace(/</g, "&lt;")
460
- .replace(/>/g, "&gt;")
461
- .replace(/\"/g, "&quot;")
462
- }
463
-
464
- S.capitalize = function() {
465
- return this.charAt(0).toUpperCase() + this.slice(1)
466
- }
467
-
468
- S.lower = S.toLowerCase
469
- S.upper = S.toUpperCase
470
-
471
442
  N.step = function(a, add) {
472
443
  var x = ("" + a).split(".")
473
444
  , steps = this / a
@@ -481,57 +452,6 @@
481
452
  })
482
453
  }
483
454
 
484
- N.scale = words([1000, 1000, 1000], ["","k","M","G"], {"default": "{n}{u}"})
485
-
486
- S.scale = function() {
487
- return this.replace(numbersRe, function(num) {
488
- return (+num).scale()
489
- })
490
- }
491
-
492
- S.pick = N.pick = function() {
493
- var val = this + "="
494
- for (var s, a = arguments, i = 0, len = a.length; i < len;) {
495
- s = a[i++]
496
- if (s.indexOf(val) == 0) {
497
- s = s.slice(val.length)
498
- i = len
499
- }
500
- }
501
- return s.replace("#", this)
502
- }
503
-
504
- S.plural = N.plural = function() {
505
- // Plural-Forms: nplurals=2; plural=n != 1;
506
- // http://www.gnu.org/software/gettext/manual/html_mono/gettext.html#Plural-forms
507
- return arguments[ +Fn("n->" + (String.plural || "n!=1"))( parseFloat(this) ) ].replace("#", this)
508
- }
509
-
510
- A.pluck = function(name) {
511
- for (var arr = this, i = arr.length, out = []; i--; ) {
512
- out[i] = arr[i][name]
513
- }
514
- return out
515
- }
516
-
517
- function words(steps, units, strings, overflow) {
518
- return function(input) {
519
- var n = +(arguments.length ? input : this)
520
- , i = 0
521
- , s = strings || {"default": "{n} {u}{s}"}
522
-
523
- for (; n>=steps[i]; ) {
524
- n /= steps[i++]
525
- }
526
- if (i == steps.length && overflow) {
527
- return overflow(this)
528
- }
529
- i = units[i]
530
- return (s[n < 2 ? i : i + "s"] || s["default"]).format({n: n, u: i, s: n < 2 ? "" : "s"})
531
- }
532
- }
533
- Fn.words = words
534
-
535
455
  function wait(fn) {
536
456
  var pending = 1
537
457
  function resume() {
@@ -555,7 +475,8 @@
555
475
  for (k in obj) if (typeof obj[k] == "function" && ignore.indexOf(k) < 0) !function(k) {
556
476
  hooked.push(k, hasOwn.call(obj, k) && obj[k])
557
477
  obj[k] = function() {
558
- hooks.push(k, arguments)
478
+ if (hooks === null) obj[k].apply(this, arguments)
479
+ else hooks.push(k, arguments)
559
480
  return obj
560
481
  }
561
482
  }(k)
@@ -648,9 +569,9 @@
648
569
  , emitter = this === exports ? empty : this
649
570
  , _e = emitter._e
650
571
  , arr = _e ? (_e[type] || empty).concat(_e["*"] || empty) : empty
651
- if (i = _e = arr.length) {
652
- for (args = arr.slice.call(arguments, 1); i--; ) {
653
- arr[i--].apply(arr[--i] || emitter, args)
572
+ if ((_e = arr.length)) {
573
+ for (i = _e - 1, args = arr.slice.call(arguments, 1); i > 1; i -= 3) {
574
+ arr[i] && arr[i].apply(arr[i - 2] || emitter, args)
654
575
  }
655
576
  }
656
577
  return _e / 3
@@ -831,7 +752,7 @@
831
752
  var key, name
832
753
  , opts = Object.assign({}, defaults, _opts)
833
754
  for (key in opts) if (hasOwn.call(opts, key)) {
834
- if (typeof View[key] == "function") {
755
+ if (typeof View[key] === "function") {
835
756
  for (name in opts[key]) if (hasOwn.call(opts[key], name)) {
836
757
  View[key](name, opts[key][name])
837
758
  }
@@ -858,7 +779,7 @@
858
779
  view.el = el
859
780
  view.parent = parent && View(parent)
860
781
 
861
- if (route.charAt(0) != "#") {
782
+ if (route.charAt(0) !== "#") {
862
783
  var params = "m[" + (view.seq = capture++) + "]?("
863
784
  , _re = route.replace(parseRe, function(_, key) {
864
785
  return key ?
@@ -881,13 +802,14 @@
881
802
  , close = view.isOpen && view
882
803
 
883
804
  View.route = view.route
805
+ emit(view, "init")
884
806
 
885
807
  for (; tmp; tmp = parent) {
886
808
  emit(syncResume = params._v = tmp, "ping", params, View)
887
809
  syncResume = null
888
- if (lastParams != params) return
810
+ if (lastParams !== params) return
889
811
  if (parent = tmp.parent) {
890
- if (parent.child && parent.child != tmp) {
812
+ if (parent.child && parent.child !== tmp) {
891
813
  close = parent.child
892
814
  }
893
815
  parent.child = tmp
@@ -901,7 +823,7 @@
901
823
  view.wait(tmp.file = null)
902
824
  )
903
825
  } else {
904
- if (tmp.route == "404") {
826
+ if (tmp.route === "404") {
905
827
  El.txt(tmp = El("h3"), "# Error 404")
906
828
  View("404", tmp, "#body")
907
829
  }
@@ -913,7 +835,7 @@
913
835
 
914
836
  if (view !== close) emit(view, "change", close)
915
837
 
916
- for (tmp in params) if (tmp.charAt(0) != "_") {
838
+ for (tmp in params) if (tmp.charAt(0) !== "_") {
917
839
  if (syncResume = hasOwn.call(paramCb, tmp) && paramCb[tmp] || paramCb["*"]) {
918
840
  syncResume.call(view, params[tmp], tmp, params)
919
841
  syncResume = null
@@ -926,7 +848,7 @@
926
848
  var params = lastParams
927
849
  params._p = 1 + (params._p | 0)
928
850
  return function() {
929
- if (--params._p || lastParams != params || syncResume) return
851
+ if (--params._p || lastParams !== params || syncResume) return
930
852
  if (params._d) {
931
853
  bubbleDown(params)
932
854
  } else if (params._v) {
@@ -959,7 +881,7 @@
959
881
  if (params._d = params._v = view.child) {
960
882
  bubbleDown(params, close)
961
883
  }
962
- if (lastView == view) {
884
+ if (lastView === view) {
963
885
  emit(view, "show", params)
964
886
  blur()
965
887
  }
@@ -1007,7 +929,7 @@
1007
929
  }
1008
930
  var params = _params || {}
1009
931
  , view = get(url, params)
1010
- if (!view.isOpen || lastUrl != url) {
932
+ if (!view.isOpen || lastUrl !== url) {
1011
933
  params._u = lastUrl = url
1012
934
  view.show(El.data.params = params)
1013
935
  }
@@ -1058,20 +980,20 @@
1058
980
  /* litejs.com/MIT-LICENSE.txt */
1059
981
 
1060
982
 
1061
- !function(window, document, Object, Event, protoStr) {
983
+ !function(window, document, Object, Event, P) {
1062
984
  var UNDEF, styleNode
1063
985
  , BIND_ATTR = "data-bind"
1064
986
  , isArray = Array.isArray
1065
987
  , seq = 0
1066
988
  , elCache = El.cache = {}
1067
- , wrapProto = ElWrap[protoStr] = []
989
+ , wrapProto = ElWrap[P] = []
1068
990
  , slice = wrapProto.slice
1069
991
  , hasOwn = elCache.hasOwnProperty
1070
992
  , body = document.body
1071
993
  , root = document.documentElement
1072
994
  , txtAttr = El.T = "textContent" in body ? "textContent" : "innerText"
1073
995
  , templateRe = /([ \t]*)(%?)((?:("|')(?:\\?.)*?\4|[-\w:.#[\]]=?)*)[ \t]*([>^;@|\\\/]|!?=|)(([\])}]?).*?([[({]?))(?=\x1f+|\n+|$)/g
1074
- , renderRe = /[;\s]*(\w+)(?:\s*(:?):((?:(["'\/])(?:\\?.)*?\3|[^;])*))?/g
996
+ , renderRe = /[;\s]*(\w+)(?:(::?| )((?:(["'\/])(?:\\?.)*?\3|[^;])*))?/g
1075
997
  , selectorRe = /([.#:[])([-\w]+)(?:\((.+?)\)|([~^$*|]?)=(("|')(?:\\?.)*?\6|[-\w]+))?]?/g
1076
998
  , splitRe = /[,\s]+/
1077
999
  , camelRe = /\-([a-z])/g
@@ -1089,6 +1011,11 @@
1089
1011
  html: function(el, html) {
1090
1012
  el.innerHTML = html
1091
1013
  },
1014
+ md: El.md = function(el, txt) {
1015
+ txt = txt.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;")
1016
+ txt = txt.replace(/\n/g, "<br>")
1017
+ el.innerHTML = txt
1018
+ },
1092
1019
  ref: function(el, name) {
1093
1020
  this[name] = el
1094
1021
  },
@@ -1152,14 +1079,10 @@
1152
1079
  * <input id="12" class="nice class" type="checkbox" checked="checked" disabled="disabled" data-lang="en">
1153
1080
  */
1154
1081
 
1155
- function isObject(obj) {
1156
- return obj && obj.constructor === Object
1157
- }
1158
-
1159
1082
  window.El = El
1160
1083
 
1161
1084
  function El(name) {
1162
- if (typeof name != "string") {
1085
+ if (!isString(name)) {
1163
1086
  return new ElWrap(name)
1164
1087
  }
1165
1088
  var el, pres
@@ -1168,14 +1091,14 @@
1168
1091
  pres = 1
1169
1092
  val = quotation ? val.slice(1, -1) : val || key
1170
1093
  pre[op =
1171
- op == "." ?
1094
+ op === "." ?
1172
1095
  (fn = "~", "class") :
1173
- op == "#" ?
1096
+ op === "#" ?
1174
1097
  "id" :
1175
1098
  key
1176
1099
  ] = fn && pre[op] ?
1177
- fn == "^" ? val + pre[op] :
1178
- pre[op] + (fn == "~" ? " " : "") + val :
1100
+ fn === "^" ? val + pre[op] :
1101
+ pre[op] + (fn === "~" ? " " : "") + val :
1179
1102
  val
1180
1103
  return ""
1181
1104
  }) || "div"
@@ -1256,11 +1179,11 @@
1256
1179
 
1257
1180
  /*** ie8 ***/
1258
1181
  // istanbul ignore next: IE fix
1259
- if (ie67 && (key == "id" || key == "name" || key == "checked")) {
1182
+ if (ie67 && (key === "id" || key === "name" || key === "checked")) {
1260
1183
  el.mergeAttributes(document.createElement('<INPUT ' + key + '="' + val + '">'), false)
1261
1184
  } else
1262
1185
  /**/
1263
- if (key == "class") {
1186
+ if (key === "class") {
1264
1187
  cls(el, val)
1265
1188
  } else if (val || val === 0) {
1266
1189
  if (current != val) {
@@ -1272,6 +1195,7 @@
1272
1195
  }
1273
1196
 
1274
1197
  function valFn(el, val) {
1198
+ if (!el) return ""
1275
1199
  var input, step, key, value
1276
1200
  , i = 0
1277
1201
  , type = el.type
@@ -1279,8 +1203,6 @@
1279
1203
  , checkbox = type === "checkbox" || type === "radio"
1280
1204
 
1281
1205
  if (el.tagName === "FORM") {
1282
- opts = {}
1283
-
1284
1206
  // Disabled controls do not receive focus,
1285
1207
  // are skipped in tabbing navigation, cannot be successfully posted.
1286
1208
  //
@@ -1289,15 +1211,11 @@
1289
1211
  //
1290
1212
  // Read-only checkboxes can be changed by the user
1291
1213
 
1292
- for (; input = el.elements[i++]; ) if (!input.disabled && (key = input.name || input.id)) {
1214
+ for (opts = {}; input = el.elements[i++]; ) if (!input.disabled && (key = input.name || input.id)) {
1293
1215
  value = valFn(input)
1294
1216
  if (value !== UNDEF) {
1295
1217
  step = opts
1296
- key.replace(/\[(.*?)\]/g, function(_, _key, offset) {
1297
- if (step == opts) key = key.slice(0, offset)
1298
- step = step[key] || (step[key] = step[key] === null || _key && +_key != _key ? {} : [])
1299
- key = _key
1300
- })
1218
+ key.replace(/\[(.*?)\]/g, replacer)
1301
1219
  step[key || step.length] = value
1302
1220
  }
1303
1221
  }
@@ -1336,17 +1254,22 @@
1336
1254
  return checkbox && !el.checked ?
1337
1255
  (type === "radio" ? UNDEF : null) :
1338
1256
  el.valObject !== UNDEF ? el.valObject : el.value
1257
+
1258
+ function replacer(_, _key, offset) {
1259
+ if (step == opts) key = key.slice(0, offset)
1260
+ step = step[key] || (step[key] = step[key] === null || _key && +_key != _key ? {} : [])
1261
+ key = _key
1262
+ }
1339
1263
  }
1340
1264
 
1341
1265
  function append(el, child, before) {
1342
1266
  if (!el.nodeType) {
1343
1267
  return el.append ? el.append(child, before) : el
1344
1268
  }
1345
- var fragment
1269
+ var fragment, tmp
1346
1270
  , i = 0
1347
- , tmp = typeof child
1348
1271
  if (child) {
1349
- if (tmp == "string" || tmp == "number") child = document.createTextNode(child)
1272
+ if (isString(child) || isNumber(child)) child = document.createTextNode(child)
1350
1273
  else if ( !("nodeType" in child) && "length" in child ) {
1351
1274
  // document.createDocumentFragment is unsupported in IE5.5
1352
1275
  // fragment = "createDocumentFragment" in document ? document.createDocumentFragment() : El("div")
@@ -1371,7 +1294,7 @@
1371
1294
  /**/
1372
1295
  tmp.insertBefore(child,
1373
1296
  (before === true ? tmp.firstChild :
1374
- typeof before == "number" ? tmp.childNodes[
1297
+ isNumber(before) ? tmp.childNodes[
1375
1298
  before < 0 ? tmp.childNodes.length - before - 2 : before
1376
1299
  ] : before) || null
1377
1300
  )
@@ -1436,7 +1359,7 @@
1436
1359
  function hasClass(el, name) {
1437
1360
  var current = el.className || ""
1438
1361
 
1439
- if (typeof current !== "string") {
1362
+ if (!isString(current)) {
1440
1363
  current = el.getAttribute("class") || ""
1441
1364
  }
1442
1365
 
@@ -1445,7 +1368,7 @@
1445
1368
 
1446
1369
  function cls(el, name, set) {
1447
1370
  var current = el.className || ""
1448
- , useAttr = typeof current !== "string"
1371
+ , useAttr = !isString(current)
1449
1372
 
1450
1373
  if (useAttr) {
1451
1374
  current = el.getAttribute("class") || ""
@@ -1524,14 +1447,14 @@
1524
1447
 
1525
1448
  function bindingOn(el, events, selector, data, handler, delay) {
1526
1449
  var argi = arguments.length
1527
- if (argi == 3 || argi == 4 && typeof data == "number") {
1450
+ if (argi == 3 || argi == 4 && isNumber(data)) {
1528
1451
  delay = data
1529
1452
  handler = selector
1530
1453
  selector = data = null
1531
- } else if (argi == 4 || argi == 5 && typeof handler == "number") {
1454
+ } else if (argi == 4 || argi == 5 && isNumber(handler)) {
1532
1455
  delay = handler
1533
1456
  handler = data
1534
- if (typeof selector == "string") {
1457
+ if (isString(selector)) {
1535
1458
  data = null
1536
1459
  } else {
1537
1460
  data = selector
@@ -1543,7 +1466,7 @@
1543
1466
  return
1544
1467
  }
1545
1468
  var fn = (
1546
- typeof handler == "string" ? function(e) {
1469
+ isString(handler) ? function(e) {
1547
1470
  var target = selector ? El.closest(e.target, selector) : el
1548
1471
  if (target) View.emit.apply(View, [handler, e, target].concat(data))
1549
1472
  } :
@@ -1628,6 +1551,7 @@
1628
1551
  }
1629
1552
 
1630
1553
  function render(node, _scope) {
1554
+ if (!node) return
1631
1555
  var bind, fn
1632
1556
  , scope = elScope(node, 0, _scope)
1633
1557
  , i = 0
@@ -1648,7 +1572,7 @@
1648
1572
  scope._m[i] = match
1649
1573
  match = bindings[name]
1650
1574
  return (
1651
- (op == ":" || match && hasOwn.call(match, "once")) ?
1575
+ (op === "::" || match && hasOwn.call(match, "once")) ?
1652
1576
  "s(this,B,data._t=data._t.replace(data._m[" + (i++)+ "],''))||" :
1653
1577
  ""
1654
1578
  ) + (
@@ -1678,7 +1602,7 @@
1678
1602
  render(bind, scope)
1679
1603
  }
1680
1604
  /*** ie8 ***/
1681
- if (ie678 && node.tagName == "SELECT") {
1605
+ if (ie678 && node.tagName === "SELECT") {
1682
1606
  node.parentNode.insertBefore(node, node)
1683
1607
  }
1684
1608
  /**/
@@ -1760,16 +1684,16 @@
1760
1684
  append(parent, parent = q = El(name))
1761
1685
  }
1762
1686
  if (text && op != "/") {
1763
- if (op == ">") {
1687
+ if (op === ">") {
1764
1688
  (indent + " " + text).replace(templateRe, work)
1765
- } else if (op == "|" || op == "\\") {
1689
+ } else if (op === "|" || op === "\\") {
1766
1690
  append(parent, text) // + "\n")
1767
1691
  } else {
1768
- if (op == "@") {
1692
+ if (op === "@") {
1769
1693
  text = text.replace(/(\w+):?/, "on:'$1',")
1770
1694
  } else if (op != ";" && op != "^") {
1771
- text = (parent.tagName == "INPUT" ? "val" : "txt") + (
1772
- op == "=" ? ":" + text.replace(/'/g, "\\'") :
1695
+ text = (parent.tagName === "INPUT" ? "val" : "txt") + (
1696
+ op === "=" ? ":" + text.replace(/'/g, "\\'") :
1773
1697
  ":_('" + text.replace(/'/g, "\\'") + "', data)"
1774
1698
  )
1775
1699
  }
@@ -1785,7 +1709,7 @@
1785
1709
  function appendBind(el, val, sep, q) {
1786
1710
  var current = getAttr(el, BIND_ATTR)
1787
1711
  setAttr(el, BIND_ATTR, (current ? (
1788
- q == "^" ?
1712
+ q === "^" ?
1789
1713
  val + sep + current :
1790
1714
  current + sep + val
1791
1715
  ) : val))
@@ -1799,7 +1723,7 @@
1799
1723
  t.el.plugin = t
1800
1724
  }
1801
1725
 
1802
- plugin[protoStr] = {
1726
+ plugin[P] = {
1803
1727
  _done: function() {
1804
1728
  var t = this
1805
1729
  , childNodes = t.el.childNodes
@@ -1832,15 +1756,15 @@
1832
1756
  t.a = attr1
1833
1757
  }
1834
1758
 
1835
- js[protoStr].done = Fn("Function(this.txt)()")
1759
+ js[P].done = Fn("Function(this.txt)()")
1836
1760
 
1837
1761
  El.plugins = {
1838
- binding: js.extend({
1762
+ binding: extend(js, {
1839
1763
  done: function() {
1840
1764
  Object.assign(bindings, Function("return({" + this.txt + "})")())
1841
1765
  }
1842
1766
  }),
1843
- child: plugin.extend({
1767
+ child: extend(plugin, {
1844
1768
  done: function() {
1845
1769
  var key = "@child-" + (++seq)
1846
1770
  , root = append(this.parent, document.createComment(key))
@@ -1849,13 +1773,13 @@
1849
1773
  root._cp = root.childNodes.length - 1
1850
1774
  }
1851
1775
  }),
1852
- css: js.extend({
1776
+ css: extend(js, {
1853
1777
  done: Fn("xhr.css(this.txt)")
1854
1778
  }),
1855
- def: js.extend({
1779
+ def: extend(js, {
1856
1780
  done: Fn("View.def(this.params||this.txt)")
1857
1781
  }),
1858
- each: js.extend({
1782
+ each: extend(js, {
1859
1783
  done: function() {
1860
1784
  var txt = this.txt
1861
1785
 
@@ -1867,7 +1791,7 @@
1867
1791
  }),
1868
1792
  el: plugin,
1869
1793
  js: js,
1870
- map: js.extend({
1794
+ map: extend(js, {
1871
1795
  done: function() {
1872
1796
  var self = this
1873
1797
  , txt = (self.params + self.txt)
@@ -1879,7 +1803,7 @@
1879
1803
  }
1880
1804
  }),
1881
1805
  template: plugin,
1882
- view: plugin.extend({
1806
+ view: extend(plugin,{
1883
1807
  done: function() {
1884
1808
  var fn
1885
1809
  , t = this
@@ -1889,7 +1813,7 @@
1889
1813
  if (bind) {
1890
1814
  fn = bind.replace(renderRe, function(match, name, op, args) {
1891
1815
  return "(this['" + name + "']" + (
1892
- typeof view[name] == "function" ?
1816
+ typeof view[name] === "function" ?
1893
1817
  "(" + (args || "") + ")" :
1894
1818
  "=" + args
1895
1819
  ) + "),"
@@ -1898,7 +1822,7 @@
1898
1822
  }
1899
1823
  }
1900
1824
  }),
1901
- "view-link": plugin.extend({
1825
+ "view-link": extend(plugin, {
1902
1826
  done: function() {
1903
1827
  var t = this
1904
1828
  , arr = t.name.split(splitRe)
@@ -1958,7 +1882,7 @@
1958
1882
  map.bubble
1959
1883
  ););
1960
1884
  if (fn) {
1961
- typeof fn === "string" ? View.emit(fn, e, chr, el) : fn(e, chr, el)
1885
+ isString(fn) ? View.emit(fn, e, chr, el) : fn(e, chr, el)
1962
1886
  }
1963
1887
  }
1964
1888
 
@@ -2049,4 +1973,26 @@
2049
1973
  addEvent(window, "orientationchange", setBreakpointsRated)
2050
1974
  addEvent(window, "load", setBreakpointsRated)
2051
1975
  /**/
1976
+
1977
+ function extend(fn, opts) {
1978
+ function wrapper() {
1979
+ return fn.apply(this, arguments)
1980
+ }
1981
+ wrapper[P] = Object.create(fn[P])
1982
+ Object.assign(wrapper[P], opts)
1983
+ wrapper[P].constructor = wrapper
1984
+ return wrapper
1985
+ }
1986
+
1987
+ function isNumber(num) {
1988
+ return typeof num === "number"
1989
+ }
1990
+
1991
+ function isObject(obj) {
1992
+ return !!obj && obj.constructor === Object
1993
+ }
1994
+
1995
+ function isString(str) {
1996
+ return typeof str === "string"
1997
+ }
2052
1998
  }(window, document, Object, Event, "prototype")
package/load.js CHANGED
@@ -28,7 +28,7 @@
28
28
  // MSXML 6.0 has improved XSD, deprecated several legacy features
29
29
  // What's New in MSXML 6.0: https://msdn.microsoft.com/en-us/library/ms753751.aspx
30
30
 
31
- !function(window, Function) {
31
+ !function(window, Function, setTimeout) {
32
32
  xhr._s = new Date
33
33
  var loaded = {}
34
34
  , urlEscRe = /[+#\s]+/g
@@ -275,5 +275,5 @@
275
275
  /**/
276
276
 
277
277
  function nop() {}
278
- }(this, Function)
278
+ }(this, Function, setTimeout)
279
279
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litejs/ui",
3
- "version": "21.11.0",
3
+ "version": "22.12.0",
4
4
  "description": "UI engine for LiteJS full-stack framework",
5
5
  "license": "MIT",
6
6
  "author": "Lauri Rooden <lauri@rooden.ee>",
@@ -17,9 +17,9 @@
17
17
  "files": [
18
18
  "*.js",
19
19
  "binding",
20
- "component",
21
- "polyfill",
22
- "css"
20
+ "css",
21
+ "el",
22
+ "polyfill"
23
23
  ],
24
24
  "litejs": {
25
25
  "build": "lj b --out=test/index.html test/dev.html"
package/polyfill/index.js CHANGED
@@ -200,7 +200,7 @@
200
200
  /**/
201
201
  var data = {
202
202
  setItem: function(id, val) {
203
- return data[id] = String(val)
203
+ return data[id] = "" + val
204
204
  },
205
205
  getItem: function(id) {
206
206
  return data[id]
@@ -239,15 +239,14 @@
239
239
  },
240
240
  stringify: function stringify(o) {
241
241
  // IE 8 serializes `undefined` as `"undefined"`
242
- var c = typeof o
243
242
  return (
244
- c == "string" ? '"' + o.replace(jsonRe, jsonFn) + '"' :
245
- o && c == "object" ? (
243
+ isStr(o) ? '"' + o.replace(jsonRe, jsonFn) + '"' :
244
+ o && typeof o == "object" ? (
246
245
  isFn(o.toJSON) ? stringify(o.toJSON()) :
247
246
  isArr(o) ? "[" + o.map(stringify) + "]" :
248
247
  "{" + oKeys(o).map(function(a){return stringify(a) + ":" + stringify(o[a])}) + "}"
249
248
  ) :
250
- c == "number" && !isFinite(o) ? "null" :
249
+ typeof o == "number" && !isFinite(o) ? "null" :
251
250
  "" + o
252
251
  )
253
252
  }
@@ -290,6 +289,7 @@
290
289
  a = "c=[];for(b in a)o.call(a,b)&&c.push("
291
290
  b = ");return c"
292
291
  patch("entries", a + "[b,a[b]]" + b)
292
+ patch("hasOwn", "return!!(a&&o.call(a,b))")
293
293
  oKeys = patch("keys", a + "b" + b)
294
294
  patch("values", a + "a[b]" + b)
295
295
  //patch("fromEntries", "for(a=a.entries(),c={};!(b=a.next()).done;c[b[0]]=b[1]" + b)
@@ -303,13 +303,15 @@
303
303
 
304
304
  // TODO:2021-02-25:lauri:Accept iterable objects
305
305
  //patch("from", "a=S.call(a);return b?a.map(b,c):a")
306
- patch("from", "a=typeof a==='string'?a.split(''):b?a:S.call(a);return b?a.map(b,c):a")
306
+ patch("from", "a=X(a)?a.split(''):b?a:S.call(a);return b?a.map(b,c):a", 0, isStr)
307
307
  patch("of", "return S.call(A)")
308
308
 
309
309
  O = O[P]
310
310
  a = "var l=t.length,o=[],i=-1;"
311
+ b = "i+=b|0;while(++i<l)"
311
312
  c = "if(t[i]===a)return i;return -1"
312
- patch("indexOf", a + "i+=b|0;while(++i<l)" + c)
313
+ patch("includes", a + b + "if(t[i]===a||(a!==a&&t[i]!==t[i]))return!0;return!1")
314
+ patch("indexOf", a + b + c)
313
315
  patch("lastIndexOf", a + "i=(b|0)||l;i>--l&&(i=l)||i<0&&(i+=l);++i;while(--i>-1)" + c)
314
316
 
315
317
  b = a + "if(A.length<2)b=t"
@@ -329,6 +331,7 @@
329
331
  patch("some", b + "return!0;return!1")
330
332
 
331
333
  patch("flat", "return a<1?S.call(t):(b=t.concat.apply([],t))&&a>1&&b.some(X)?b.flat(a-1):b", 0, isArr)
334
+ patch("flatMap", "return X.apply(t,A).flat()", 0, O.map)
332
335
  //patch("entries", "a=this;b=-1;return{next:function(){c=a.length<=++b;return{done:c,value:c?void 0:a[b]}}}")
333
336
 
334
337
 
@@ -406,7 +409,7 @@
406
409
  }
407
410
  function walk(el, by, sel, first, nextFn) {
408
411
  var out = []
409
- if (typeof sel !== "function") sel = selectorFn(sel)
412
+ if (!isFn(sel)) sel = selectorFn(sel)
410
413
  for (; el; el = el[by] || nextFn && nextFn(el)) if (sel(el)) {
411
414
  if (first === 1) return el
412
415
  out.push(el)
@@ -423,7 +426,7 @@
423
426
 
424
427
  // ie6789
425
428
  // The documentMode is an IE only property, supported from IE8.
426
- if (ie678 || document.documentMode <= 9) {
429
+ if (ie678) {
427
430
  try {
428
431
  // Remove background image flickers on hover in IE6
429
432
  // You could also use CSS
@@ -432,15 +435,18 @@
432
435
  } catch(e){}
433
436
  }
434
437
 
435
- function isFn(f) {
436
- return typeof f === "function"
438
+ function isFn(value) {
439
+ return typeof value === "function"
440
+ }
441
+ function isStr(value) {
442
+ return typeof value === "string"
437
443
  }
438
444
  function nop() {}
439
445
 
440
446
  function patch(key_, src, force, arg1, arg2) {
441
447
  var key = key_.split(":").pop()
442
448
  return !force && O[key] || (O[patched.push(key_), key] = (
443
- typeof src === "string" ?
449
+ isStr(src) ?
444
450
  Function("o,O,P,S,F,X,Y", "return function(a,b,c){var t=this,A=arguments;" + src + "}")(hasOwn, O[key], P, patched.slice, force, arg1, arg2) :
445
451
  src || {}
446
452
  ))
package/schema-apply.js CHANGED
@@ -46,6 +46,9 @@
46
46
  } else if (type == "string") {
47
47
  if (type !== actualType) data = "" + data
48
48
  } else if (type === "number" || type == "integer") {
49
+ if (schema["ui:el"] == "date-time") {
50
+ data = Date.parse(data)
51
+ }
49
52
  data = (data + "").replace(",", ".")
50
53
  data = type === "number" ? parseFloat(data) : parseInt(data, 10)
51
54
 
@@ -75,7 +78,7 @@
75
78
  return memo
76
79
  }, []) :
77
80
  null
78
- } else {
81
+ } else if (data) {
79
82
  var reqArr = Array.isArray(schema.required) && schema.required
80
83
  Object.each(schema.properties, function(propSchema, prop) {
81
84
  if (data[prop] !== void 0) {