@shortfuse/materialdesignweb 0.7.6 → 0.8.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 (114) hide show
  1. package/README.md +57 -68
  2. package/components/Badge.js +2 -2
  3. package/components/BottomAppBar.js +3 -5
  4. package/components/Box.js +33 -3
  5. package/components/Button.js +48 -21
  6. package/components/Button.md +9 -9
  7. package/components/Card.js +9 -16
  8. package/components/Checkbox.js +45 -36
  9. package/components/CheckboxIcon.js +2 -2
  10. package/components/Chip.js +1 -1
  11. package/components/Dialog.js +228 -359
  12. package/components/DialogActions.js +2 -2
  13. package/components/Divider.js +3 -3
  14. package/components/ExtendedFab.js +4 -8
  15. package/components/Fab.js +1 -2
  16. package/components/FilterChip.js +4 -4
  17. package/components/Headline.js +1 -1
  18. package/components/Icon.js +8 -8
  19. package/components/IconButton.js +9 -14
  20. package/components/Input.js +273 -1
  21. package/components/Layout.js +485 -16
  22. package/components/List.js +6 -4
  23. package/components/ListItem.js +12 -12
  24. package/components/ListOption.js +21 -5
  25. package/components/Listbox.js +239 -0
  26. package/components/Menu.js +77 -526
  27. package/components/MenuItem.js +12 -14
  28. package/components/Nav.js +0 -2
  29. package/components/NavBar.js +8 -79
  30. package/components/NavDrawer.js +12 -11
  31. package/components/NavDrawerItem.js +2 -1
  32. package/components/NavItem.js +18 -8
  33. package/components/NavRail.js +15 -7
  34. package/components/NavRailItem.js +3 -1
  35. package/components/Popup.js +20 -0
  36. package/components/Progress.js +24 -23
  37. package/components/Radio.js +42 -35
  38. package/components/RadioIcon.js +3 -3
  39. package/components/Ripple.js +2 -3
  40. package/components/Search.js +85 -0
  41. package/components/SegmentedButton.js +1 -10
  42. package/components/SegmentedButtonGroup.js +16 -10
  43. package/components/Select.js +4 -4
  44. package/components/Shape.js +1 -1
  45. package/components/Slider.js +43 -50
  46. package/components/Snackbar.js +4 -5
  47. package/components/Surface.js +3 -3
  48. package/components/Switch.js +55 -21
  49. package/components/SwitchIcon.js +10 -8
  50. package/components/Tab.js +11 -9
  51. package/components/TabContent.js +4 -3
  52. package/components/TabList.js +2 -2
  53. package/components/TabPanel.js +11 -8
  54. package/components/TextArea.js +38 -35
  55. package/components/Tooltip.js +2 -2
  56. package/components/TopAppBar.js +65 -147
  57. package/core/Composition.js +985 -628
  58. package/core/CompositionAdapter.js +315 -0
  59. package/core/CustomElement.js +153 -90
  60. package/core/DomAdapter.js +586 -0
  61. package/core/ICustomElement.d.ts +2 -2
  62. package/core/css.js +8 -7
  63. package/core/customTypes.js +53 -31
  64. package/{utils → core}/jsonMergePatch.js +36 -14
  65. package/core/observe.js +111 -57
  66. package/core/optimizations.js +23 -0
  67. package/core/template.js +17 -11
  68. package/core/test.js +126 -0
  69. package/core/typings.d.ts +11 -5
  70. package/core/uid.js +13 -0
  71. package/dist/index.min.js +83 -152
  72. package/dist/index.min.js.map +4 -4
  73. package/dist/meta.json +1 -1
  74. package/mixins/AriaReflectorMixin.js +1 -2
  75. package/mixins/AriaToolbarMixin.js +2 -3
  76. package/mixins/ControlMixin.js +25 -17
  77. package/mixins/DensityMixin.js +0 -1
  78. package/mixins/FlexableMixin.js +1 -2
  79. package/mixins/FormAssociatedMixin.js +13 -10
  80. package/mixins/InputMixin.js +2 -9
  81. package/mixins/KeyboardNavMixin.js +14 -1
  82. package/mixins/PopupMixin.js +757 -0
  83. package/mixins/RTLObserverMixin.js +0 -1
  84. package/mixins/ResizeObserverMixin.js +0 -1
  85. package/mixins/RippleMixin.js +3 -4
  86. package/mixins/ScrollListenerMixin.js +41 -32
  87. package/mixins/SemiStickyMixin.js +151 -0
  88. package/mixins/ShapeMixin.js +29 -24
  89. package/mixins/StateMixin.js +11 -6
  90. package/mixins/SurfaceMixin.js +3 -57
  91. package/mixins/TextFieldMixin.js +57 -65
  92. package/mixins/ThemableMixin.js +78 -156
  93. package/mixins/TooltipTriggerMixin.js +7 -13
  94. package/mixins/TouchTargetMixin.js +4 -3
  95. package/package.json +9 -5
  96. package/theming/index.js +1 -1
  97. package/theming/themableMixinLoader.js +12 -0
  98. package/utils/{hct → material-color}/blend.js +8 -10
  99. package/utils/{hct → material-color/hct}/Cam16.js +196 -69
  100. package/utils/{hct → material-color/hct}/Hct.js +61 -19
  101. package/utils/{hct → material-color/hct}/ViewingConditions.js +3 -3
  102. package/utils/{hct → material-color/hct}/hctSolver.js +9 -16
  103. package/utils/{hct → material-color}/helper.js +11 -18
  104. package/utils/{hct → material-color/palettes}/CorePalette.js +79 -19
  105. package/utils/{hct → material-color/palettes}/TonalPalette.js +12 -4
  106. package/utils/material-color/scheme/Scheme.js +376 -0
  107. package/utils/{hct/colorUtils.js → material-color/utils/color.js} +61 -1
  108. package/utils/popup.js +46 -25
  109. package/components/ListSelect.js +0 -220
  110. package/components/Option.js +0 -91
  111. package/components/Pane.js +0 -281
  112. package/core/identify.js +0 -40
  113. package/utils/hct/Scheme.js +0 -587
  114. /package/utils/{hct/mathUtils.js → material-color/utils/math.js} +0 -0
