@eunomia/elements 1.0.0-beta.2 → 1.0.0-beta.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.
Files changed (98) hide show
  1. package/dist/cdn/components/chunks/chunk-3LMI7KUA.js +48 -0
  2. package/dist/cdn/components/chunks/{chunk-74HHV4CX.js → chunk-53QH6MPM.js} +2 -2
  3. package/dist/cdn/components/chunks/{chunk-7WTSHE7M.js → chunk-EAGGN3ZI.js} +1 -1
  4. package/dist/cdn/components/chunks/chunk-GU6BVMFJ.js +1 -0
  5. package/dist/cdn/components/chunks/chunk-KNM5QHDK.js +38 -0
  6. package/dist/cdn/components/chunks/{chunk-AQQMW353.js → chunk-TBKKTJOX.js} +1 -1
  7. package/dist/cdn/components/chunks/chunk-YYCEPZUN.js +1 -0
  8. package/dist/cdn/components/chunks/{chunk-27Q2SLRY.js → chunk-Z6PJYSC3.js} +30 -11
  9. package/dist/cdn/components/eun-animate.js +178 -2
  10. package/dist/cdn/components/eun-button.js +1 -1
  11. package/dist/cdn/components/eun-card.js +15 -7
  12. package/dist/cdn/components/eun-carousel.js +1 -1
  13. package/dist/cdn/components/eun-check-card.js +1 -1
  14. package/dist/cdn/components/eun-checkbox-list.js +2 -2
  15. package/dist/cdn/components/eun-checkbox.js +1 -1
  16. package/dist/cdn/components/eun-chip.js +11 -14
  17. package/dist/cdn/components/eun-collapse.js +8 -15
  18. package/dist/cdn/components/eun-color-picker.js +19 -19
  19. package/dist/cdn/components/eun-counter.js +4 -4
  20. package/dist/cdn/components/eun-date-picker.js +2 -2
  21. package/dist/cdn/components/eun-icon.js +1 -1
  22. package/dist/cdn/components/eun-input-file.js +11 -11
  23. package/dist/cdn/components/eun-input-phone.js +3 -3
  24. package/dist/cdn/components/eun-input.js +1 -1
  25. package/dist/cdn/components/eun-radio-card.js +1 -1
  26. package/dist/cdn/components/eun-radio-list.js +3 -3
  27. package/dist/cdn/components/eun-radio.js +1 -1
  28. package/dist/cdn/components/eun-search.js +1 -1
  29. package/dist/cdn/components/eun-select.js +33 -12
  30. package/dist/cdn/components/eun-sidebar.js +1 -1
  31. package/dist/cdn/components/eun-slider.js +3 -3
  32. package/dist/cdn/components/eun-sliding-card.js +4 -8
  33. package/dist/cdn/components/eun-switch.js +1 -1
  34. package/dist/cdn/components/eun-table.js +1 -1
  35. package/dist/cdn/components/eun-tag.js +13 -9
  36. package/dist/cdn/components/eun-textarea.js +11 -11
  37. package/dist/cdn/components/eun-time-picker.js +2 -2
  38. package/dist/cdn/components/eun-toggle-group.js +2 -2
  39. package/dist/cdn/components/eun-toggle-item.js +1 -1
  40. package/dist/cdn/components/eun-toggle.js +2 -2
  41. package/dist/cdn/components/eun-toolbar.js +14 -12
  42. package/dist/cdn/components/eun-tooltip.js +2 -2
  43. package/dist/components/action/button/button.d.ts +5 -6
  44. package/dist/components/action/button/button.js +5 -6
  45. package/dist/components/action/button/button.styles.js +31 -9
  46. package/dist/components/action/toggle/toggle-group.js +1 -1
  47. package/dist/components/action/toggle/toggle-item.styles.js +1 -1
  48. package/dist/components/action/toggle/toggle.js +1 -1
  49. package/dist/components/content/card/card.d.ts +1 -1
  50. package/dist/components/content/card/card.js +1 -1
  51. package/dist/components/content/card/card.styles.js +13 -5
  52. package/dist/components/content/card/sliding-card.styles.js +0 -4
  53. package/dist/components/content/chip/chip.styles.js +6 -9
  54. package/dist/components/content/collapse/collapse.styles.js +0 -7
  55. package/dist/components/content/icon/icon.d.ts +48 -5
  56. package/dist/components/content/icon/icon.js +92 -20
  57. package/dist/components/content/tag/tag.styles.js +10 -6
  58. package/dist/components/content/tooltip/tooltip.styles.js +2 -2
  59. package/dist/components/form/checkbox/checkbox-list.js +1 -1
  60. package/dist/components/form/color-picker/color-picker.js +9 -7
  61. package/dist/components/form/counter/counter.js +3 -3
  62. package/dist/components/form/date-picker/date-picker.js +3 -3
  63. package/dist/components/form/input/input.js +2 -2
  64. package/dist/components/form/input-file/input-file.js +5 -5
  65. package/dist/components/form/input-phone/input-phone.js +3 -3
  66. package/dist/components/form/radio/radio-list.js +2 -2
  67. package/dist/components/form/select/select.d.ts +16 -0
  68. package/dist/components/form/select/select.js +28 -5
  69. package/dist/components/form/select/select.styles.js +11 -0
  70. package/dist/components/form/slider/slider.js +2 -2
  71. package/dist/components/form/textarea/textarea.js +4 -4
  72. package/dist/components/form/time-picker/time-picker.js +3 -3
  73. package/dist/components/layout/animate/animate.d.ts +40 -5
  74. package/dist/components/layout/animate/animate.js +30 -11
  75. package/dist/components/layout/animate/animate.styles.d.ts +1 -1
  76. package/dist/components/layout/animate/animate.styles.js +191 -1
  77. package/dist/components/navigation/carousel/carousel.styles.js +1 -1
  78. package/dist/components/navigation/toolbar/toolbar.d.ts +22 -0
  79. package/dist/components/navigation/toolbar/toolbar.js +28 -2
  80. package/dist/components/navigation/toolbar/toolbar.styles.js +4 -3
  81. package/dist/events/change.event.d.ts +13 -1
  82. package/dist/events/change.event.js +2 -1
  83. package/dist/index.d.ts +1 -1
  84. package/dist/index.js +1 -1
  85. package/dist/mixins/check.mixin.js +6 -2
  86. package/dist/mixins/form.mixin.d.ts +4 -0
  87. package/dist/mixins/form.mixin.js +78 -2
  88. package/dist/mixins/radio.mixin.js +6 -2
  89. package/dist/ssr/animate-ssr.css +149 -0
  90. package/dist/ssr/overlay-ssr.css +57 -0
  91. package/dist/ssr/sidebar-ssr.css +57 -0
  92. package/dist/ssr/toolbar-ssr.css +41 -0
  93. package/package.json +9 -3
  94. package/dist/cdn/components/chunks/chunk-2IQUMAMI.js +0 -38
  95. package/dist/cdn/components/chunks/chunk-7Q6AHVI5.js +0 -1
  96. package/dist/cdn/components/chunks/chunk-DENMN3WH.js +0 -48
  97. package/dist/cdn/components/chunks/chunk-ONYUXQV2.js +0 -1
  98. package/dist/components/layout/animate/animate-ssr.css +0 -64
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, property, query } from "lit/decorators.js";
7
+ import { customElement, property, query, queryAssignedElements, } from "lit/decorators.js";
8
8
  import { html, LitElement, nothing } from "lit";
