@justeattakeaway/pie-webc-core 1.0.0 → 2.0.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.
package/dist/index.js CHANGED
@@ -1,28 +1,27 @@
1
1
  import { customElement as a } from "lit/decorators.js";
2
- import { isServer as u } from "lit";
3
- const f = (t, e, n) => function(i, s) {
4
- const o = `#${s}`;
5
- Object.defineProperty(i, s, {
2
+ const d = (t, e, s) => function(r, i) {
3
+ const o = `#${i}`;
4
+ Object.defineProperty(r, i, {
6
5
  get() {
7
6
  return this[o];
8
7
  },
9
8
  set(c) {
10
9
  e.includes(c) ? this[o] = c : (console.error(
11
- `<${t}> Invalid value "${c}" provided for property "${s}".`,
10
+ `<${t}> Invalid value "${c}" provided for property "${i}".`,
12
11
  `Must be one of: ${e.join(" | ")}.`,
13
- `Falling back to default value: "${n}"`
14
- ), this[o] = n);
12
+ `Falling back to default value: "${s}"`
13
+ ), this[o] = s);
15
14
  },
16
15
  configurable: !0
17
16
  });
18
- }, m = (t) => function(n, r) {
19
- const i = `#${r}`;
20
- Object.defineProperty(n, r, {
17
+ }, l = (t) => function(s, n) {
18
+ const r = `#${n}`;
19
+ Object.defineProperty(s, n, {
21
20
  get() {
22
- return this[i];
21
+ return this[r];
23
22
  },
24
- set(s) {
25
- (s == null || typeof s == "string" && s.trim() === "") && console.error(`<${t}> Missing required attribute "${r}"`), this[i] = s;
23
+ set(i) {
24
+ (i == null || typeof i == "string" && i.trim() === "") && console.error(`<${t}> Missing required attribute "${n}"`), this[r] = i;
26
25
  },
27
26
  configurable: !0
28
27
  });
@@ -31,16 +30,16 @@ function h(t) {
31
30
  return (e) => {
32
31
  try {
33
32
  a(t)(e);
34
- } catch (n) {
35
- const r = customElements.get(t), i = r == null ? void 0 : r.v;
36
- e.v !== i && console.warn(
37
- `PIE Web Component: "${t}" was already registered with version: ${i ?? "No version data found. Icon components do not contain version data. If the component is not an icon, please report the missing version data."}.`,
38
- n
33
+ } catch (s) {
34
+ const n = customElements.get(t), r = n == null ? void 0 : n.v;
35
+ e.v !== r && console.warn(
36
+ `PIE Web Component: "${t}" was already registered with version: ${r ?? "No version data found. Icon components do not contain version data. If the component is not an icon, please report the missing version data."}.`,
37
+ s
39
38
  );
40
39
  }
41
40
  };
42
41
  }
43
- function p(t) {
42
+ function b(t) {
44
43
  return new CustomEvent(t.type, {
45
44
  detail: {
46
45
  sourceEvent: t
@@ -49,51 +48,81 @@ function p(t) {
49
48
  cancelable: t.cancelable
50
49
  });
51
50
  }
52
- function b(t, e, n) {
51
+ function p(t, e, s) {
53
52
  e.startsWith("pie-") || console.warn("A custom event name should start with `pie-`");
54
- const r = new CustomEvent(e, {
53
+ const n = new CustomEvent(e, {
55
54
  bubbles: !0,
56
55
  composed: !0,
57
- detail: n
56
+ detail: s
58
57
  });
59
- t.dispatchEvent(r);
58
+ t.dispatchEvent(n);
60
59
  }
61
- const g = (t) => {
60
+ const m = (t) => {
62
61
  class e extends t {
62
+ constructor() {
63
+ super(...arguments), this._isRTL = !1, this.observer = null;
64
+ }
65
+ get isRTL() {
66
+ return this._isRTL;
67
+ }
68
+ set isRTL(n) {
69
+ this._isRTL = n, this.requestUpdate();
70
+ }
71
+ connectedCallback() {
72
+ super.connectedCallback(), this.handleWritingDirectionUpdate(), this.observer = new MutationObserver(() => {
73
+ this.handleWritingDirectionUpdate();
74
+ }), this.observer.observe(document.documentElement, {
75
+ attributeFilter: ["dir"],
76
+ subtree: !0
77
+ });
78
+ }
79
+ disconnectedCallback() {
80
+ super.disconnectedCallback(), this.observer && (this.observer.disconnect(), this.observer = null);
81
+ }
63
82
  /**
64
- * A getter to determine whether the text direction is right-to-left (RTL).
65
83
  * If the `dir` property is present on the component, it will be used to determine the text direction.
66
- * If running on the client-side (not SSR) and the `dir` property is not present, the text direction will be inferred
67
- * from the document's root element. This inference is not available during SSR.
68
- * In all other cases, it will return `false`, indicating a left-to-right (LTR) text direction.
69
- *
70
- * @returns {boolean} - Returns `true` if the text direction is RTL, otherwise `false`.
84
+ * If the `dir` property is not present, the text direction will be inferred from the document's root element.
85
+ * otherwise the default value is `false`, indicating a left-to-right (LTR) text direction.
71
86
  */
72
- get isRTL() {
73
- return this.dir ? this.dir === "rtl" : !u && !this.dir ? document.documentElement.getAttribute("dir") === "rtl" : !1;
87
+ handleWritingDirectionUpdate() {
88
+ this.isRTL = this.dir === "rtl" || document.documentElement.getAttribute("dir") === "rtl";
74
89
  }
75
90
  }
76
91
  return e;
77
- }, v = (t) => {
78
- const n = class n extends t {
92
+ }, f = (t) => {
93
+ const s = class s extends t {
79
94
  get form() {
80
95
  return this._internals.form;
81
96
  }
82
97
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
83
- constructor(...i) {
84
- super(...i), this._internals = this.attachInternals();
98
+ constructor(...r) {
99
+ super(...r), this._internals = this.attachInternals();
85
100
  }
86
101
  };
87
- n.formAssociated = !0;
88
- let e = n;
102
+ s.formAssociated = !0;
103
+ let e = s;
104
+ return e;
105
+ }, v = (t) => {
106
+ const s = class s extends t {
107
+ };
108
+ s.shadowRootOptions = {
109
+ // The `as any` cast is a safe way to access the static property
110
+ // from the generic superclass constructor. LitElement provides a default.
111
+ // This is unfortunately unavoidable and a common issue with mixins in TS.
112
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
113
+ ...t.shadowRootOptions,
114
+ delegatesFocus: !0
115
+ };
116
+ let e = s;
89
117
  return e;
90
118
  };
91
119
  export {
92
- v as FormControlMixin,
93
- g as RtlMixin,
94
- b as dispatchCustomEvent,
95
- m as requiredProperty,
120
+ v as DelegatesFocusMixin,
121
+ f as FormControlMixin,
122
+ m as RtlMixin,
123
+ p as dispatchCustomEvent,
124
+ l as requiredProperty,
96
125
  h as safeCustomElement,
97
- f as validPropertyValues,
98
- p as wrapNativeEvent
126
+ d as validPropertyValues,
127
+ b as wrapNativeEvent
99
128
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justeattakeaway/pie-webc-core",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "PIE design system base classes, mixins and utilities for web components",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -27,8 +27,11 @@
27
27
  "dependencies": {
28
28
  "lit": "3.2.0"
29
29
  },
30
+ "peerDependencies": {
31
+ "@justeattakeaway/pie-css": "0.22.0"
32
+ },
30
33
  "devDependencies": {
31
- "@justeattakeaway/pie-components-config": "0.20.1"
34
+ "@justeattakeaway/pie-components-config": "0.21.0"
32
35
  },
33
36
  "volta": {
34
37
  "extends": "../../../package.json"
@@ -0,0 +1,51 @@
1
+ import type { LitElement } from 'lit';
2
+ import type { GenericConstructor } from '../types/GenericConstructor';
3
+
4
+ /**
5
+ * Mixin to add `delegatesFocus: true` to a LitElement's shadow root options.
6
+ * This is useful for custom elements that act like form controls, allowing focus
7
+ * to be automatically delegated to the first focusable element inside the shadow DOM.
8
+ *
9
+ * @param superClass - The LitElement class to extend.
10
+ * @returns A class extending the provided LitElement with the delegatesFocus behaviour.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { LitElement, html } from 'lit';
15
+ * import { DelegatesFocusMixin } from './path-to-DelegatesFocusMixin'; // Update the import path
16
+ *
17
+ * // Create a new component using the DelegatesFocusMixin
18
+ * class MyCustomInput extends DelegatesFocusMixin(LitElement) {
19
+ * render() {
20
+ * // The focus will automatically go to the input when the component is focused
21
+ * return html`<input>`;
22
+ * }
23
+ * }
24
+ *
25
+ * customElements.define('my-custom-input', MyCustomInput);
26
+ * ```
27
+ */
28
+ export const DelegatesFocusMixin =
29
+ <T extends GenericConstructor<LitElement>>(superClass: T) => {
30
+ /**
31
+ * A LitElement with `delegatesFocus` enabled on its shadow root.
32
+ * @extends {LitElement}
33
+ */
34
+ class DelegatesFocusElement extends superClass {
35
+ /**
36
+ * Overrides shadow root options to include `delegatesFocus: true`, ensuring
37
+ * focus is passed into the component's shadow DOM to the first focusable element. It preserves
38
+ * any existing shadowRootOptions from the superclass.
39
+ */
40
+ static shadowRootOptions = {
41
+ // The `as any` cast is a safe way to access the static property
42
+ // from the generic superclass constructor. LitElement provides a default.
43
+ // This is unfortunately unavoidable and a common issue with mixins in TS.
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ ...(superClass as any).shadowRootOptions,
46
+ delegatesFocus: true,
47
+ };
48
+ }
49
+
50
+ return DelegatesFocusElement as T;
51
+ };
@@ -50,6 +50,8 @@ export const FormControlMixin =
50
50
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
51
51
  constructor (...args: any[]) {
52
52
  super(...args);
53
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
54
+ // @ts-ignore
53
55
  this._internals = this.attachInternals();
54
56
  }
55
57
  }
@@ -1,4 +1,5 @@
1
1
  export * from './rtl/rtlMixin';
2
2
  export * from './formControl/formControlMixin';
3
+ export * from './delegatesFocus/delegatesFocusMixin';
3
4
 
4
5
  export * from './types/GenericConstructor';
@@ -1,4 +1,4 @@
1
- import { type LitElement, isServer } from 'lit';
1
+ import { type LitElement } from 'lit';
2
2
  import { type GenericConstructor } from '../types/GenericConstructor';
3
3
 
4
4
  /**
@@ -63,26 +63,47 @@ export const RtlMixin =
63
63
  * @implements {RTLInterface}
64
64
  */
65
65
  class RTLElement extends superClass implements RTLInterface {
66
+ private _isRTL = false;
67
+
68
+ get isRTL () {
69
+ return this._isRTL;
70
+ }
71
+
72
+ set isRTL (val: boolean) {
73
+ this._isRTL = val;
74
+ this.requestUpdate();
75
+ }
76
+
77
+ private observer: MutationObserver | null = null;
78
+
79
+ connectedCallback () {
80
+ super.connectedCallback();
81
+ this.handleWritingDirectionUpdate();
82
+
83
+ this.observer = new MutationObserver(() => {
84
+ this.handleWritingDirectionUpdate();
85
+ });
86
+
87
+ this.observer.observe(document.documentElement, {
88
+ attributeFilter: ['dir'],
89
+ subtree: true,
90
+ });
91
+ }
92
+
93
+ disconnectedCallback () {
94
+ super.disconnectedCallback();
95
+ if (!this.observer) return;
96
+ this.observer.disconnect();
97
+ this.observer = null;
98
+ }
99
+
66
100
  /**
67
- * A getter to determine whether the text direction is right-to-left (RTL).
68
101
  * If the `dir` property is present on the component, it will be used to determine the text direction.
69
- * If running on the client-side (not SSR) and the `dir` property is not present, the text direction will be inferred
70
- * from the document's root element. This inference is not available during SSR.
71
- * In all other cases, it will return `false`, indicating a left-to-right (LTR) text direction.
72
- *
73
- * @returns {boolean} - Returns `true` if the text direction is RTL, otherwise `false`.
102
+ * If the `dir` property is not present, the text direction will be inferred from the document's root element.
103
+ * otherwise the default value is `false`, indicating a left-to-right (LTR) text direction.
74
104
  */
75
- get isRTL (): boolean {
76
- if (this.dir) {
77
- return this.dir === 'rtl';
78
- }
79
-
80
- // If running on client-side and `dir` is not present, infer from the document's root element.
81
- if (!isServer && !this.dir) {
82
- return document.documentElement.getAttribute('dir') === 'rtl';
83
- }
84
-
85
- return false;
105
+ private handleWritingDirectionUpdate () {
106
+ this.isRTL = this.dir === 'rtl' || document.documentElement.getAttribute('dir') === 'rtl';
86
107
  }
87
108
  }
88
109