@shgysk8zer0/polyfills 0.3.1 → 0.3.3

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.
package/array.js CHANGED
@@ -262,6 +262,19 @@ if (! (Array.prototype.with instanceof Function)) {
262
262
  };
263
263
  }
264
264
 
265
+ if (! (Array.isTemplateObject instanceof Function)) {
266
+ Array.isTemplateObject = function(target) {
267
+ if (! (
268
+ Array.isArray(target) && Array.isArray(target.raw)
269
+ && Object.isFrozen(target) && Object.isFrozen(target.raw)
270
+ )) {
271
+ return false;
272
+ } else {
273
+ return target.length !== 0 && target.length === target.raw.length;
274
+ }
275
+ };
276
+ }
277
+
265
278
  /**
266
279
  * @see https://github.com/tc39/proposal-arraybuffer-base64
267
280
  */
File without changes
package/element.js CHANGED
@@ -1,7 +1,123 @@
1
1
  import { aria } from './aom.js';
2
- import { overwriteMethod, polyfillGetterSetter } from './utils.js';
3
- import { SanitizerConfig as defaultConfig } from './assets/SanitizerConfigW3C.js';
4
- import { setHTML as safeSetHTML, convertToSanitizerConfig } from './assets/sanitizerUtils.js';
2
+ import { polyfillGetterSetter } from './utils.js';
3
+ import './sanitizer.js';
4
+
5
+ function handlePopover({ currentTarget }) {
6
+ switch(currentTarget.popoverTargetAction) {
7
+ case 'show':
8
+ currentTarget.popoverTargetElement.showPopover();
9
+ break;
10
+
11
+ case 'hide':
12
+ currentTarget.popoverTargetElement.hidePopover();
13
+ break;
14
+
15
+ default:
16
+ currentTarget.popoverTargetElement.togglePopover();
17
+ }
18
+ }
19
+
20
+ export function initPopover(target = document.body) {
21
+ target.querySelectorAll('button[popovertarget], input[type="button"][popovertarget]')
22
+ .forEach(el => el.addEventListener('click', handlePopover));
23
+ }
24
+
25
+ if ((globalThis.ToggleEvent instanceof Function)) {
26
+ class ToggleEvent extends Event {
27
+ #newState;
28
+ #oldState;
29
+
30
+ constructor(type, { newState, oldState }) {
31
+ super(type, { bubbles: true });
32
+ this.#newState = newState;
33
+ this.#oldState = oldState;
34
+ }
35
+
36
+ get newState() {
37
+ return this.#newState;
38
+ }
39
+
40
+ get oldState() {
41
+ return this.#oldState;
42
+ }
43
+ }
44
+
45
+ globalThis.ToggleEvent = ToggleEvent;
46
+ }
47
+
48
+ if (! (HTMLElement.prototype.showPopover instanceof Function)) {
49
+ const isPopoverOpen = el => el.classList.contains('_popover-open');
50
+
51
+ Object.defineProperties(HTMLElement.prototype, {
52
+ showPopover: {
53
+ value: function showPopover() {
54
+ if (! isPopoverOpen(this)) {
55
+ this.dispatchEvent(new ToggleEvent('beforetoggle', { oldState: 'closed', newState: 'open' }));
56
+
57
+ if (this.getAttribute('popover') === 'auto') {
58
+ const controller = new AbortController();
59
+
60
+ document.body.addEventListener('click', ({ target }) => {
61
+ if (! this.contains(target) && ! this.isSameNode(target.popoverTargetElement)) {
62
+ controller.abort();
63
+ this.hidePopover();
64
+ }
65
+ }, { signal: controller.signal, capture: true });
66
+
67
+ document.body.addEventListener('keydown', ({ key }) => {
68
+ if (key === 'Escape') {
69
+ controller.abort();
70
+ this.hidePopover();
71
+ }
72
+ }, { signal: controller.signal, capture: true });
73
+
74
+ document.addEventListener('beforetoggle', ({ target }) => {
75
+ if (! target.isSameNode(this) && target.getAttribute('popover') === 'auto') {
76
+ controller.abort();
77
+ this.hidePopover();
78
+ }
79
+ }, { signal: controller.signal });
80
+ }
81
+
82
+ this.classList.add('_popover-open');
83
+ this.dispatchEvent(new ToggleEvent('toggle', { oldState: 'closed', newState: 'open' }));
84
+ }
85
+ }
86
+ },
87
+ hidePopover: {
88
+ value: function hidePopover() {
89
+ if (isPopoverOpen(this)) {
90
+ this.dispatchEvent(new ToggleEvent('beforetoggle', { oldState: 'open', newState: 'closed' }));
91
+ queueMicrotask(() => this.classList.remove('_popover-open'));
92
+ this.dispatchEvent(new ToggleEvent('toggle', { oldState: 'open', newState: 'closed' }));
93
+ }
94
+ }
95
+ },
96
+ togglePopover: {
97
+ value: function togglePopover() {
98
+ isPopoverOpen(this) ? this.hidePopover() : this.showPopover();
99
+ }
100
+ }
101
+ });
102
+
103
+ Object.defineProperties(HTMLButtonElement.prototype, {
104
+ popoverTargetElement: {
105
+ get() {
106
+ return document.getElementById(this.getAttribute('popovertarget'));
107
+ }
108
+ },
109
+ popoverTargetAction: {
110
+ get() {
111
+ return this.getAttribute('popovertargetaction') || 'toggle';
112
+ },
113
+ set(val) {
114
+ this.setAttribute('popovertargetaction', val);
115
+ }
116
+ }
117
+ });
118
+
119
+ initPopover();
120
+ }
5
121
 
