@lightningjs/blits 1.1.0 → 1.3.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/NOTICE +9 -0
  3. package/docs/_sidebar.md +1 -0
  4. package/docs/built-in/directives.md +4 -6
  5. package/docs/built-in/for-loop.md +6 -8
  6. package/docs/components/component_state.md +3 -5
  7. package/docs/components/computed_properties.md +3 -5
  8. package/docs/components/lifecycle_events.md +2 -4
  9. package/docs/components/methods.md +1 -3
  10. package/docs/components/props.md +3 -5
  11. package/docs/components/user_input.md +6 -8
  12. package/docs/components/utilities.md +1 -2
  13. package/docs/components/watchers.md +2 -4
  14. package/docs/essentials/application_root.md +1 -3
  15. package/docs/essentials/components.md +2 -4
  16. package/docs/essentials/displaying_images.md +4 -6
  17. package/docs/essentials/displaying_text.md +4 -6
  18. package/docs/essentials/element_attributes.md +10 -12
  19. package/docs/essentials/template_syntax.md +5 -7
  20. package/docs/getting_started/file_structure.md +9 -11
  21. package/docs/getting_started/getting_started.md +5 -7
  22. package/docs/plugins/language.md +172 -0
  23. package/docs/plugins/text-to-speech-announcer.md +2 -4
  24. package/docs/sidebar.json +4 -0
  25. package/docs/transitions_animations/transitions.md +5 -7
  26. package/index.d.ts +2 -0
  27. package/index.js +2 -0
  28. package/package.json +3 -2
  29. package/src/component/base/index.js +4 -1
  30. package/src/component/base/log.js +1 -1
  31. package/src/component/base/methods.js +1 -2
  32. package/src/component/setup/state.js +9 -13
  33. package/src/component.d.ts +6 -0
  34. package/src/component.js +30 -10
  35. package/src/components/FPScounter.js +56 -12
  36. package/src/components/index.js +0 -2
  37. package/src/components/index.orig.js +0 -2
  38. package/src/engines/L3/element.js +56 -66
  39. package/src/helpers/fetchJson.js +34 -0
  40. package/src/lib/codegenerator/generator.js +104 -28
  41. package/src/lib/codegenerator/generator.test.js +184 -0
  42. package/src/lib/colors/colors.js +6 -7
  43. package/src/lib/reactivity/reactive.js +3 -5
  44. package/src/lib/symbols.js +1 -0
  45. package/src/lib/templateparser/parser.js +1 -1
  46. package/src/plugin.d.ts +71 -0
  47. package/src/plugin.js +23 -0
  48. package/src/{components/Image.orig.js → plugins/index.js} +2 -17
  49. package/src/plugins/language.js +122 -0
  50. package/src/components/Image.js +0 -52