9
9
  import { ChangeEvent } from "../../../events/change.event.js";
10
10
  import { handleLinkNavigation } from "../../../utils/navigation.utils.js";
@@ -53,6 +53,8 @@ export const EunomiaToolbarTagName = "eun-toolbar";
53
53
  * everything behind it, including the logo and any other bar content;
54
54
  * the burger is the only thing that stays visible in front of it.
55
55
  *
56
+ * @slot [menu-icon] - Replaces the burger's default open icon (an `eun-icon name="menu"`) with any content, shown while the panel is closed. Useful wherever `eun-icon`'s own dynamic SVG resolution doesn't fit, e.g. some bundler setups
57
+ * @slot [close-icon] - Replaces the burger's default close icon (an `eun-icon name="close"`) with any content, shown while the panel is open. See `menu-icon` above
56
58
  * @slot start - Left-side content, rendered after a logo image linking to logoHref whenever logoSrc is set
57
59
  * @slot center - Center content, truly centered independently of the start and end widths
58
60
  * @slot end - Right-side content
@@ -134,6 +136,7 @@ export const EunomiaToolbarTagName = "eun-toolbar";
134
136
  * @cssprop [--toolbar-skip-links-background] - Sets the background of the skip-links bar, defaulting to a darker mix of the bar's own background
135
137
  * @cssprop [--toolbar-skip-links-color] - Sets the text color of the skip-links bar
136
138
  * @cssprop [--toolbar-skip-links-separator-color] - Sets the color of the divider drawn between skip links
139
+ * @cssprop [--toolbar-skip-links-gap] - Sets the gap between skip links, with the divider centered in it
137
140
  * @element eun-toolbar
138
141
  */