6
122
  if (! (HTMLScriptElement.supports instanceof Function)) {
7
123
  HTMLScriptElement.supports = function supports(type) {
@@ -126,23 +242,6 @@ if (! (HTMLImageElement.prototype.decode instanceof Function)) {
126
242
  };
127
243
  }
128
244
 
129
- if (! (Element.prototype.setHTML instanceof Function)) {
130
- Element.prototype.setHTML = function setHTML(input, opts = defaultConfig) {
131
- safeSetHTML(this, input, opts);
132
- };
133
- } else {
134
- overwriteMethod(Element.prototype, 'setHTML', function(orig) {
135
- return function setHTML(input, opts = {}) {
136
- if (! (opts.sanitizer instanceof Sanitizer)) {
137
- const sanitizer = new Sanitizer(convertToSanitizerConfig(opts));
138
- orig.call(this, input, { sanitizer });
139
- } else {
140
- orig.call(this, input, opts);
141
- }
142
- };
143
- });
144
- }
145
-
146
245
  if (! HTMLTemplateElement.prototype.hasOwnProperty('shadowRootMode')) {
147
246
  Object.defineProperty(HTMLTemplateElement.prototype, 'shadowRootMode', {
148
247
  get: function() {
package/iterator.js CHANGED
@@ -287,6 +287,45 @@ if (! (IteratorPrototype.indexed instanceof Function)) {
287
287
  };
288
288
  }
289
289
 
290
+ if (! (IteratorPrototype.chunks instanceof Function)) {
291
+ IteratorPrototype.chunks = function(size) {
292
+ if (! Number.isSafeInteger(size) || size < 1) {
293
+ throw new TypeError('Size must be a positive integer.');
294
+ } else {
295
+ const iter = this;
296
+ let done = false;
297
+
298
+ return Iterator.from({
299
+ next() {
300
+ if (done) {
301
+ return { done };
302
+ } else {
303
+ const items = [];
304
+ let i = 0;
305
+
306
+ while(i++ < size && ! done) {
307
+ const next = iter.next();
308
+
309
+ if (next.done) {
310
+ done = true;
311
+
312
+ if (typeof next.value !== 'undefined') {
313
+ items.push(next.value);
314
+ }
315
+ break;
316
+ } else {
317
+ items.push(next.value);
318
+ }
319
+ }
320
+
321
+ return { value: items, done: false };
322
+ }
323
+ }
324
+ });
325
+ }
326
+ };
327
+ }
328
+
290
329
  if (! (Iterator.from instanceof Function)) {
291
330
  Iterator.from = function from(obj) {
292
331
  if (typeof obj !== 'object' || obj === null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgysk8zer0/polyfills",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "A collection of JavaScript polyfills",
@@ -38,6 +38,7 @@
38
38
  "fix:js": "eslint . --fix",
39
39
  "lint:js": "eslint .",
40
40
  "lint:html": "htmlhint \"**/*.html\"",
41
+ "build": "npm run build:js",
41
42
  "build:js": "rollup -c rollup.config.js",
42
43
  "create:lock": "npm i --package-lock-only --ignore-scripts --no-audit --no-fund",
43
44
  "version:bump": "npm run version:bump:patch",
@@ -70,8 +71,12 @@
70
71
  },
71
72
  "homepage": "https://github.com/shgysk8zer0/polyfills#readme",
72
73
  "devDependencies": {
74
+ "@rollup/plugin-node-resolve": "^15.2.3",
73
75
  "@shgysk8zer0/js-utils": "^1.0.1",
74
76
  "htmlhint": "^1.1.4",
75
77
  "http-server": "^14.1.1"
78
+ },
79
+ "dependencies": {
80
+ "@aegisjsproject/sanitizer": "^0.0.2"
76
81
  }
77
82
  }
package/popover.css ADDED
@@ -0,0 +1,25 @@
1
+ @supports not selector(:popover-open) {
2
+ :is([popover]:not(._popover-open)) {
3
+ display: none;
4
+ }
5
+
6
+ :is([popover]._popover-open) {
7
+ position: fixed;
8
+ z-index: 2147483647;
9
+ margin: auto;
10
+ inset: 0;
11
+ border: 3px solid currentColor;
12
+ height: fit-content;
13
+ width: fit-content;
14
+ padding: 0.25em;
15
+ background-color: #ffffff;
16
+ color: #070707;
17
+ }
18
+
19
+ @media (prefers-color-scheme: dark) {
20
+ :is([popover]._popover-open) {
21
+ background-color: #1c1b22;
22
+ color: #fbfbfe;
23
+ }
24
+ }
25
+ }
package/popover.js ADDED
@@ -0,0 +1,118 @@
1
+ // function handlePopover({ currentTarget }) {
2
+ // currentTarget.addEventListener('click', ({ currentTarget }) => {
3
+ // switch(currentTarget.popoverTargetAction) {
4
+ // case 'show':
5
+ // currentTarget.popoverTargetElement.showPopover();
6
+ // break;
7
+
8
+ // case 'hide':
9
+ // currentTarget.popoverTargetElement.hidePopover();
10
+ // break;
11
+
12
+ // default:
13
+ // currentTarget.popoverTargetElement.togglePopover();
14
+ // }
15
+ // }, { capture: true });
16
+ // }
17
+
18
+ // export function initPopover(target = document.body) {
19
+ // target.querySelectorAll('button[popovertarget], input[type="button"][popovertarget]')
20
+ // .forEach(el => el.addEventListener('click', handlePopover));
21
+ // }
22
+
23
+ // if ((globalThis.ToggleEvent instanceof Function)) {
24
+ // class ToggleEvent extends Event {
25
+ // #newState;
26
+ // #oldState;
27
+
28
+ // constructor(type, { newState, oldState }) {
29
+ // super(type, { bubbles: true });
30
+ // this.#newState = newState;
31
+ // this.#oldState = oldState;
32
+ // }
33
+
34
+ // get newState() {
35
+ // return this.#newState;
36
+ // }
37
+
38
+ // get oldState() {
39
+ // return this.#oldState;
40
+ // }
41
+ // }
42
+
43
+ // globalThis.ToggleEvent = ToggleEvent;
44
+ // }
45
+
46
+ // if (! (HTMLElement.prototype.showPopover instanceof Function)) {
47
+ // const isPopoverOpen = el => el.classList.contains('_popover-open');
48
+
49
+ // Object.defineProperties(HTMLElement.prototype, {
50
+ // showPopover: {
51
+ // value: function showPopover() {
52
+ // if (! isPopoverOpen(this)) {
53
+ // this.dispatchEvent(new ToggleEvent('beforetoggle', { oldState: 'closed', newState: 'open' }));
54
+
55
+ // if (this.getAttribute('popover') === 'auto') {
56
+ // const controller = new AbortController();
57
+
58
+ // document.body.addEventListener('click', ({ target }) => {
59
+ // if (! this.contains(target) && ! this.isSameNode(target.popoverTargetElement)) {
60
+ // controller.abort();
61
+ // this.hidePopover();
62
+ // }
63
+ // }, { signal: controller.signal, capture: true });
64
+
65
+ // document.body.addEventListener('keydown', ({ key }) => {
66
+ // if (key === 'Escape') {
67
+ // controller.abort();
68
+ // this.hidePopover();
69
+ // }
70
+ // }, { signal: controller.signal, capture: true });
71
+
72
+ // document.addEventListener('beforetoggle', ({ target }) => {
73
+ // if (! target.isSameNode(this) && target.getAttribute('popover') === 'auto') {
74
+ // controller.abort();
75
+ // this.hidePopover();
76
+ // }
77
+ // }, { signal: controller.signal });
78
+ // }
79
+
80
+ // this.classList.add('_popover-open');
81
+ // this.dispatchEvent(new ToggleEvent('toggle', { oldState: 'closed', newState: 'open' }));
82
+ // }
83
+ // }
84
+ // },
85
+ // hidePopover: {
86
+ // value: function hidePopover() {
87
+ // if (isPopoverOpen(this)) {
88
+ // this.dispatchEvent(new ToggleEvent('beforetoggle', { oldState: 'open', newState: 'closed' }));
89
+ // queueMicrotask(() => this.classList.remove('_popover-open'));
90
+ // this.dispatchEvent(new ToggleEvent('toggle', { oldState: 'open', newState: 'closed' }));
91
+ // }
92
+ // }
93
+ // },
94
+ // togglePopover: {
95
+ // value: function togglePopover() {
96
+ // isPopoverOpen(this) ? this.hidePopover() : this.showPopover();
97
+ // }
98
+ // }
99
+ // });
100
+
101
+ // Object.defineProperties(HTMLButtonElement.prototype, {
102
+ // popoverTargetElement: {
103
+ // get() {
104
+ // return document.getElementById(this.getAttribute('popovertarget'));
105
+ // }
106
+ // },
107
+ // popoverTargetAction: {
108
+ // get() {
109
+ // return this.getAttribute('popovertargetaction') || 'toggle';
110
+ // },
111
+ // set(val) {
112
+ // this.setAttribute('popovertargetaction', val);
113
+ // }
114
+ // }
115
+ // });
116
+
117
+ // initPopover();
118
+ // }
package/rollup.config.js CHANGED
@@ -1,8 +1,11 @@
1
1
  /* eslint-env node */
2
2
  import { getConfig } from '@shgysk8zer0/js-utils/rollup';
3
+ import nodeResolve from '@rollup/plugin-node-resolve';
4
+
3
5
 
4
6
  export default getConfig('./all.js', {
5
7
  sourcemap: true,
6
8
  minify: true,
7
9
  format: 'iife',
10
+ plugins: [nodeResolve()],
8
11
  });
package/sanitizer.js ADDED
@@ -0,0 +1 @@
1
+ import '@aegisjsproject/sanitizer/sanitizer.js';
@@ -1,61 +0,0 @@
1
- /**
2
- * @copyright 2022-2023 Chris Zuber <admin@kernvalley.us>
3
- */
4
- import { nativeSupport, getSantizerUtils, sanitize, trustPolicies } from './sanitizerUtils.js';
5
- import { SanitizerConfig as defaultConfig } from './SanitizerConfigW3C.js';
6
-
7
- const protectedData = new WeakMap();
8
-
9
- /**
10
- * Need to create a policy for the Sanitizer API since
11
- * `trustedTypes.defaultPolicy.createHTML` will most likely use `new Sanitizer().sanitize()`
12
- * which would create infinite recursion.
13
- * @type {TrustedTypePolicy}
14
- */
15
-
16
-
17
- /**
18
- * @SEE https://wicg.github.io/sanitizer-api/
19
- * @SEE https://developer.mozilla.org/en-US/docs/Web/API/Sanitizer/Sanitizer
20
- * @TODO: Figure out how to handle `allowElements`, `allowAttributes`, and how each
21
- * works with their `block*` and/or `drop*` counterparts.
22
- * @TODO: Handle `svg:*` and `mathml:*`
23
- *
24
- * @NOTE: The spec is still under development and is likely to change.
25
- * @NOTE: This is a very imperfect implementation and may not perform very well,
26
- * as it may involve a lot of querying & modifying.
27
- */
28
- export class Sanitizer {
29
- constructor({
30
- allowElements, allowAttributes, blockElements, dropAttributes,
31
- dropElements, allowComments = defaultConfig.allowComments,
32
- allowCustomElements = defaultConfig.allowCustomElements,
33
- allowUnknownMarkup = defaultConfig.allowUnknownMarkup,
34
- } = Sanitizer.getDefaultConfiguration()) {
35
- protectedData.set(this, {
36
- allowElements, allowComments, allowAttributes, allowCustomElements,
37
- blockElements, dropAttributes, dropElements, allowUnknownMarkup,
38
- });
39
- }
40
-
41
- getConfiguration() {
42
- return protectedData.get(this);
43
- }
44
-
45
- sanitize(input) {
46
- return sanitize(input, this.getConfiguration());
47
- }
48
-
49
- sanitizeFor(tag, content) {
50
- const el = document.createElement(tag);
51
- el.setHTML(content, this.getConfiguration());
52
- return el;
53
- }
54
-
55
- static getDefaultConfiguration() {
56
- return defaultConfig;
57
- }
58
- }
59
-
60
- const { setHTML, polyfill } = getSantizerUtils(Sanitizer, defaultConfig);
61
- export { nativeSupport, setHTML, polyfill, trustPolicies };