@@ -70,7 +70,7 @@ const generateElementCode = function (
70
70
  renderCode.push(`const elementConfig${counter} = {}`)
71
71
 
72
72
  if (options.forloop) {
73
- renderCode.push(`if(!${elm}) {`)
73
+ renderCode.push(`if(${elm} === undefined) {`)
74
74
  }
75
75
 
76
76
  renderCode.push(`
@@ -99,9 +99,20 @@ const generateElementCode = function (
99
99
 
100
100
  if (isReactiveKey(key)) {
101
101
  if (options.holder && key === ':color') return
102
- this.effectsCode.push(
103
- `${elm}.set('${key.substring(1)}', ${interpolate(templateObject[key], options.component)})`
104
- )
102
+ if (options.holder) {
103
+ this.effectsCode.push(`
104
+ if(typeof skip${counter} === 'undefined' ||
105
+ skip${counter}.indexOf('${key.substring(1)}') === -1)
106
+ ${elm}.set('${key.substring(1)}', ${interpolate(templateObject[key], options.component)})
107
+ `)
108
+ } else {
109
+ this.effectsCode.push(`
110
+ ${elm}.set('${key.substring(1)}', ${interpolate(
111
+ templateObject[key],
112
+ options.component
113
+ )})
114
+ `)
115
+ }
105
116
  renderCode.push(
106
117
  `elementConfig${counter}['${key.substring(1)}'] = ${interpolate(
107
118
  templateObject[key],
@@ -117,16 +128,18 @@ const generateElementCode = function (
117
128
 
118
129
  if (options.holder === true) {
119
130
  renderCode.push(`
131
+ const skip${counter} = []
120
132
  if(typeof cmp${counter} !== 'undefined') {
121
133
  for(let key in cmp${counter}.config.props) {
122
134
  delete elementConfig${counter}[cmp${counter}.config.props[key]]
135
+ skip${counter}.push(cmp${counter}.config.props[key])
123
136
  }
124
137
  }
125
138
  `)
126
139
  }
127
140
 
128
141
  if (options.forloop) {
129
- renderCode.push(`if(!${elm}.nodeId) {`)
142
+ renderCode.push(`if(${elm}.nodeId === undefined) {`)
130
143
  }
131
144
 
132
145
  renderCode.push(`${elm}.populate(elementConfig${counter})`)
@@ -187,6 +200,11 @@ const generateComponentCode = function (
187
200
  }
188
201
 
189
202
  renderCode.push(`const props${counter} = {}`)
203
+
204
+ if (options.forloop) {
205
+ renderCode.push(`if(${elm} === undefined) {`)
206
+ }
207
+
190
208
  Object.keys(templateObject).forEach((key) => {
191
209
  if (isReactiveKey(key)) {
192
210
  this.effectsCode.push(`
@@ -207,10 +225,6 @@ const generateComponentCode = function (
207
225
  }
208
226
  })
209
227
 
210
- if (options.forloop) {
211
- renderCode.push(`if(!${elm}) {`)
212
- }
213
-
214
228
  renderCode.push(`
215
229
  componentType = props${counter}['is'] || '${templateObject[Symbol.for('componentType')]}'
216
230
 
@@ -256,6 +270,11 @@ const generateForLoopCode = function (templateObject, parent) {
256
270
  const key = templateObject['key']
257
271
  const forKey = interpolate(key, 'scope.')
258
272
 
273
+ const shallow = !!!(
274
+ templateObject['$shallow'] && templateObject['$shallow'].toLowerCase() === 'false'
275
+ )
276
+ delete templateObject['$shallow']
277
+
259
278
  delete templateObject['key']
260
279
  const regex = /(.+)\s+in\s+(.+)/gi
261
280
  // const regex = /(:?\(*)(.+)\s+in\s+(.+)/gi
@@ -287,7 +306,12 @@ const generateForLoopCode = function (templateObject, parent) {
287
306
  const created${forStartCounter} = []
288
307
  const forloop${forStartCounter} = (collection = [], elms, created) => {
289
308
  const rawCollection = getRaw(collection)
290
- const keys = new Set(rawCollection.map((${item}) => '' + ${interpolate(key, '')}))
309
+ const keys = new Set()
310
+ let l = rawCollection.length
311
+ while(l--) {
312
+ const ${item} = rawCollection[l]
313
+ keys.add('' + ${interpolate(key, '') || 'l'})
314
+ }
291
315
  `)
292
316
 
293
317
  // keep track of the index in the render code so we can inject
@@ -297,13 +321,13 @@ const generateForLoopCode = function (templateObject, parent) {
297
321
 
298
322
  ctx.renderCode.push(`
299
323
  created.length = 0
300
- const length = collection.length
324
+ const length = rawCollection.length
301
325
  for(let __index = 0; __index < length; __index++) {
302
326
  const scope = Object.create(component)
303
327
  parent = ${parent}
304
328
  scope['${index}'] = __index
305
329
  scope['${item}'] = rawCollection[__index]
306
- scope['key'] = ${forKey || '__index'}
330
+ scope['key'] = '' + ${forKey || '__index'}
307
331
  `)
308
332
  if ('ref' in templateObject && templateObject.ref.indexOf('$') === -1) {
309
333
  // automatically map the ref for each item in the loop based on the given ref key
@@ -347,24 +371,33 @@ const generateForLoopCode = function (templateObject, parent) {
347
371
  (effect) => [...effect.matchAll(scopeRegex)].length !== 0
348
372
  )
349
373
 
350
- ctx.renderCode.push(`
351
- scope['${item}'] = collection[__index]
374
+ if (shallow === false) {
375
+ ctx.renderCode.push(`
376
+ scope['${item}'] = null
377
+ scope['${item}'] = collection[__index]
352
378
  `)
379
+ }
353
380
 
354
381
  // inner scope variables are part of the main forloop
355
382
  innerScopeEffects.forEach((effect) => {
356
383
  const key = effect.indexOf(`scope.${index}`) > -1 ? `'${interpolate(result[2], '')}'` : null
357
- ctx.renderCode.push(`
358
- effect(() => {
384
+ if (effect.indexOf("Symbol.for('props')") === -1) {
385
+ ctx.renderCode.push(`
386
+ effect(() => {
387
+ ${effect}
388
+ }, ${key})
389
+ `)
390
+ } else {
391
+ // props shouldn't be wrapped in an effect, but simply passed on
392
+ ctx.renderCode.push(`
359
393
  ${effect}
360
- }, ${key})
361
- `)
394
+ `)
395
+ }
362
396
  })
363
-
397
+ // if(elms[${forStartCounter}][0] && elms[${forStartCounter}][0].forComponent && elms[${forStartCounter}][0].forComponent.___layout) {
398
+ // elms[${forStartCounter}][0].forComponent.___layout()
399
+ // }
364
400
  ctx.renderCode.push(`
365
- if(elms[${forStartCounter}][0] && elms[${forStartCounter}][0].forComponent && elms[${forStartCounter}][0].forComponent.___layout) {
366
- elms[${forStartCounter}][0].forComponent.___layout()
367
- }
368
401
  }
369
402
  }`)
370
403
 
@@ -374,8 +407,8 @@ const generateForLoopCode = function (templateObject, parent) {
374
407
  let i = created.length
375
408
 
376
409
  while (i--) {
377
- const key = created[i]
378
- if (!keys.has(key)) {
410
+ if (keys.has(created[i]) === false) {
411
+ const key = created[i]
379
412
  `)
380
413
  const forEndCounter = counter
381
414
 
@@ -458,7 +491,7 @@ const generateCode = function (templateObject, parent = false, options = {}) {
458
491
  const interpolate = (val, component = 'component.') => {
459
492
  if (val === undefined) return val
460
493
  const replaceString = /('.*?')+/gi
461
- const replaceDollar = /\$/gi
494
+ const replaceDollar = /\$(\$(?=\$)|\$?)/g
462
495
  const matches = val.matchAll(replaceString)
463
496
  const restore = []
464
497
 
@@ -471,10 +504,19 @@ const interpolate = (val, component = 'component.') => {
471
504
  i++
472
505
  }
473
506
 
474
- // replace remaining dollar signs
475
- val = val.replace(replaceDollar, component || '')
507
+ // replace dollar signs using the regex and function
508
+ val = val.replace(replaceDollar, (match, group1) => {
509
+ // single dollar sign
510
+ if (group1 === '') {
511
+ return component
512
+ }
513
+ // consecutive dollar sign, replace only the first $
514
+ else if (group1 === '$') {
515
+ return component + '$'
516
+ }
517
+ })
476
518
 
477
- // restore string replacemenet
519
+ // restore string replacement
478
520
  restore.forEach((el, idx) => {
479
521
  val = val.replace(`[@@REPLACEMENT${idx}@@]`, el)
480
522
  })
@@ -483,6 +525,7 @@ const interpolate = (val, component = 'component.') => {
483
525
  }
484
526
 
485
527
  const cast = (val = '', key = false, component = 'component.') => {
528
+ const dynamicArgumentRegex = /\$\w+/gi
486
529
  let castedValue
487
530
 
488
531
  // inline content
@@ -533,6 +576,21 @@ const cast = (val = '', key = false, component = 'component.') => {
533
576
  else if (val.startsWith('$')) {
534
577
  castedValue = `${component}${val.replace('$', '')}`
535
578
  }
579
+ // dynamic value in object
580
+ else if (dynamicArgumentRegex.exec(val)) {
581
+ const rex = /\w+\s*:\s*(?:[^\s,}]+|".*?"|'.*?')/g
582
+ const results = val.match(rex)
583
+ castedValue = {}
584
+ if (results) {
585
+ for (let i = 0; i < results.length; i++) {
586
+ const members = results[i].split(/\s*:\s*/)
587
+ if (members) {
588
+ populateFields(members[0], members[1], component, castedValue)
589
+ }
590
+ }
591
+ }
592
+ return interpolateObject(castedValue)
593
+ }
536
594
  // static string
537
595
  else {
538
596
  castedValue = `"${val}"`
@@ -554,3 +612,21 @@ const parseInlineContent = (val, component) => {
554
612
  }
555
613
  return val
556
614
  }
615
+
616
+ // Populate value into target's prop
617
+ const populateFields = (prop, val, component, target) => {
618
+ if (val.startsWith('$')) {
619
+ target[prop] = `${component}${val.replace('$', '')}`
620
+ } else {
621
+ target[prop] = val
622
+ }
623
+ }
624
+
625
+ const interpolateObject = (input) => {
626
+ const interpolatedResults = []
627
+ Object.keys(input).forEach((key) => {
628
+ interpolatedResults.push(`${key}: ${input[key]}`)
629
+ })
630
+
631
+ return ` { ${interpolatedResults.join(', ')} }`
632
+ }
@@ -684,6 +684,138 @@ test('Generate code for a template with dynamic attributes with code to be evalu
684
684
  assert.end()
685
685
  })
686
686
 
687
+ test('Generate code for a template with attribute (object)', (assert) => {
688
+ const templateObject = {
689
+ children: [
690
+ {
691
+ [Symbol.for('componentType')]: 'Element',
692
+ w: '100',
693
+ h: '100',
694
+ color: '{top: 0xff0000ff, bottom: 0x008000ff, left: 0xffff00ff }',
695
+ },
696
+ ],
697
+ }
698
+
699
+ const expectedRender = `
700
+ function anonymous(parent,component,context,components,effect,getRaw) {
701
+ const elms = []
702
+ let componentType
703
+ const rootComponent = component
704
+ const elementConfig0 = {}
705
+
706
+ elms[0] = this.element({parent: parent || 'root'}, component)
707
+ elementConfig0['w'] = 100
708
+ elementConfig0['h'] = 100
709
+ elementConfig0['color'] = "{top: 0xff0000ff, bottom: 0x008000ff, left: 0xffff00ff}"
710
+ elms[0].populate(elementConfig0)
711
+
712
+ return elms
713
+ }
714
+ `
715
+
716
+ const actual = generator.call(scope, templateObject)
717
+ console.log(actual.render.toString())
718
+ assert.equal(
719
+ normalize(actual.render.toString()),
720
+ normalize(expectedRender),
721
+ 'Generator should return a render function with the correct code'
722
+ )
723
+ assert.ok(
724
+ Array.isArray(actual.effects) && actual.effects.length === 0,
725
+ 'Generator should return an empty effects array'
726
+ )
727
+
728
+ assert.end()
729
+ })
730
+
731
+ test('Generate code for a template with dynamic attribute (object)', (assert) => {
732
+ const templateObject = {
733
+ children: [
734
+ {
735
+ [Symbol.for('componentType')]: 'Element',
736
+ w: '100',
737
+ h: '100',
738
+ color: '{top: $colorT, bottom: $colorB, left:$colorL}',
739
+ },
740
+ ],
741
+ }
742
+
743
+ const expectedRender = `
744
+ function anonymous(parent,component,context,components,effect,getRaw) {
745
+ const elms = []
746
+ let componentType
747
+ const rootComponent = component
748
+ const elementConfig0 = {}
749
+
750
+ elms[0] = this.element({parent: parent || 'root'}, component)
751
+ elementConfig0['w'] = 100
752
+ elementConfig0['h'] = 100
753
+ elementConfig0['color'] = { top: component.colorT, bottom: component.colorB, left: component.colorL }
754
+ elms[0].populate(elementConfig0)
755
+
756
+ return elms
757
+ }
758
+ `
759
+
760
+ const actual = generator.call(scope, templateObject)
761
+
762
+ assert.equal(
763
+ normalize(actual.render.toString()),
764
+ normalize(expectedRender),
765
+ 'Generator should return a render function with the correct code'
766
+ )
767
+ assert.ok(
768
+ Array.isArray(actual.effects) && actual.effects.length === 0,
769
+ 'Generator should return an empty effects array'
770
+ )
771
+
772
+ assert.end()
773
+ })
774
+
775
+ test('Generate code for a template with attribute (object) with mixed dynamic & static value', (assert) => {
776
+ const templateObject = {
777
+ children: [
778
+ {
779
+ [Symbol.for('componentType')]: 'Element',
780
+ w: '100',
781
+ h: '100',
782
+ color: '{top: 0xff0000ff, bottom: $colorB, left: $colorL}',
783
+ },
784
+ ],
785
+ }
786
+
787
+ const expectedRender = `
788
+ function anonymous(parent,component,context,components,effect,getRaw) {
789
+ const elms = []
790
+ let componentType
791
+ const rootComponent = component
792
+ const elementConfig0 = {}
793
+
794
+ elms[0] = this.element({parent: parent || 'root'}, component)
795
+ elementConfig0['w'] = 100
796
+ elementConfig0['h'] = 100
797
+ elementConfig0['color'] = { top: 0xff0000ff, bottom: component.colorB, left: component.colorL }
798
+ elms[0].populate(elementConfig0)
799
+
800
+ return elms
801
+ }
802
+ `
803
+
804
+ const actual = generator.call(scope, templateObject)
805
+
806
+ assert.equal(
807
+ normalize(actual.render.toString()),
808
+ normalize(expectedRender),
809
+ 'Generator should return a render function with the correct code'
810
+ )
811
+ assert.ok(
812
+ Array.isArray(actual.effects) && actual.effects.length === 0,
813
+ 'Generator should return an empty effects array'
814
+ )
815
+
816
+ assert.end()
817
+ })
818
+
687
819
  test('Generate code for a template with @-listeners', (assert) => {
688
820
  const templateObject = {
689
821
  children: [
@@ -2290,3 +2422,55 @@ test('Generate code for a template with a simple for-loop on an Element with an
2290
2422
 
2291
2423
  assert.end()
2292
2424
  })
2425
+
2426
+ test('Generate code for a template with double $$ (i.e. referencing a Blits plugin)', (assert) => {
2427
+ const templateObject = {
2428
+ children: [
2429
+ {
2430
+ [Symbol.for('componentType')]: 'Text',
2431
+ ':content': "$$language.translate('hello')",
2432
+ },
2433
+ ],
2434
+ }
2435
+
2436
+ const expectedRender = `
2437
+ function anonymous(parent, component, context, components, effect, getRaw) {
2438
+ const elms = []
2439
+ let componentType
2440
+ const rootComponent = component
2441
+ const elementConfig0 = {}
2442
+
2443
+ elms[0] = this.element({ parent: parent || 'root' }, component)
2444
+ elementConfig0['content'] = component.$language.translate('hello')
2445
+ elementConfig0['__textnode'] = true
2446
+ elms[0].populate(elementConfig0)
2447
+
2448
+ return elms
2449
+ }
2450
+ `
2451
+
2452
+ const expectedEffect1 = `
2453
+ function anonymous(component, elms, context, components, rootComponent, effect) {
2454
+ elms[0].set('content', component.$language.translate('hello'))
2455
+ }
2456
+ `
2457
+
2458
+ const actual = generator.call(scope, templateObject)
2459
+
2460
+ assert.equal(
2461
+ normalize(actual.render.toString()),
2462
+ normalize(expectedRender),
2463
+ 'Generator should return a render function with the correct code'
2464
+ )
2465
+ assert.ok(
2466
+ Array.isArray(actual.effects) && actual.effects.length === 1,
2467
+ 'Generator should return an effects array with 1 item'
2468
+ )
2469
+ assert.equal(
2470
+ normalize(actual.effects[0].toString()),
2471
+ normalize(expectedEffect1),
2472
+ 'Generator should return first render function with the correct code'
2473
+ )
2474
+
2475
+ assert.end()
2476
+ })
@@ -39,17 +39,16 @@ export default {
39
39
  normalize: (color = '', defaultColor = '0xffffffff') => {
40
40
  color = color.toString()
41
41
 
42
- // its mappable, map it
43
- if (colorsMap[color] !== undefined) {
44
- return colorsMap[color]
45
- }
46
-
47
- // its a 0xRRGGBBAA color, store it and return it
42
+ // it is a 0xRRGGBBAA color, return it
48
43
  if (color.startsWith('0x') && color.length === 10) {
49
- colorsMap[color] = color
50
44
  return color
51
45
  }
52
46
 
47
+ // it is a previously mapped color, return it
48
+ if (colorsMap[color] !== undefined) {
49
+ return colorsMap[color]
50
+ }
51
+
53
52
  // check for hex color
54
53
  if (hex.test(color)) {
55
54
  color = color.replace('#', '').toLowerCase()
@@ -30,11 +30,9 @@ export const getRaw = (value) => {
30
30
  const reactiveProxy = (original, _parent = null, _key) => {
31
31
  // don't create a proxy when a Blits component or an Image Texture
32
32
  // is assigned to a state variable
33
- if (
34
- (typeof original === 'object' && original[symbols.id]) ||
35
- original.constructor.name === '_ImageTexture'
36
- ) {
37
- return original
33
+ if (typeof original === 'object') {
34
+ if (original[symbols.id] !== undefined) return original
35
+ if (original.constructor.name === '_ImageTexture') return original
38
36
  }
39
37
 
40
38
  // if original object is already a proxy, don't create a new one but return the existing one instead
@@ -14,6 +14,7 @@ export default {
14
14
  level: Symbol('level'),
15
15
  methodKeys: Symbol('methodKeys'),
16
16
  originalState: Symbol('originalState'),
17
+ pluginsRegistered: Symbol('pluginsRegistered'),
17
18
  propKeys: Symbol('propKeys'),
18
19
  raw: Symbol('raw'),
19
20
  ready: Symbol('ready'),
@@ -28,7 +28,7 @@ export default (template = '', componentName, parentComponent, filePath = null)
28
28
  // regular expressions
29
29
  const tagStartRegex = /^<\/?([a-zA-Z0-9_\-.]+)\s*/
30
30
  const tagEndRegex = /^\s*(\/?>)\s*/
31
- const attrNameRegex = /^([A-Za-z0-9:.\-_@]+)=\s*(["'])/
31
+ const attrNameRegex = /^([A-Za-z0-9:.\-_@$]+)=\s*(["'])/
32
32
  const emptyTagStartRegex = /^<>\s*/
33
33
  const emptyTagEndRegex = /^\s*(<\/>)\s*/
34
34
 
@@ -0,0 +1,71 @@
1
+
2
+ /*
3
+ * Copyright 2024 Comcast Cable Communications Management, LLC
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ * SPDX-License-Identifier: Apache-2.0
17
+ */
18
+
19
+ declare namespace Plugin {
20
+
21
+ interface Plugin {
22
+ /**
23
+ * Name of the plugin. The plugin will be accessible on each Component's
24
+ * `this` scope under this name, prefixed with a `$` (i.e. myplugin => `this.$myplugin`)
25
+ */
26
+ name: string,
27
+ /**
28
+ * Singleton function that will be used to instantiate the plugin.
29
+ * Should do all necessary setup and ideally return an object with
30
+ * properties or methods that can be used in the App
31
+ */
32
+ plugin: () => any
33
+ }
34
+
35
+ }
36
+
37
+
38
+ /**
39
+ * Blits.Plugin()
40
+ *
41
+ * Method to register a plugin
42
+ */
43
+ declare function Plugin(
44
+ /**
45
+ * Plugin object or singleton function that will be used to instantiate the
46
+ * plugin. Should do all necessary setup and ideally return an object with
47
+ * properties or methods that can be used in the App
48
+ */
49
+ plugin: Plugin.Plugin | (() => any),
50
+ /**
51
+ * Name of the plugin or options object, to be passed into the plugin instantiation.
52
+ *
53
+ * When passing a string, the value will be used as **name** of the plugin. The plugin
54
+ * will be accessible on each Component's `this` scope under this name, prefixed with a `$`
55
+ * (i.e. myplugin => `this.$myplugin`)
56
+ *
57
+ * Passing a name is **required** when `plugin` argument is a singleton function
58
+ *
59
+ * When passing an object, the value will be considered to be an `options` object.
60
+ * The options object will be passed into the plugin instantiation method. Can
61
+ * be used to set default values
62
+ */
63
+ nameOrOptions?: string | object,
64
+ /**
65
+ * Object with options to be passed into the plugin instantiation method.
66
+ * Can be used to set default values
67
+ */
68
+ options?: object
69
+ ) : void
70
+
71
+ export default Plugin;
package/src/plugin.js ADDED
@@ -0,0 +1,23 @@
1
+ export const plugins = {}
2
+
3
+ const registerPlugin = (plugin, nameOrOptions = '', options = {}) => {
4
+ // map name and options depending on the arguments provided
5
+ let name
6
+ if (typeof nameOrOptions === 'object') {
7
+ options = nameOrOptions
8
+ name = ''
9
+ } else {
10
+ name = nameOrOptions
11
+ }
12
+
13
+ if (typeof plugin === 'function') {
14
+ if (name === '') {
15
+ throw Error('Error registering plugin: name is required for plugin')
16
+ }
17
+ plugins[name] = { plugin, options }
18
+ } else if (plugin.plugin) {
19
+ registerPlugin(plugin.plugin, plugin.name, options)
20
+ }
21
+ }
22
+
23
+ export default registerPlugin
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2023 Comcast Cable Communications Management, LLC
2
+ * Copyright 2024 Comcast Cable Communications Management, LLC
3
3
  * Licensed under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License.
5
5
  * You may obtain a copy of the License at
@@ -15,19 +15,4 @@
15
15
  * SPDX-License-Identifier: Apache-2.0
16
16
  */
17
17
 
18
- import Component from '../component.js'
19
-
20
- export default () =>
21
- Component('Image', {
22
- template: `
23
- <Element :imageSource="$imageSource" />`,
24
- props: ['src'],
25
- computed: {
26
- imageSource() {
27
- if (/^(?:https?:)?\/\//i.test(this.src)) {
28
- return this.src
29
- }
30
- return `${window.location.protocol}//${window.location.host}/${this.src}`
31
- },
32
- },
33
- })
18
+ export { default as language } from './language.js'