-
Notifications
You must be signed in to change notification settings - Fork 1
/
lit-extended.js
140 lines (140 loc) · 4.84 KB
/
lit-extended.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
* @license
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at
* http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at
* http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at
* http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/
import { AttributePart, defaultPartCallback, noChange, getValue, SVGTemplateResult, TemplateResult } from './lit-html.js'
export { render } from './lit-html.js'
/**
* Interprets a template literal as a lit-extended HTML template.
*/
export const html = (strings, ...values) => new TemplateResult(strings, values, 'html', extendedPartCallback)
/**
* Interprets a template literal as a lit-extended SVG template.
*/
export const svg = (strings, ...values) => new SVGTemplateResult(strings, values, 'svg', extendedPartCallback)
/**
* A PartCallback which allows templates to set properties and declarative
* event handlers.
*
* Properties are set by default, instead of attributes. Attribute names in
* lit-html templates preserve case, so properties are case sensitive. If an
* expression takes up an entire attribute value, then the property is set to
* that value. If an expression is interpolated with a string or other
* expressions then the property is set to the string result of the
* interpolation.
*
* To set an attribute instead of a property, append a `$` suffix to the
* attribute name.
*
* Example:
*
* html`<button class$="primary">Buy Now</button>`
*
* To set an event handler, prefix the attribute name with `on-`:
*
* Example:
*
* html`<button on-click=${(e)=> this.onClickHandler(e)}>Buy Now</button>`
*
*/
export const extendedPartCallback = (instance, templatePart, node) => {
if (templatePart.type === 'attribute') {
if (templatePart.rawName.substr(0, 3) === 'on-') {
const eventName = templatePart.rawName.slice(3)
return new EventPart(instance, node, eventName)
}
const lastChar = templatePart.name.substr(templatePart.name.length - 1)
if (lastChar === '$') {
const name = templatePart.name.slice(0, -1)
return new AttributePart(instance, node, name, templatePart.strings)
}
if (lastChar === '?') {
const name = templatePart.name.slice(0, -1)
return new BooleanAttributePart(instance, node, name, templatePart.strings)
}
return new PropertyPart(instance, node, templatePart.rawName, templatePart.strings)
}
return defaultPartCallback(instance, templatePart, node)
}
/**
* Implements a boolean attribute, roughly as defined in the HTML
* specification.
*
* If the value is truthy, then the attribute is present with a value of
* ''. If the value is falsey, the attribute is removed.
*/
export class BooleanAttributePart extends AttributePart {
setValue (values, startIndex) {
const s = this.strings
if (s.length === 2 && s[0] === '' && s[1] === '') {
const value = getValue(this, values[startIndex])
if (value === noChange) {
return
}
if (value) {
this.element.setAttribute(this.name, '')
} else {
this.element.removeAttribute(this.name)
}
} else {
throw new Error('boolean attributes can only contain a single expression')
}
}
}
export class PropertyPart extends AttributePart {
setValue (values, startIndex) {
const s = this.strings
let value
if (this._equalToPreviousValues(values, startIndex)) {
return
}
if (s.length === 2 && s[0] === '' && s[1] === '') {
// An expression that occupies the whole attribute value will leave
// leading and trailing empty strings.
value = getValue(this, values[startIndex])
} else {
// Interpolation, so interpolate
value = this._interpolate(values, startIndex)
}
if (value !== noChange) {
this.element[this.name] = value
}
this._previousValues = values
}
}
export class EventPart {
constructor (instance, element, eventName) {
this.instance = instance
this.element = element
this.eventName = eventName
}
setValue (value) {
const listener = getValue(this, value)
if (listener === this._listener) {
return
}
if (listener == null) {
this.element.removeEventListener(this.eventName, this)
} else if (this._listener == null) {
this.element.addEventListener(this.eventName, this)
}
this._listener = listener
}
handleEvent (event) {
if (typeof this._listener === 'function') {
this._listener.call(this.element, event)
} else if (typeof this._listener.handleEvent === 'function') {
this._listener.handleEvent(event)
}
}
}
// # sourceMappingURL=lit-extended.js.map