139
142
  let EunomiaToolbar = class EunomiaToolbar extends DialogSurfaceMixin(LitElement) {
@@ -256,6 +259,14 @@ let EunomiaToolbar = class EunomiaToolbar extends DialogSurfaceMixin(LitElement)
256
259
  * @internal
257
260
  */
258
261
  this.mobile = false;
262
+ /**
263
+ * Re-renders once a `menu-icon`/`close-icon` slot's content changes, so
264
+ * the default `eun-icon` fallback correctly appears/disappears.
265
+ * @private
266
+ */
267
+ this.handleIconSlotChange = () => {
268
+ this.requestUpdate();
269
+ };
259
270
  /**
260
271
  * The element (or `window`) {@link handleScroll} is currently listening
261
272
  * on, resolved from `scrollTarget`.
@@ -834,6 +845,11 @@ let EunomiaToolbar = class EunomiaToolbar extends DialogSurfaceMixin(LitElement)
834
845
  * @private
835
846
  */
836
847
  renderBurger() {
848
+ const slotName = this.open ? "close-icon" : "menu-icon";
849
+ const iconName = this.open ? "close" : "menu";
850
+ const hasSlotted = this.open
851
+ ? this.closeIconSlotEls.length
852
+ : this.menuIconSlotEls.length;
837
853
  return html `
838
854
  <eun-button
839
855
  id="burger"
@@ -846,7 +862,11 @@ let EunomiaToolbar = class EunomiaToolbar extends DialogSurfaceMixin(LitElement)
846
862
  : this.ariaLabelMenuOpen}
847
863
  @click=${() => this.toggle()}
848
864
  >
849
- <eun-icon name=${this.open ? "close" : "menu"} size="20"></eun-icon>
865
+ <slot name=${slotName} @slotchange=${this.handleIconSlotChange}>
866
+ ${hasSlotted
867
+ ? nothing
868
+ : html `<eun-icon name=${iconName} size="20"></eun-icon>`}
869
+ </slot>
850
870
  </eun-button>
851
871
  `;
852
872
  }
@@ -996,6 +1016,12 @@ __decorate([
996
1016
  __decorate([
997
1017
  query("#burger")
998
1018
  ], EunomiaToolbar.prototype, "burgerEl", void 0);
1019
+ __decorate([
1020
+ queryAssignedElements({ slot: "menu-icon" })
1021
+ ], EunomiaToolbar.prototype, "menuIconSlotEls", void 0);
1022
+ __decorate([
1023
+ queryAssignedElements({ slot: "close-icon" })
1024
+ ], EunomiaToolbar.prototype, "closeIconSlotEls", void 0);
999
1025
  EunomiaToolbar = __decorate([
1000
1026
  customElement(EunomiaToolbarTagName)
1001
1027
  ], EunomiaToolbar);
@@ -32,6 +32,7 @@ import { css } from "lit";
32
32
  * [--toolbar-skip-links-background] - Set a custom background for the skip-links bar, default a darker mix of the bar's own background
33
33
  * [--toolbar-skip-links-color] - Set a custom text color for the skip-links bar
34
34
  * [--toolbar-skip-links-separator-color] - Set a custom color for the divider drawn between skip links
35
+ * [--toolbar-skip-links-gap] - Set a custom gap between skip links, with the divider centered in it
35
36
  */
36
37
  const base = css `
37
38
  :host {
@@ -79,6 +80,7 @@ const base = css `
79
80
  color-mix(in srgb, var(--_skipLinksBase) 82%, black 18%)
80
81
  );
81
82
  --_skipLinksColor: var(--toolbar-skip-links-color, #fff);
83
+ --_skipLinksGap: var(--toolbar-skip-links-gap, var(--eun-space-m, 16px));
82
84
  --_skipLinksSeparatorColor: var(
83
85
  --toolbar-skip-links-separator-color,
84
86
  color-mix(in srgb, var(--_skipLinksColor) 50%, transparent)
@@ -201,7 +203,7 @@ const base = css `
201
203
  z-index: calc(var(--_zIndex) + 2);
202
204
  display: flex;
203
205
  align-items: center;
204
- gap: var(--eun-space-m);
206
+ gap: var(--_skipLinksGap);
205
207
  overflow: hidden;
206
208
  height: var(--_skipLinksHeight);
207
209
  padding-inline: var(--eun-space-m);
@@ -253,13 +255,12 @@ const base = css `
253
255
  #skip-links ::slotted(a:not(:first-child)),
254
256
  #skip-links ::slotted(eun-link:not(:first-child)) {
255
257
  position: relative;
256
- padding-inline-start: var(--eun-space-s);
257
258
  }
258
259
  #skip-links ::slotted(a:not(:first-child))::before,
259
260
  #skip-links ::slotted(eun-link:not(:first-child))::before {
260
261
  content: "";
261
262
  position: absolute;
262
- inset-inline-start: 0;
263
+ inset-inline-start: calc(var(--_skipLinksGap) / -2);
263
264
  inset-block: 0;
264
265
  width: 1px;
265
266
  background: var(--_skipLinksSeparatorColor);
@@ -11,7 +11,19 @@ export declare class ChangeEvent<T = unknown> extends Event {
11
11
  * Declaration of the element that dispatches the event.
12
12
  */
13
13
  target: LitElement & FormMixinInterface<T>;
14
- constructor();
14
+ /**
15
+ * The new value (or `checked` state, for a checkable field) at the
16
+ * moment this event was dispatched — the same one already readable from
17
+ * `event.target.value`/`.checked`, exposed directly on the event too so
18
+ * a listener attached higher up the tree (delegation on a `<form>`, for
19
+ * instance) can read it as `event.value` without narrowing
20
+ * `event.target`'s type itself. `undefined` for a dispatcher with no
21
+ * single value of its own (toolbar, sidebar, collapse still only ever
22
+ * construct this with no argument, reporting their own state through
23
+ * `event.target` instead, same as before).
24
+ */
25
+ readonly value: T;
26
+ constructor(value?: T);
15
27
  }
16
28
  declare global {
17
29
  interface GlobalEventHandlersEventMap {
@@ -1,6 +1,7 @@
1
1
  export class ChangeEvent extends Event {
2
- constructor() {
2
+ constructor(value) {
3
3
  super(ChangeEvent.eventName, { bubbles: true, composed: false });
4
+ this.value = value;
4
5
  }
5
6
  }
6
7
  /**
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export { EunomiaToggleItem, EunomiaToggleItemTagName, } from "./components/actio
15
15
  export { EunomiaToggleGroup, EunomiaToggleGroupTagName, } from "./components/action/toggle/toggle-group.js";
16
16
  export type { EunomiaToggleGroupOption, EunomiaToggleGroupAppearance, } from "./components/action/toggle/toggle-group.js";
17
17
  export { EunomiaLink, EunomiaLinkTagName, } from "./components/action/link/link.js";
18
- export { EunomiaIcon, EunomiaIconTagName, } from "./components/content/icon/icon.js";
18
+ export { EunomiaIcon, EunomiaIconTagName, setIconBaseUrl, } from "./components/content/icon/icon.js";
19
19
  export type { EunomiaIconName, EunomiaIconType, } from "./components/content/icon/icon.type.js";
20
20
  export { EunomiaTag, EunomiaTagTagName } from "./components/content/tag/tag.js";
21
21
  export { EunomiaChip, EunomiaChipTagName, } from "./components/content/chip/chip.js";
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ export { EunomiaToggle, EunomiaToggleTagName, } from "./components/action/toggle
39
39
  export { EunomiaToggleItem, EunomiaToggleItemTagName, } from "./components/action/toggle/toggle-item.js";
40
40
  export { EunomiaToggleGroup, EunomiaToggleGroupTagName, } from "./components/action/toggle/toggle-group.js";
41
41
  export { EunomiaLink, EunomiaLinkTagName, } from "./components/action/link/link.js";
42
- export { EunomiaIcon, EunomiaIconTagName, } from "./components/content/icon/icon.js";
42
+ export { EunomiaIcon, EunomiaIconTagName, setIconBaseUrl, } from "./components/content/icon/icon.js";
43
43
  export { EunomiaTag, EunomiaTagTagName } from "./components/content/tag/tag.js";
44
44
  export { EunomiaChip, EunomiaChipTagName, } from "./components/content/chip/chip.js";
45
45
  export { EunomiaBadge, EunomiaBadgeTagName, } from "./components/content/badge/badge.js";
@@ -73,10 +73,14 @@ export const CheckMixin = (superClass) => {
73
73
  * Resets `checked` to `defaultChecked` (or `false`, if never set) on a
74
74
  * native form `reset()` — overrides `FormMixin`'s own
75
75
  * `formResetCallback`, which unconditionally forces checkable fields
76
- * to `false` with no notion of a default checked state.
76
+ * to `false` with no notion of a default checked state. Also resets
77
+ * `dirty`/`touched` itself, since it doesn't call `super` to reach
78
+ * `FormMixin`'s own reset of those two.
77
79
  */
78
80
  formResetCallback() {
79
81
  this.checked = this.defaultChecked ?? false;
82
+ this.dirty = false;
83
+ this.touched = false;
80
84
  }
81
85
  /**
82
86
  * Lifecycle: Called when the component is disconnected from the DOM.
@@ -140,7 +144,7 @@ export const CheckMixin = (superClass) => {
140
144
  else {
141
145
  this.removeAttribute("aria-description");
142
146
  }
143
- this.dispatchEvent(new ChangeEvent());
147
+ this.dispatchEvent(new ChangeEvent(this.checked));
144
148
  }
145
149
  /**
146
150
  * Handles keydown interactions.
@@ -17,6 +17,10 @@ export declare class FormMixinInterface<T> {
17
17
  valueState?: T;
18
18
  hideError?: boolean;
19
19
  form: HTMLFormElement | null;
20
+ dirty: boolean;
21
+ touched: boolean;
22
+ get pristine(): boolean;
23
+ get untouched(): boolean;
20
24
  get value(): T;
21
25
  set value(value: T);
22
26
  get defaultValue(): T | undefined;
@@ -4,9 +4,15 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { html, nothing, } from "lit";
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ import { html, nothing } from "lit";
8
13
  import { property, state } from "lit/decorators.js";
9
14
  import { when } from "lit/directives/when.js";
15
+ import { ChangeEvent } from "../events/change.event.js";
10
16
  /**
11
17
  * Mixin that adds form-related behavior and value management.
12
18
  *
@@ -15,6 +21,7 @@ import { when } from "lit/directives/when.js";
15
21
  * @returns A class extending the provided base with form capabilities.
16
22
  */
17
23
  export const FormMixin = (superClass) => {
24
+ var _FormMixinClass_markDirty, _FormMixinClass_markTouched;
18
25
  class FormMixinClass extends superClass {
19
26
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
27
  constructor(...args) {
@@ -36,11 +43,60 @@ export const FormMixin = (superClass) => {
36
43
  * @private
37
44
  */
38
45
  this.checked = false;
39
- // Attach internals if not already done by ValidatorsMixin
46
+ /**
47
+ * Whether the value has changed since the field connected (or since the
48
+ * last reset). Derived from `eunchange`, the event every field's own
49
+ * user-interaction handler already dispatches (and only that: setting
50
+ * `.value`/`.defaultValue` from outside, as a controlled React field
51
+ * does on every render, never dispatches it), so a controlled field
52
+ * stays pristine across ordinary re-renders and only turns dirty from
53
+ * genuine user input.
54
+ * @default false
55
+ */
56
+ this.dirty = false;
57
+ /**
58
+ * Whether the field has lost focus at least once since it connected (or
59
+ * since the last reset).
60
+ * @default false
61
+ */
62
+ this.touched = false;
63
+ /**
64
+ * Marks the field dirty on its own `eunchange` — dispatched only from a
65
+ * genuine user-interaction handler, never from the `value`/`checked`
66
+ * setters themselves — so a re-render setting the same property from
67
+ * outside never flips this.
68
+ */
69
+ _FormMixinClass_markDirty.set(this, () => {
70
+ if (!this.dirty) {
71
+ this.dirty = true;
72
+ }
73
+ });
74
+ /**
75
+ * Marks the field touched the first time focus leaves it.
76
+ */
77
+ _FormMixinClass_markTouched.set(this, () => {
78
+ if (!this.touched) {
79
+ this.touched = true;
80
+ }
81
+ });
40
82
  if (!this.internals) {
41
83
  this.internals = this.attachInternals();
42
84
  }
43
85
  }
86
+ /**
87
+ * Whether the value hasn't changed since the field connected (or since
88
+ * the last reset). The inverse of {@link dirty}.
89
+ */
90
+ get pristine() {
91
+ return !this.dirty;
92
+ }
93
+ /**
94
+ * Whether the field hasn't lost focus yet since it connected (or since
95
+ * the last reset). The inverse of {@link touched}.
96
+ */
97
+ get untouched() {
98
+ return !this.touched;
99
+ }
44
100
  /**
45
101
  * Gets the default value of the field.
46
102
  *
@@ -128,6 +184,17 @@ export const FormMixin = (superClass) => {
128
184
  this.value = this.defaultValue;
129
185
  }
130
186
  this.checkValidity(this.value);
187
+ this.addEventListener(ChangeEvent.eventName, __classPrivateFieldGet(this, _FormMixinClass_markDirty, "f"));
188
+ this.addEventListener("focusout", __classPrivateFieldGet(this, _FormMixinClass_markTouched, "f"));
189
+ }
190
+ /**
191
+ * Lifecycle callback called when element is disconnected from the DOM.
192
+ * Removes the listeners driving {@link dirty} and {@link touched}.
193
+ */
194
+ disconnectedCallback() {
195
+ this.removeEventListener(ChangeEvent.eventName, __classPrivateFieldGet(this, _FormMixinClass_markDirty, "f"));
196
+ this.removeEventListener("focusout", __classPrivateFieldGet(this, _FormMixinClass_markTouched, "f"));
197
+ super.disconnectedCallback?.();
131
198
  }
132
199
  /**
133
200
  * LitElement lifecycle method called before update.
@@ -196,6 +263,8 @@ export const FormMixin = (superClass) => {
196
263
  else {
197
264
  this.value = this.defaultValue;
198
265
  }
266
+ this.dirty = false;
267
+ this.touched = false;
199
268
  }
200
269
  /**
201
270
  * Renders the description or error messages.
@@ -237,6 +306,7 @@ export const FormMixin = (superClass) => {
237
306
  `;
238
307
  }
239
308
  }
309
+ _FormMixinClass_markDirty = new WeakMap(), _FormMixinClass_markTouched = new WeakMap();
240
310
  FormMixinClass.formAssociated = true;
241
311
  __decorate([
242
312
  property({ reflect: true })
@@ -250,6 +320,12 @@ export const FormMixin = (superClass) => {
250
320
  __decorate([
251
321
  state()
252
322
  ], FormMixinClass.prototype, "valueState", void 0);
323
+ __decorate([
324
+ state()
325
+ ], FormMixinClass.prototype, "dirty", void 0);
326
+ __decorate([
327
+ state()
328
+ ], FormMixinClass.prototype, "touched", void 0);
253
329
  __decorate([
254
330
  property({
255
331
  attribute: "default-value",
@@ -80,10 +80,14 @@ export const RadioMixin = (superClass) => {
80
80
  * Resets `checked` to `defaultChecked` (or `false`, if never set) on a
81
81
  * native form `reset()` — overrides `FormMixin`'s own
82
82
  * `formResetCallback`, which unconditionally forces checkable fields
83
- * to `false` with no notion of a default checked state.
83
+ * to `false` with no notion of a default checked state. Also resets
84
+ * `dirty`/`touched` itself, since it doesn't call `super` to reach
85
+ * `FormMixin`'s own reset of those two.
84
86
  */
85
87
  formResetCallback() {
86
88
  this.checked = this.defaultChecked ?? false;
89
+ this.dirty = false;
90
+ this.touched = false;
87
91
  }
88
92
  /**
89
93
  * Lifecycle: Called when the component is disconnected from the DOM.
@@ -147,7 +151,7 @@ export const RadioMixin = (superClass) => {
147
151
  else {
148
152
  this.removeAttribute("aria-description");
149
153
  }
150
- this.dispatchEvent(new ChangeEvent());
154
+ this.dispatchEvent(new ChangeEvent(this.checked));
151
155
  }
152
156
  /**
153
157
  * Handles keydown interactions.
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Optional light-DOM stylesheet for `<eun-animate>` in server-rendered
3
+ * pages (Next.js, or any framework/setup without Declarative Shadow DOM
4
+ * for Lit components). It closes the SSR flash described in the eun-animate
5
+ * documentation's Accessibility/SSR notes : server HTML has no Shadow DOM
6
+ * yet, so `<eun-animate>`'s own `:host([animation="fade"]) { opacity: 0 }`
7
+ * (and the other animation variants) can't apply until the element is
8
+ * upgraded client-side, meaning content renders visible first, then snaps
9
+ * hidden the instant the custom element registers, then fades back in.
10
+ *
11
+ * This stylesheet lives in the host document instead, applying the exact
12
+ * same starting state through `:not(:defined)`, which is true from first
13
+ * paint and stops matching permanently the moment the browser upgrades the
14
+ * element — handing off to the component's own Shadow DOM styles at
15
+ * exactly the point they take over, with no gap and no double transition.
16
+ *
17
+ * Usage — link it in the page `<head>`, alongside (not instead of)
18
+ * importing "@eunomia/elements/animate.js" :
19
+ *
20
+ * <link
21
+ * rel="stylesheet"
22
+ * href="node_modules/@eunomia/elements/dist/ssr/animate-ssr.css"
23
+ * />
24
+ *
25
+ * Requires every server-rendered `<eun-animate>` to write its `animation`
26
+ * attribute explicitly (even when it's the "fade" default), since that
27
+ * default only ever becomes an attribute once Lit initializes the
28
+ * property client-side — invisible to this stylesheet, or any plain CSS,
29
+ * before then :
30
+ *
31
+ * <eun-animate animation="fade">...</eun-animate>
32
+ */
33
+
34
+ eun-animate:not(:defined) {
35
+ --_distance: var(--animate-distance, 80px);
36
+ }
37
+
38
+ eun-animate[animation="fade"]:not(:defined),
39
+ eun-animate[animation="faded-scroll-right"]:not(:defined),
40
+ eun-animate[animation="faded-scroll-left"]:not(:defined),
41
+ eun-animate[animation="faded-scroll-top"]:not(:defined),
42
+ eun-animate[animation="faded-scroll-bottom"]:not(:defined) {
43
+ opacity: 0;
44
+ }
45
+
46
+ eun-animate[animation="scroll-right"]:not(:defined),
47
+ eun-animate[animation="faded-scroll-right"]:not(:defined) {
48
+ transform: translateX(calc(-1 * var(--_distance)));
49
+ }
50
+
51
+ eun-animate[animation="scroll-left"]:not(:defined),
52
+ eun-animate[animation="faded-scroll-left"]:not(:defined) {
53
+ transform: translateX(var(--_distance));
54
+ }
55
+
56
+ eun-animate[animation="scroll-top"]:not(:defined),
57
+ eun-animate[animation="faded-scroll-top"]:not(:defined) {
58
+ transform: translateY(var(--_distance));
59
+ }
60
+
61
+ eun-animate[animation="scroll-bottom"]:not(:defined),
62
+ eun-animate[animation="faded-scroll-bottom"]:not(:defined) {
63
+ transform: translateY(calc(-1 * var(--_distance)));
64
+ }
65
+
66
+ /**
67
+ * `tablet-animation`/`mobile-animation` overrides, mirroring the rules
68
+ * above and the same-named `@media` blocks in the component's own
69
+ * `animate.styles.ts` — kept in sync by hand, since this file has to
70
+ * duplicate the shadow DOM's styles for the light-DOM pre-hydration
71
+ * window regardless. Placed after the unscoped rules above so an
72
+ * equal-specificity tie (e.g. both `animation="fade"` and
73
+ * `tablet-animation="none"` set at once) resolves in the narrower
74
+ * breakpoint's favor, once its `@media` condition is true — same
75
+ * source-order reasoning as `animate.styles.ts`.
76
+ *
77
+ * `max-width` values match `EUNOMIA_BREAKPOINTS.tablet`/`.mobile`
78
+ * (`breakpoints.ts`) — hardcoded here since plain CSS can't read a JS
79
+ * constant.
80
+ */
81
+ @media (max-width: 768px) {
82
+ eun-animate[tablet-animation="none"]:not(:defined) {
83
+ opacity: 1;
84
+ transform: none;
85
+ }
86
+
87
+ eun-animate[tablet-animation="fade"]:not(:defined),
88
+ eun-animate[tablet-animation="faded-scroll-right"]:not(:defined),
89
+ eun-animate[tablet-animation="faded-scroll-left"]:not(:defined),
90
+ eun-animate[tablet-animation="faded-scroll-top"]:not(:defined),
91
+ eun-animate[tablet-animation="faded-scroll-bottom"]:not(:defined) {
92
+ opacity: 0;
93
+ }
94
+
95
+ eun-animate[tablet-animation="scroll-right"]:not(:defined),
96
+ eun-animate[tablet-animation="faded-scroll-right"]:not(:defined) {
97
+ transform: translateX(calc(-1 * var(--_distance)));
98
+ }
99
+
100
+ eun-animate[tablet-animation="scroll-left"]:not(:defined),
101
+ eun-animate[tablet-animation="faded-scroll-left"]:not(:defined) {
102
+ transform: translateX(var(--_distance));
103
+ }
104
+
105
+ eun-animate[tablet-animation="scroll-top"]:not(:defined),
106
+ eun-animate[tablet-animation="faded-scroll-top"]:not(:defined) {
107
+ transform: translateY(var(--_distance));
108
+ }
109
+
110
+ eun-animate[tablet-animation="scroll-bottom"]:not(:defined),
111
+ eun-animate[tablet-animation="faded-scroll-bottom"]:not(:defined) {
112
+ transform: translateY(calc(-1 * var(--_distance)));
113
+ }
114
+ }
115
+
116
+ @media (max-width: 600px) {
117
+ eun-animate[mobile-animation="none"]:not(:defined) {
118
+ opacity: 1;
119
+ transform: none;
120
+ }
121
+
122
+ eun-animate[mobile-animation="fade"]:not(:defined),
123
+ eun-animate[mobile-animation="faded-scroll-right"]:not(:defined),
124
+ eun-animate[mobile-animation="faded-scroll-left"]:not(:defined),
125
+ eun-animate[mobile-animation="faded-scroll-top"]:not(:defined),
126
+ eun-animate[mobile-animation="faded-scroll-bottom"]:not(:defined) {
127
+ opacity: 0;
128
+ }
129
+
130
+ eun-animate[mobile-animation="scroll-right"]:not(:defined),
131
+ eun-animate[mobile-animation="faded-scroll-right"]:not(:defined) {
132
+ transform: translateX(calc(-1 * var(--_distance)));
133
+ }
134
+
135
+ eun-animate[mobile-animation="scroll-left"]:not(:defined),
136
+ eun-animate[mobile-animation="faded-scroll-left"]:not(:defined) {
137
+ transform: translateX(var(--_distance));
138
+ }
139
+
140
+ eun-animate[mobile-animation="scroll-top"]:not(:defined),
141
+ eun-animate[mobile-animation="faded-scroll-top"]:not(:defined) {
142
+ transform: translateY(var(--_distance));
143
+ }
144
+
145
+ eun-animate[mobile-animation="scroll-bottom"]:not(:defined),
146
+ eun-animate[mobile-animation="faded-scroll-bottom"]:not(:defined) {
147
+ transform: translateY(calc(-1 * var(--_distance)));
148
+ }
149
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Optional light-DOM stylesheet for server-rendered pages (Next.js, or
3
+ * any framework/setup without Declarative Shadow DOM for Lit
4
+ * components), covering every closed-by-default overlay/disclosure
5
+ * component in one file : `eun-collapse`, `eun-drawer`, `eun-modal`,
6
+ * `eun-dropdown-button`, and `eun-tooltip`. Each hides its own slotted
7
+ * content only through its own Shadow DOM (a `grid-template-rows: 0fr`
8
+ * panel for collapse, a `popover="manual"`/`popover="auto"` surface for
9
+ * the rest), which doesn't exist yet in server-rendered HTML. That
10
+ * content renders as plain, unstyled light-DOM children instead, on top
11
+ * of everything else on the page, until the element upgrades — the same
12
+ * SSR flash `animate-ssr.css`/`toolbar-ssr.css`/`sidebar-ssr.css`
13
+ * document for their own components, just for content that's meant to
14
+ * stay hidden until something opens it, rather than a starting animation
15
+ * state or a persistent, always-visible layout piece.
16
+ *
17
+ * This stylesheet lives in the host document instead, hiding that exact
18
+ * content through `:not(:defined)`, which is true from first paint and
19
+ * stops matching permanently the moment the browser upgrades the
20
+ * element — handing off to each component's own Shadow DOM at exactly
21
+ * the point it takes over, with no gap.
22
+ *
23
+ * Usage — link it in the page `<head>`, alongside (not instead of)
24
+ * importing whichever of these components the page actually uses :
25
+ *
26
+ * <link
27
+ * rel="stylesheet"
28
+ * href="node_modules/@eunomia/elements/dist/ssr/overlay-ssr.css"
29
+ * />
30
+ *
31
+ * `eun-drawer`/`eun-modal` are skipped whenever `open` is written
32
+ * explicitly in the server-rendered markup, so a dialog meant to be
33
+ * visible on first paint (a startup announcement, for instance) still
34
+ * renders — see the `open` attribute on the component's own doc page for
35
+ * the same requirement `animate-ssr.css` documents for `animation`, and
36
+ * `eun-collapse`'s own `open` attribute for the same reasoning there.
37
+ * `eun-dropdown-button`'s own trigger label (its default slot) and
38
+ * `eun-tooltip`'s own trigger (`slot="anchor"`) are never hidden, only
39
+ * their menu/panel content is.
40
+ */
41
+
42
+ eun-collapse:not(:defined):not([open]) > :not([slot]) {
43
+ display: none;
44
+ }
45
+
46
+ eun-drawer:not(:defined):not([open]) > *,
47
+ eun-modal:not(:defined):not([open]) > * {
48
+ display: none;
49
+ }
50
+
51
+ eun-dropdown-button:not(:defined) > [slot="items"] {
52
+ display: none;
53
+ }
54
+
55
+ eun-tooltip:not(:defined) > :not([slot="anchor"]) {
56
+ display: none;
57
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Optional light-DOM stylesheet for `<eun-sidebar>` in server-rendered
3
+ * pages (Next.js, or any framework/setup without Declarative Shadow DOM
4
+ * for Lit components). Closes the same SSR flash described in
5
+ * eun-toolbar's own SSR notes (see `toolbar-ssr.css`), but here it hits
6
+ * every instance, not just a mobile-only panel : `display: flex` and the
7
+ * sidebar's own width live in eun-sidebar's Shadow DOM, which doesn't
8
+ * exist yet in server-rendered HTML. An unregistered custom element
9
+ * defaults to `display: inline` with no layout of its own, so a
10
+ * server-rendered sidebar renders as a plain run of unstyled inline
11
+ * content (header, body, footer flowing one after another) first, then
12
+ * snaps into a proper flex column the instant the element upgrades. A
13
+ * sidebar meant to start `collapsed` (mini or fully hidden) makes this
14
+ * worse : that state lives in the same Shadow DOM too, so it renders at
15
+ * full width first, then shrinks down on upgrade instead of the other
16
+ * way around.
17
+ *
18
+ * This stylesheet lives in the host document instead, mirroring
19
+ * eun-sidebar's own resting layout through `:not(:defined)`, which is
20
+ * true from first paint and stops matching permanently the moment the
21
+ * browser upgrades the element — handing off to eun-sidebar's own Shadow
22
+ * DOM styles at exactly the point they take over, with no gap.
23
+ *
24
+ * Usage — link it in the page `<head>`, alongside (not instead of)
25
+ * importing "@eunomia/elements/sidebar.js" :
26
+ *
27
+ * <link
28
+ * rel="stylesheet"
29
+ * href="node_modules/@eunomia/elements/dist/ssr/sidebar-ssr.css"
30
+ * />
31
+ *
32
+ * `collapsed`/`collapse-mode`/`dragged-hidden` only take effect here when
33
+ * written explicitly in the server-rendered markup, same requirement
34
+ * `animate-ssr.css` documents for `animation` :
35
+ *
36
+ * <eun-sidebar collapsed collapse-mode="mini">...</eun-sidebar>
37
+ */
38
+
39
+ eun-sidebar:not(:defined) {
40
+ display: flex;
41
+ position: sticky;
42
+ top: 0;
43
+ flex-shrink: 0;
44
+ height: 100%;
45
+ box-sizing: border-box;
46
+ overflow: hidden;
47
+ width: var(--sidebar-width, 280px);
48
+ }
49
+
50
+ eun-sidebar[collapsed][collapse-mode="mini"]:not(:defined) {
51
+ width: var(--sidebar-mini-width, 64px);
52
+ }
53
+
54
+ eun-sidebar[collapsed][collapse-mode="hidden"]:not(:defined),
55
+ eun-sidebar[dragged-hidden]:not(:defined) {
56
+ width: 0px;
57
+ }