@semantic-ui/templating
Advanced tools
Comparing version 0.0.20 to 0.0.21
@@ -8,9 +8,9 @@ { | ||
"dependencies": { | ||
"@semantic-ui/component": "^0.0.20", | ||
"@semantic-ui/query": "^0.0.20", | ||
"@semantic-ui/reactivity": "^0.0.20", | ||
"@semantic-ui/templating": "^0.0.20", | ||
"@semantic-ui/utils": "^0.0.20" | ||
"@semantic-ui/component": "^0.0.21", | ||
"@semantic-ui/query": "^0.0.21", | ||
"@semantic-ui/reactivity": "^0.0.21", | ||
"@semantic-ui/templating": "^0.0.21", | ||
"@semantic-ui/utils": "^0.0.21" | ||
}, | ||
"version": "0.0.20" | ||
"version": "0.0.21" | ||
} |
@@ -31,3 +31,3 @@ import { each, isString, last } from '@semantic-ui/utils'; | ||
VERBOSE_PROPERTIES: /(\w+)\s*=\s*(((?!\w+\s*=).)+)/gms, | ||
STANDARD: /(\w.*?)($|\s)/gm, | ||
STANDARD: /(\w+)\s*=\s*((?:(?!\n|$|\w+\s*=).)+)/g, | ||
DATA_OBJECT: /(\w+)\s*:\s*([^,}]+)/g, // parses { one: 'two' } | ||
@@ -260,15 +260,9 @@ }; | ||
let data = {}; | ||
const matches = [...expression.matchAll(regExp.STANDARD)]; | ||
each(matches, (match, index) => { | ||
if (index == 0) { | ||
templateInfo.name = `'${match[0].trim()}'`; | ||
} | ||
else { | ||
const parts = match[0].split('='); | ||
if (parts.length) { | ||
let name = parts[0].trim(); | ||
let value = parts[1].trim(); | ||
data[name] = value; | ||
} | ||
} | ||
const name = expression.split(/\b/)[0]; | ||
templateInfo.name = `'${name}'`; | ||
const dataMatches = [...expression.matchAll(regExp.STANDARD)]; | ||
each(dataMatches, (match, index) => { | ||
let name = match[1].trim(); | ||
let value = match[2].trim(); | ||
data[name] = value; | ||
}); | ||
@@ -275,0 +269,0 @@ templateInfo.data = data; |
@@ -8,2 +8,3 @@ import { Reaction } from '@semantic-ui/reactivity'; | ||
formatDate, | ||
each, | ||
escapeHTML, | ||
@@ -33,2 +34,5 @@ tokenize, | ||
}, | ||
concat(a, b) { | ||
return a + b; | ||
}, | ||
not(a) { | ||
@@ -50,2 +54,11 @@ return !a; | ||
}, | ||
classMap(classObj) { | ||
let classNames = []; | ||
each(classObj, (condition, className) => { | ||
if(condition) { | ||
classNames.push(className); | ||
} | ||
}); | ||
return (classNames.length) ? `${classNames.join(' ')} `: ''; | ||
}, | ||
maybe(expr, trueExpr, falseExpr) { | ||
@@ -52,0 +65,0 @@ return expr ? trueExpr : falseExpr; |
import { $ } from '@semantic-ui/query'; | ||
import { capitalize, fatal, each, remove, generateID, isEqual, noop, isServer, inArray, isFunction, extend, wrapFunction } from '@semantic-ui/utils'; | ||
import { capitalize, fatal, each, remove, clone, generateID, isEqual, noop, isServer, inArray, isFunction, extend, wrapFunction } from '@semantic-ui/utils'; | ||
import { ReactiveVar, Reaction } from '@semantic-ui/reactivity'; | ||
@@ -23,3 +23,3 @@ | ||
events, | ||
state, | ||
stateConfig, | ||
subTemplates, | ||
@@ -46,3 +46,4 @@ createInstance, | ||
this.reactions = []; | ||
this.state = state || {}; | ||
this.stateConfig = stateConfig; | ||
this.state = this.createReactiveState(stateConfig) || {}; | ||
this.templateName = templateName || this.getGenericTemplateName(); | ||
@@ -60,2 +61,3 @@ this.subTemplates = subTemplates; | ||
this.isPrototype = isPrototype; | ||
this.parentTemplate = parentTemplate; | ||
this.attachStyles = attachStyles; | ||
@@ -69,2 +71,18 @@ this.element = element; | ||
createReactiveState(stateConfig) { | ||
let reactiveState = {}; | ||
each(stateConfig, (config, name) => { | ||
if(config?.value && config?.options) { | ||
// complex config { counter: { value: 0, options: { equalityFunction }}} | ||
reactiveState[name] = new ReactiveVar(config.value, config.options); | ||
} | ||
else { | ||
// simple config i.e. { counter: 0 } | ||
const initialValue = config; | ||
reactiveState[name] = new ReactiveVar(initialValue); | ||
} | ||
}); | ||
return reactiveState; | ||
} | ||
setDataContext(data, { rerender = true } = {}) { | ||
@@ -188,2 +206,3 @@ this.data = data; | ||
...this.data, | ||
...this.state, | ||
...this.tpl, | ||
@@ -226,2 +245,3 @@ }; | ||
css: this.css, | ||
stateConfig: this.stateConfig, | ||
events: this.events, | ||
@@ -233,2 +253,3 @@ renderingEngine: this.renderingEngine, | ||
onRendered: this.onRenderedCallback, | ||
parentTemplate: this.parentTemplate, | ||
onDestroyed: this.onDestroyedCallback, | ||
@@ -243,17 +264,9 @@ createInstance: this.createInstance, | ||
attachEvents(events = this.events) { | ||
if (!this.parentNode || !this.renderRoot) { | ||
fatal('You must set a parent before attaching events'); | ||
} | ||
this.removeEvents(); | ||
// format like 'click .foo baz' | ||
const parseEventString = (eventString) => { | ||
const parts = eventString.split(' '); | ||
let eventName = parts[0]; | ||
parts.shift(); | ||
const selector = parts.join(' '); | ||
parseEventString(eventString) { | ||
// we are using event delegation so we will have to bind | ||
// some events to their corresponding event that bubbles | ||
const getBubbledEvent = (eventName) => { | ||
const bubbleMap = { | ||
blur: 'focusout', | ||
focus: 'focusin', | ||
//change: 'input', | ||
load: 'DOMContentLoaded', | ||
@@ -264,8 +277,46 @@ unload: 'beforeunload', | ||
}; | ||
if (bubbleMap[eventName]) { | ||
if(bubbleMap[eventName]) { | ||
eventName = bubbleMap[eventName]; | ||
} | ||
return { eventName, selector }; | ||
return eventName; | ||
}; | ||
let events = []; | ||
let parts = eventString.split(/\s+/); | ||
let addedEvents = false; | ||
const eventNames = []; | ||
const selectors = []; | ||
each(parts, (part, index) => { | ||
const value = part.replace(/(\,|\W)+$/, '').trim(); | ||
if(!addedEvents) { | ||
eventNames.push(getBubbledEvent(value)); | ||
addedEvents = (part.includes(',') === false); | ||
} | ||
else { | ||
selectors.push(value); | ||
} | ||
}); | ||
if(eventNames.length > 1) { | ||
each(eventNames, (eventName) => { | ||
events.push({ eventName, selector: selectors[0] }); | ||
}); | ||
} | ||
else if(selectors.length > 1) { | ||
each(selectors, (selector) => { | ||
events.push({ eventName: eventNames[0], selector }); | ||
}); | ||
} | ||
else { | ||
events.push({ eventName: eventNames[0], selector: selectors[0] || '' }); | ||
} | ||
return events; | ||
} | ||
attachEvents(events = this.events) { | ||
if (!this.parentNode || !this.renderRoot) { | ||
fatal('You must set a parent before attaching events'); | ||
} | ||
this.removeEvents(); | ||
// this is to cancel event bindings when template tears down | ||
@@ -288,38 +339,37 @@ // <https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal> | ||
each(events, (eventHandler, eventString) => { | ||
const { eventName, selector } = parseEventString(eventString); | ||
const subEvents = this.parseEventString(eventString); | ||
const template = this; | ||
// BUG: iOS Safari will not bubble the touchstart / touchend events | ||
// if theres no handler on the actual element | ||
if(selector) { | ||
$(selector, { root: this.renderRoot }).on(eventName, noop); | ||
} | ||
$(this.renderRoot).on( | ||
eventName, | ||
selector, | ||
(event) => { | ||
if (!this.isNodeInTemplate(event.target)) { | ||
console.log('ignored event because it is not in template', eventName, selector); | ||
return; | ||
} | ||
if ( | ||
(eventName === 'mouseover' || eventName === 'mouseout') && | ||
event.relatedTarget && | ||
event.target.contains(event.relatedTarget) | ||
) { | ||
return; | ||
} | ||
const targetElement = (selector) | ||
? $(event.target).closest(selector).get(0) // delegation | ||
: event.target | ||
; | ||
const boundEvent = eventHandler.bind(targetElement); | ||
const eventData = event?.detail || {}; | ||
const elData = targetElement.dataset; | ||
template.call(boundEvent, { | ||
additionalData: { event: event, data: { ...elData, ...eventData } }, | ||
}); | ||
}, | ||
{ abortController: this.eventController } | ||
); | ||
each(subEvents, (event) => { | ||
const { eventName, selector } = event; | ||
// BUG: iOS Safari will not bubble the touchstart / touchend events | ||
// if theres no handler on the actual element | ||
if(selector) { | ||
$(selector, { root: this.renderRoot }).on(eventName, noop); | ||
} | ||
$(this.renderRoot).on( | ||
eventName, | ||
selector, | ||
(event) => { | ||
if (!this.isNodeInTemplate(event.target)) { | ||
return; | ||
} | ||
if (inArray(eventName, ['mouseover', 'mouseout']) | ||
&& event.relatedTarget | ||
&& event.target.contains(event.relatedTarget)) { | ||
return; | ||
} | ||
const targetElement = (selector) | ||
? $(event.target).closest(selector).get(0) // delegation | ||
: event.target | ||
; | ||
const boundEvent = eventHandler.bind(targetElement); | ||
const eventData = event?.detail || {}; | ||
const elData = targetElement.dataset; | ||
template.call(boundEvent, { | ||
additionalData: { event: event, data: { ...elData, ...eventData } }, | ||
}); | ||
}, | ||
{ abortController: this.eventController } | ||
); | ||
}); | ||
}); | ||
@@ -339,3 +389,7 @@ } | ||
while (node && node.parentNode !== this.parentNode) { | ||
node = node.parentNode; | ||
if (node.parentNode === null && node.host) { | ||
node = node.host; | ||
} else { | ||
node = node.parentNode; | ||
} | ||
} | ||
@@ -353,3 +407,3 @@ return node; | ||
if (node === null) { | ||
return; | ||
return false; | ||
} | ||
@@ -415,3 +469,3 @@ const startComparison = startNode.compareDocumentPosition(node); | ||
$$(selector, args) { | ||
return this.$(selector, { root: this.renderRoot, filterTemplate: false, ...args }); | ||
return this.$(selector, { root: this.renderRoot, pierceShadow: true, filterTemplate: true, ...args }); | ||
} | ||
@@ -432,2 +486,3 @@ | ||
$: this.$.bind(this), | ||
$$: this.$$.bind(this), | ||
@@ -439,7 +494,7 @@ reaction: this.reaction.bind(this), | ||
settings: this.element.settings, | ||
state: this.element.state, | ||
state: this.state, | ||
isRendered: this.rendered, | ||
isServer: Template.isServer, | ||
isClient: !Template.isServer, // convenience | ||
isClient: !Template.isServer, | ||
@@ -446,0 +501,0 @@ dispatchEvent: this.dispatchEvent.bind(this), |
@@ -667,2 +667,85 @@ import { describe, expect, it, vi } from 'vitest'; | ||
}); | ||
it('should compile a template with a partial and data containing parentheses', () => { | ||
const compiler = new TemplateCompiler(); | ||
const template = ` | ||
<div> | ||
{{> CodePlaygroundPanel size=(getPanelSize) }} | ||
</div> | ||
`; | ||
const ast = compiler.compile(template); | ||
const expectedAST = [ | ||
{ type: 'html', html: '<div>\n ' }, | ||
{ | ||
type: 'template', | ||
name: "'CodePlaygroundPanel'", | ||
data: { size: '(getPanelSize)' }, | ||
}, | ||
{ type: 'html', html: '\n </div>' }, | ||
]; | ||
expect(ast).toEqual(expectedAST); | ||
}); | ||
it('should compile a template with a partial and data containing parentheses and spaces', () => { | ||
const compiler = new TemplateCompiler(); | ||
const template = ` | ||
<div> | ||
{{> CodePlaygroundPanel size=(getPanelSize panel) }} | ||
</div> | ||
`; | ||
const ast = compiler.compile(template); | ||
const expectedAST = [ | ||
{ type: 'html', html: '<div>\n ' }, | ||
{ | ||
type: 'template', | ||
name: "'CodePlaygroundPanel'", | ||
data: { size: '(getPanelSize panel)' }, | ||
}, | ||
{ type: 'html', html: '\n </div>' }, | ||
]; | ||
expect(ast).toEqual(expectedAST); | ||
}); | ||
it('should compile a template with a partial and data containing line breaks', () => { | ||
const compiler = new TemplateCompiler(); | ||
const template = ` | ||
<div> | ||
{{> CodePlaygroundPanel | ||
panel=panel | ||
size=(getPanelSize panel) | ||
}} | ||
</div> | ||
`; | ||
const ast = compiler.compile(template); | ||
const expectedAST = [ | ||
{ type: 'html', html: '<div>\n ' }, | ||
{ | ||
type: 'template', | ||
name: "'CodePlaygroundPanel'", | ||
data: { panel: 'panel', size: '(getPanelSize panel)' }, | ||
}, | ||
{ type: 'html', html: '\n </div>' }, | ||
]; | ||
expect(ast).toEqual(expectedAST); | ||
}); | ||
it('should compile a template with a partial and data containing multiple parentheses', () => { | ||
const compiler = new TemplateCompiler(); | ||
const template = ` | ||
<div> | ||
{{> CodePlaygroundPanel size=(getPanelSize (getPanel)) }} | ||
</div> | ||
`; | ||
const ast = compiler.compile(template); | ||
const expectedAST = [ | ||
{ type: 'html', html: '<div>\n ' }, | ||
{ | ||
type: 'template', | ||
name: "'CodePlaygroundPanel'", | ||
data: { size: '(getPanelSize (getPanel))' }, | ||
}, | ||
{ type: 'html', html: '\n </div>' }, | ||
]; | ||
expect(ast).toEqual(expectedAST); | ||
}); | ||
}); | ||
@@ -738,2 +821,5 @@ | ||
}); | ||
}); | ||
@@ -740,0 +826,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
74673
2149
+ Added@semantic-ui/component@0.0.21(transitive)
+ Added@semantic-ui/query@0.0.21(transitive)
+ Added@semantic-ui/reactivity@0.0.21(transitive)
+ Added@semantic-ui/utils@0.0.21(transitive)
- Removed@semantic-ui/component@0.0.20(transitive)
- Removed@semantic-ui/query@0.0.20(transitive)
- Removed@semantic-ui/reactivity@0.0.20(transitive)
- Removed@semantic-ui/utils@0.0.20(transitive)
Updated@semantic-ui/query@^0.0.21
Updated@semantic-ui/utils@^0.0.21