@@ -3,6 +3,7 @@
3
3
  import Composition from './Composition.js';
4
4
  import { ICustomElement } from './ICustomElement.js';
5
5
  import { attrNameFromPropName, attrValueFromDataValue } from './dom.js';
6
+ import { applyMergePatch } from './jsonMergePatch.js';
6
7
  import { defineObservableProperty } from './observe.js';
7
8
  import { addInlineFunction, css, html } from './template.js';
8
9
 
@@ -175,14 +176,12 @@ export default class CustomElement extends ICustomElement {
175
176
  * @type {typeof ICustomElement['autoRegister']}
176
177
  */
177
178
  static autoRegister(elementName) {
178
- if (elementName) {
179
- this.elementName = elementName;
179
+ if (this.hasOwnProperty('defined') && this.defined) {
180
+ console.warn(this.elementName, 'already registered.');
181
+ // @ts-expect-error Can't cast T
182
+ return this;
180
183
  }
181
- queueMicrotask(() => {
182
- if (this.autoRegistration) {
183
- this.register();
184
- }
185
- });
184
+ this.register(elementName);
186
185
  // @ts-expect-error Can't cast T
187
186
  return this;
188
187
  }
@@ -214,9 +213,7 @@ export default class CustomElement extends ICustomElement {
214
213
  }
215
214
 
216
215
  /**
217
- * Extends base class into a new class.
218
- * Use to avoid mutating base class.
219
- * TODO: Add constructor arguments typing
216
+ * Fix for Typescript not parsing constructor params
220
217
  * @type {typeof ICustomElement.tsClassFix}
221
218
  */
222
219
  static tsClassFix() {
@@ -250,8 +247,8 @@ export default class CustomElement extends ICustomElement {
250
247
  static set(source, options) {
251
248
  Object.defineProperties(
252
249
  this.prototype,
253
- Object.fromEntries(
254
- Object.entries(source).map(([name, value]) => {
250
+ Object.fromEntries([
251
+ ...Object.entries(source).map(([name, value]) => {
255
252
  // Tap into .map() to avoid double iteration
256
253
  // Property may be redefined observable
257
254
  this.undefine(name);
@@ -266,7 +263,17 @@ export default class CustomElement extends ICustomElement {
266
263
  },
267
264
  ];
268
265
  }),
269
- ),
266
+ ...Object.getOwnPropertySymbols(source).map((symbol) => [
267
+ symbol,
268
+ {
269
+ enumerable: false,
270
+ configurable: true,
271
+ value: source[symbol],
272
+ writable: true,
273
+ ...options,
274
+ },
275
+ ]),
276
+ ]),
270
277
  );
271
278
  // @ts-expect-error Can't cast T
272
279
  return this;
@@ -284,13 +291,7 @@ export default class CustomElement extends ICustomElement {
284
291
  * Registers class with window.customElements synchronously
285
292
  * @type {typeof ICustomElement['register']}
286
293
  */
287
- static register(elementName, force = false) {
288
- if (this.hasOwnProperty('defined') && this.defined && !force) {
289
- console.warn(this.elementName, 'already registered.');
290
- // @ts-expect-error Can't cast T
291
- return this;
292
- }
293
-
294
+ static register(elementName) {
294
295
  if (elementName) {
295
296
  this.elementName = elementName;
296
297
  }
@@ -414,10 +415,10 @@ export default class CustomElement extends ICustomElement {
414
415
 
415
416
  static undefine(name) {
416
417
  Reflect.deleteProperty(this.prototype, name);
417
- const config = this.propList.get(name);
418
- if (config && config.watchers.length) {
419
- const propWatchers = this.propChangedCallbacks.get(name);
420
- if (propWatchers) {
418
+ if (this.propList.has(name)) {
419
+ const config = this.propList.get(name);
420
+ if (config.watchers.length && this.propChangedCallbacks.has(name)) {
421
+ const propWatchers = this.propChangedCallbacks.get(name);
421
422
  for (const watcher of config.watchers) {
422
423
  const index = propWatchers.indexOf(watcher);
423
424
  if (index !== -1) {
@@ -473,6 +474,20 @@ export default class CustomElement extends ICustomElement {
473
474
  composed({ composition }) {
474
475
  for (const [key, listenerOptions] of Object.entries(listeners)) {
475
476
  const [, flags, type] = key.match(EVENT_PREFIX_REGEX);
477
+ // TODO: Make abstract
478
+ let prop;
479
+ /** @type {string[]} */
480
+ let deepProp = [];
481
+ if (typeof listenerOptions === 'string') {
482
+ const parsedProps = listenerOptions.split('.');
483
+ if (parsedProps.length === 1) {
484
+ prop = listenerOptions;
485
+ deepProp = [];
486
+ } else {
487
+ prop = parsedProps[0];
488
+ deepProp = parsedProps;
489
+ }
490
+ }
476
491
  composition.addCompositionEventListener({
477
492
  type,
478
493
  once: flags?.includes('1'),
@@ -482,7 +497,7 @@ export default class CustomElement extends ICustomElement {
482
497
  typeof listenerOptions === 'function'
483
498
  ? { handleEvent: listenerOptions }
484
499
  : (typeof listenerOptions === 'string'
485
- ? { prop: listenerOptions }
500
+ ? { prop, deepProp }
486
501
  : listenerOptions)
487
502
  ),
488
503
  ...(
@@ -500,9 +515,10 @@ export default class CustomElement extends ICustomElement {
500
515
 
501
516
  /** @type {typeof ICustomElement.childEvents} */
502
517
  static childEvents(listenerMap, options) {
503
- for (const [id, listeners] of Object.entries(listenerMap)) {
518
+ for (const [tag, listeners] of Object.entries(listenerMap)) {
519
+ // @ts-expect-error Can't cast T
504
520
  this.events(listeners, {
505
- id,
521
+ tag: attrNameFromPropName(tag),
506
522
  ...options,
507
523
  });
508
524
  }
@@ -511,6 +527,15 @@ export default class CustomElement extends ICustomElement {
511
527
  return this;
512
528
  }
513
529
 
530
+ /** @type {typeof ICustomElement.events} */
531
+ static rootEvents(listeners, options) {
532
+ // @ts-expect-error Can't cast T
533
+ return this.events(listeners, {
534
+ tag: Composition.shadowRootTag,
535
+ ...options,
536
+ });
537
+ }
538
+
514
539
  /** @type {typeof ICustomElement['on']} */
515
540
  static on(nameOrCallbacks, callback) {
516
541
  const callbacks = typeof nameOrCallbacks === 'string'
@@ -548,12 +573,11 @@ export default class CustomElement extends ICustomElement {
548
573
  /** @type {typeof ICustomElement['onPropChanged']} */
549
574
  static onPropChanged(options) {
550
575
  for (const [prop, callback] of Object.entries(options)) {
551
- let array = this.propChangedCallbacks.get(prop);
552
- if (!array) {
553
- array = [];
554
- this.propChangedCallbacks.set(prop, array);
576
+ if (this.propChangedCallbacks.has(prop)) {
577
+ this.propChangedCallbacks.get(prop).push(callback);
578
+ } else {
579
+ this.propChangedCallbacks.set(prop, [callback]);
555
580
  }
556
- array.push(callback);
557
581
  }
558
582
 
559
583
  // @ts-expect-error Can't cast T
@@ -564,12 +588,11 @@ export default class CustomElement extends ICustomElement {
564
588
  static onAttributeChanged(options) {
565
589
  for (const [name, callback] of Object.entries(options)) {
566
590
  const lcName = name.toLowerCase();
567
- let array = this.attributeChangedCallbacks.get(lcName);
568
- if (!array) {
569
- array = [];
570
- this.attributeChangedCallbacks.set(lcName, array);
591
+ if (this.attributeChangedCallbacks.has(lcName)) {
592
+ this.attributeChangedCallbacks.get(lcName).push(callback);
593
+ } else {
594
+ this.attributeChangedCallbacks.set(lcName, [callback]);
571
595
  }
572
- array.push(callback);
573
596
  }
574
597
 
575
598
  // @ts-expect-error Can't cast T
@@ -588,7 +611,7 @@ export default class CustomElement extends ICustomElement {
588
611
  /** @type {Composition<?>} */
589
612
  #composition;
590
613
 
591
- /** @type {Map<string,null|[string,any]>} */
614
+ /** @type {Map<string,{stringValue:string, parsedValue:any}>} */
592
615
  _propAttributeCache;
593
616
 
594
617
  /** @type {import('./ICustomElement.js').CallbackArguments} */
@@ -604,33 +627,38 @@ export default class CustomElement extends ICustomElement {
604
627
 
605
628
  this.attachShadow({ mode: 'open', delegatesFocus: this.delegatesFocus });
606
629
 
607
- this.composition.initialRender(this.shadowRoot, this);
630
+ /**
631
+ * Updates nodes based on data
632
+ * Expects data in JSON Merge Patch format
633
+ * @see https://www.rfc-editor.org/rfc/rfc7386
634
+ * @param {Partial<?>} changes
635
+ * @param {any} data
636
+ * @return {void}
637
+ */
638
+ this.render = this.composition.render(
639
+ this,
640
+ this,
641
+ {
642
+ store: this,
643
+ target: this.shadowRoot,
644
+ context: this,
645
+ },
646
+ );
608
647
 
609
648
  for (const callback of this.static._onConstructedCallbacks) {
610
649
  callback.call(this, this.callbackArguments);
611
650
  }
612
651
  }
613
652
 
614
- /**
615
- * Updates nodes based on data
616
- * Expects data in JSON Merge Patch format
617
- * @see https://www.rfc-editor.org/rfc/rfc7386
618
- * @param {?} data
619
- * @param {?} [store]
620
- * @return {void}
621
- */
622
- render(data, store) {
623
- // console.log('render', data);
624
- this.composition.render(this.shadowRoot, data, this, store ? { ...this, store } : this);
625
- }
626
-
627
653
  /** @type {InstanceType<typeof ICustomElement>['propChangedCallback']} */
628
654
  propChangedCallback(name, oldValue, newValue, changes = newValue) {
629
- this.render({ [name]: changes });
655
+ if (!this.patching) {
656
+ this.render.byProp(name, changes, this);
657
+ // this.render({ [name]: changes });
658
+ }
630
659
 
631
- const callbacks = this.static.propChangedCallbacks.get(name);
632
- if (callbacks) {
633
- for (const callback of callbacks) {
660
+ if (this.static._propChangedCallbacks.has(name)) {
661
+ for (const callback of this.static.propChangedCallbacks.get(name)) {
634
662
  callback.call(this, oldValue, newValue, changes, this);
635
663
  }
636
664
  }
@@ -642,9 +670,9 @@ export default class CustomElement extends ICustomElement {
642
670
  * @param {string|null} newValue
643
671
  */
644
672
  attributeChangedCallback(name, oldValue, newValue) {
645
- const callbacks = this.static.attributeChangedCallbacks.get(name.toLowerCase());
646
- if (callbacks) {
647
- for (const callback of callbacks) {
673
+ const lcName = name.toLowerCase();
674
+ if (this.static.attributeChangedCallbacks.has(lcName)) {
675
+ for (const callback of this.static.attributeChangedCallbacks.get(lcName)) {
648
676
  callback.call(this, oldValue, newValue, this);
649
677
  }
650
678
  }
@@ -660,10 +688,10 @@ export default class CustomElement extends ICustomElement {
660
688
  return;
661
689
  }
662
690
 
663
- const [stringValue] = this.attributeCache.get(name) ?? [null, null];
664
- if (stringValue === newValue) {
665
- // Attribute was changed via data change event. Ignore.
666
- return;
691
+ let cacheEntry;
692
+ if (this.attributeCache.has(lcName)) {
693
+ cacheEntry = this.attributeCache.get(lcName);
694
+ if (cacheEntry.stringValue === newValue) return;
667
695
  }
668
696
 
669
697
  // @ts-expect-error any
@@ -679,7 +707,14 @@ export default class CustomElement extends ICustomElement {
679
707
  }
680
708
  // "Remember" that this attrValue equates to this data value
681
709
  // Avoids rewriting attribute later on data change event
682
- this.attributeCache.set(name, [newValue, parsedValue]);
710
+ if (cacheEntry) {
711
+ cacheEntry.stringValue = newValue;
712
+ cacheEntry.parsedValue = parsedValue;
713
+ } else {
714
+ this.attributeCache.set(lcName, {
715
+ stringValue: newValue, parsedValue,
716
+ });
717
+ }
683
718
  // @ts-expect-error any
684
719
  this[config.key] = parsedValue;
685
720
  return;
@@ -697,19 +732,32 @@ export default class CustomElement extends ICustomElement {
697
732
  * @param {any} changes
698
733
  */
699
734
  _onObserverPropertyChanged(name, oldValue, newValue, changes) {
700
- const { reflect, attr } = this.static.propList.get(name);
701
- if (attr && (reflect === true || reflect === 'write')) {
702
- const [, dataValue] = this.attributeCache.get(attr) ?? [null, null];
703
- // Don't change attribute if data value is equivalent
704
- // (eg: Boolean('foo') === true; Number("1.0") === 1)
705
- if (dataValue !== newValue) {
706
- const attrValue = attrValueFromDataValue(newValue);
707
- // Cache attrValue to ignore attributeChangedCallback later
708
- this.attributeCache.set(attr, [attrValue, newValue]);
709
- if (attrValue == null) {
710
- this.removeAttribute(attr);
735
+ if (this.static.propList.has(name)) {
736
+ const { reflect, attr } = this.static.propList.get(name);
737
+ if (attr && (reflect === true || reflect === 'write')) {
738
+ const lcName = attr.toLowerCase();
739
+ /** @type {{stringValue:string, parsedValue:any}} */
740
+ let cacheEntry;
741
+ let needsWrite = false;
742
+ if (this.attributeCache.has(lcName)) {
743
+ cacheEntry = this.attributeCache.get(lcName);
744
+ needsWrite = (cacheEntry.parsedValue !== newValue);
711
745
  } else {
712
- this.setAttribute(attr, attrValue);
746
+ // @ts-ignore skip cast
747
+ cacheEntry = {};
748
+ this.attributeCache.set(lcName, cacheEntry);
749
+ needsWrite = true;
750
+ }
751
+ if (needsWrite) {
752
+ const stringValue = attrValueFromDataValue(newValue);
753
+ cacheEntry.parsedValue = newValue;
754
+ cacheEntry.stringValue = stringValue;
755
+ // Cache attrValue to ignore attributeChangedCallback later
756
+ if (stringValue == null) {
757
+ this.removeAttribute(attr);
758
+ } else {
759
+ this.setAttribute(attr, stringValue);
760
+ }
713
761
  }
714
762
  }
715
763
  }
@@ -718,8 +766,15 @@ export default class CustomElement extends ICustomElement {
718
766
  this.propChangedCallback(name, oldValue, newValue, changes);
719
767
  }
720
768
 
769
+ patch(patch) {
770
+ this.patching = true;
771
+ applyMergePatch(this, patch);
772
+ this.render(patch);
773
+ this.patching = false;
774
+ }
775
+
721
776
  /**
722
- * Proxy object that returns shadow DOM elements by ID.
777
+ * Proxy object that returns shadow DOM elements by tag.
723
778
  * If called before interpolation (eg: on composed), returns from template
724
779
  * @return {Record<string,HTMLElement>}
725
780
  */
@@ -728,32 +783,40 @@ export default class CustomElement extends ICustomElement {
728
783
  return (this.#refsProxy ??= new Proxy({}, {
729
784
  /**
730
785
  * @param {any} target
731
- * @param {string} id
786
+ * @param {string} tag
732
787
  * @return {Element}
733
788
  */
734
- get: (target, id) => {
789
+ get: (target, tag) => {
735
790
  if (!this.#composition) {
736
791
  console.warn(this.static.name, 'Attempted to access references before composing!');
737
792
  }
738
793
  const composition = this.composition;
794
+ let element;
739
795
  if (!composition.interpolated) {
740
- let element = this.#refsCompositionCache.get(id)?.deref();
741
- if (element) return element;
742
- const formattedId = attrNameFromPropName(id);
796
+ if (this.#refsCompositionCache.has(tag)) {
797
+ element = this.#refsCompositionCache.get(tag).deref();
798
+ if (element) return element;
799
+ }
800
+ const formattedTag = attrNameFromPropName(tag);
743
801
  // console.warn(this.tagName, 'Returning template reference');
744
- element = composition.template.getElementById(formattedId);
802
+ element = composition.template.getElementById(formattedTag);
745
803
  if (!element) return null;
746
- this.#refsCompositionCache.set(id, new WeakRef(element));
804
+ this.#refsCompositionCache.set(tag, new WeakRef(element));
747
805
  return element;
748
806
  }
749
- let element = this.#refsCache.get(id)?.deref();
750
- if (element) {
751
- return element;
807
+ if (this.#refsCache.has(tag)) {
808
+ element = this.#refsCache.get(tag).deref();
809
+ if (element) {
810
+ return element;
811
+ }
752
812
  }
753
- const formattedId = attrNameFromPropName(id);
754
- element = composition.getElement(this.shadowRoot, formattedId);
813
+
814
+ const formattedTag = attrNameFromPropName(tag);
815
+ const tagIndex = this.composition.tags.indexOf(formattedTag);
816
+ element = this.render.state.refs[tagIndex];
817
+
755
818
  if (!element) return null;
756
- this.#refsCache.set(id, new WeakRef(element));
819
+ this.#refsCache.set(tag, new WeakRef(element));
757
820
  return element;
758
821
  },
759
822
  }));