@progressive-development/pd-forms 0.9.2 → 1.0.1

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 (164) hide show
  1. package/LICENSE +21 -2
  2. package/README.md +56 -62
  3. package/dist/base/pd-base-input-element.d.ts +10 -10
  4. package/dist/base/pd-base-input-element.d.ts.map +1 -1
  5. package/dist/base/pd-base-input-element.js +8 -1
  6. package/dist/base/pd-base-ui-input.d.ts +41 -16
  7. package/dist/base/pd-base-ui-input.d.ts.map +1 -1
  8. package/dist/base/pd-base-ui-input.js +25 -6
  9. package/dist/base/pd-base-ui.js +0 -18
  10. package/dist/generated/locales/be.d.ts +3 -0
  11. package/dist/generated/locales/be.d.ts.map +1 -1
  12. package/dist/generated/locales/de.d.ts +3 -0
  13. package/dist/generated/locales/de.d.ts.map +1 -1
  14. package/dist/generated/locales/en.d.ts +3 -0
  15. package/dist/generated/locales/en.d.ts.map +1 -1
  16. package/dist/index.d.ts +4 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +6 -0
  19. package/dist/locales/be.js +4 -1
  20. package/dist/locales/de.js +4 -1
  21. package/dist/locales/en.js +4 -1
  22. package/dist/pd-button/PdButton.d.ts +172 -37
  23. package/dist/pd-button/PdButton.d.ts.map +1 -1
  24. package/dist/pd-button/PdButton.js +507 -71
  25. package/dist/pd-button/pd-button.stories.d.ts +82 -10
  26. package/dist/pd-button/pd-button.stories.d.ts.map +1 -1
  27. package/dist/pd-button-group/PdButtonGroup.d.ts +25 -0
  28. package/dist/pd-button-group/PdButtonGroup.d.ts.map +1 -1
  29. package/dist/pd-button-group/PdButtonGroup.js +52 -27
  30. package/dist/pd-button-group/pd-button-group.stories.d.ts +42 -17
  31. package/dist/pd-button-group/pd-button-group.stories.d.ts.map +1 -1
  32. package/dist/pd-button-select-group/PdButtonSelectGroup.d.ts +17 -3
  33. package/dist/pd-button-select-group/PdButtonSelectGroup.d.ts.map +1 -1
  34. package/dist/pd-button-select-group/PdButtonSelectGroup.js +23 -19
  35. package/dist/pd-button-select-group/pd-button-select-group.stories.d.ts +43 -18
  36. package/dist/pd-button-select-group/pd-button-select-group.stories.d.ts.map +1 -1
  37. package/dist/pd-checkbox/PdCheckbox.d.ts +23 -2
  38. package/dist/pd-checkbox/PdCheckbox.d.ts.map +1 -1
  39. package/dist/pd-checkbox/PdCheckbox.js +85 -21
  40. package/dist/pd-checkbox/pd-checkbox.stories.d.ts +43 -27
  41. package/dist/pd-checkbox/pd-checkbox.stories.d.ts.map +1 -1
  42. package/dist/pd-form-container/PdFormContainer.d.ts +30 -9
  43. package/dist/pd-form-container/PdFormContainer.d.ts.map +1 -1
  44. package/dist/pd-form-container/PdFormContainer.js +59 -8
  45. package/dist/pd-form-container/pd-form-container.stories.d.ts +49 -0
  46. package/dist/pd-form-container/pd-form-container.stories.d.ts.map +1 -0
  47. package/dist/pd-form-field/PdFormField.d.ts +35 -0
  48. package/dist/pd-form-field/PdFormField.d.ts.map +1 -0
  49. package/dist/pd-form-field/PdFormField.js +38 -0
  50. package/dist/pd-form-field/pd-form-field.d.ts +3 -0
  51. package/dist/pd-form-field/pd-form-field.d.ts.map +1 -0
  52. package/dist/pd-form-field/pd-form-field.stories.d.ts +40 -0
  53. package/dist/pd-form-field/pd-form-field.stories.d.ts.map +1 -0
  54. package/dist/pd-form-field.d.ts +2 -0
  55. package/dist/pd-form-field.js +8 -0
  56. package/dist/pd-form-fieldset/PdFormFieldset.d.ts +144 -0
  57. package/dist/pd-form-fieldset/PdFormFieldset.d.ts.map +1 -0
  58. package/dist/pd-form-fieldset/PdFormFieldset.js +364 -0
  59. package/dist/pd-form-fieldset/index.d.ts +2 -0
  60. package/dist/pd-form-fieldset/index.d.ts.map +1 -0
  61. package/dist/pd-form-fieldset/pd-form-fieldset.d.ts +3 -0
  62. package/dist/pd-form-fieldset/pd-form-fieldset.d.ts.map +1 -0
  63. package/dist/pd-form-fieldset/pd-form-fieldset.js +8 -0
  64. package/dist/pd-form-fieldset/pd-form-fieldset.stories.d.ts +38 -0
  65. package/dist/pd-form-fieldset/pd-form-fieldset.stories.d.ts.map +1 -0
  66. package/dist/pd-form-row/PdFormRow.d.ts +35 -5
  67. package/dist/pd-form-row/PdFormRow.d.ts.map +1 -1
  68. package/dist/pd-form-row/PdFormRow.js +135 -69
  69. package/dist/pd-form-row/pd-form-row.stories.d.ts +41 -25
  70. package/dist/pd-form-row/pd-form-row.stories.d.ts.map +1 -1
  71. package/dist/pd-generic-form/PdGenericForm.d.ts +50 -0
  72. package/dist/pd-generic-form/PdGenericForm.d.ts.map +1 -0
  73. package/dist/pd-generic-form/PdGenericForm.js +334 -0
  74. package/dist/pd-generic-form/pd-generic-form.d.ts +3 -0
  75. package/dist/pd-generic-form/pd-generic-form.d.ts.map +1 -0
  76. package/dist/pd-generic-form/pd-generic-form.stories.d.ts +35 -0
  77. package/dist/pd-generic-form/pd-generic-form.stories.d.ts.map +1 -0
  78. package/dist/pd-generic-form/pd-generic-form.styles.d.ts +2 -0
  79. package/dist/pd-generic-form/pd-generic-form.styles.d.ts.map +1 -0
  80. package/dist/pd-generic-form/pd-generic-form.styles.js +110 -0
  81. package/dist/pd-generic-form/pd-generic-form.test.d.ts +1 -0
  82. package/dist/pd-generic-form/pd-generic-form.test.d.ts.map +1 -0
  83. package/dist/pd-generic-form.d.ts +2 -0
  84. package/dist/pd-generic-form.js +8 -0
  85. package/dist/pd-hover-box/PdHoverBox.d.ts +61 -11
  86. package/dist/pd-hover-box/PdHoverBox.d.ts.map +1 -1
  87. package/dist/pd-hover-box/PdHoverBox.js +130 -28
  88. package/dist/pd-hover-box/pd-hover-box.stories.d.ts +28 -5
  89. package/dist/pd-hover-box/pd-hover-box.stories.d.ts.map +1 -1
  90. package/dist/pd-input/PdComboboxInput.d.ts +20 -0
  91. package/dist/pd-input/PdComboboxInput.d.ts.map +1 -0
  92. package/dist/pd-input/PdComboboxInput.js +67 -0
  93. package/dist/pd-input/PdInput.d.ts +33 -15
  94. package/dist/pd-input/PdInput.d.ts.map +1 -1
  95. package/dist/pd-input/PdInput.js +49 -21
  96. package/dist/pd-input/pd-input.stories.d.ts +71 -35
  97. package/dist/pd-input/pd-input.stories.d.ts.map +1 -1
  98. package/dist/pd-input-area/PdInputArea.d.ts +19 -6
  99. package/dist/pd-input-area/PdInputArea.d.ts.map +1 -1
  100. package/dist/pd-input-area/PdInputArea.js +17 -15
  101. package/dist/pd-input-area/pd-input-area.stories.d.ts +65 -52
  102. package/dist/pd-input-area/pd-input-area.stories.d.ts.map +1 -1
  103. package/dist/pd-input-file/PdInputFile.d.ts +24 -0
  104. package/dist/pd-input-file/PdInputFile.d.ts.map +1 -1
  105. package/dist/pd-input-file/PdInputFile.js +53 -22
  106. package/dist/pd-input-file/pd-input-file.stories.d.ts +51 -47
  107. package/dist/pd-input-file/pd-input-file.stories.d.ts.map +1 -1
  108. package/dist/pd-input-time/PdInputTime.d.ts +21 -0
  109. package/dist/pd-input-time/PdInputTime.d.ts.map +1 -1
  110. package/dist/pd-input-time/PdInputTime.js +48 -22
  111. package/dist/pd-input-time/pd-input-time.stories.d.ts +94 -0
  112. package/dist/pd-input-time/pd-input-time.stories.d.ts.map +1 -0
  113. package/dist/pd-panel-button/PdPanelButton.d.ts +50 -34
  114. package/dist/pd-panel-button/PdPanelButton.d.ts.map +1 -1
  115. package/dist/pd-panel-button/PdPanelButton.js +149 -262
  116. package/dist/pd-panel-button/pd-panel-button.stories.d.ts +55 -25
  117. package/dist/pd-panel-button/pd-panel-button.stories.d.ts.map +1 -1
  118. package/dist/pd-radio-group/PdRadioGroup.d.ts +14 -0
  119. package/dist/pd-radio-group/PdRadioGroup.d.ts.map +1 -1
  120. package/dist/pd-radio-group/PdRadioGroup.js +48 -11
  121. package/dist/pd-radio-group/pd-radio-group.stories.d.ts +37 -7
  122. package/dist/pd-radio-group/pd-radio-group.stories.d.ts.map +1 -1
  123. package/dist/pd-range/PdRange.d.ts +22 -2
  124. package/dist/pd-range/PdRange.d.ts.map +1 -1
  125. package/dist/pd-range/PdRange.js +54 -43
  126. package/dist/pd-range/pd-range.stories.d.ts +49 -7
  127. package/dist/pd-range/pd-range.stories.d.ts.map +1 -1
  128. package/dist/pd-select/PdSelect.d.ts +16 -4
  129. package/dist/pd-select/PdSelect.d.ts.map +1 -1
  130. package/dist/pd-select/PdSelect.js +23 -21
  131. package/dist/pd-select/pd-select.stories.d.ts +56 -35
  132. package/dist/pd-select/pd-select.stories.d.ts.map +1 -1
  133. package/dist/pd-suggestion-box/PdSuggestionBox.d.ts +74 -0
  134. package/dist/pd-suggestion-box/PdSuggestionBox.d.ts.map +1 -0
  135. package/dist/pd-suggestion-box/PdSuggestionBox.js +277 -0
  136. package/dist/pd-suggestion-box/PdSuggestionPanel.d.ts +42 -0
  137. package/dist/pd-suggestion-box/PdSuggestionPanel.d.ts.map +1 -0
  138. package/dist/pd-suggestion-box/PdSuggestionPanel.js +227 -0
  139. package/dist/pd-suggestion-box/pd-suggestion-box.d.ts +3 -0
  140. package/dist/pd-suggestion-box/pd-suggestion-box.d.ts.map +1 -0
  141. package/dist/pd-suggestion-box/pd-suggestion-box.stories.d.ts +79 -0
  142. package/dist/pd-suggestion-box/pd-suggestion-box.stories.d.ts.map +1 -0
  143. package/dist/pd-suggestion-box.d.ts +2 -0
  144. package/dist/pd-suggestion-box.js +8 -0
  145. package/dist/pd-utils/dist/position-helper.js +35 -0
  146. package/dist/stories/pd-forms-overview.stories.d.ts +48 -0
  147. package/dist/stories/pd-forms-overview.stories.d.ts.map +1 -0
  148. package/dist/stories/story-helpers.d.ts +10 -0
  149. package/dist/stories/story-helpers.d.ts.map +1 -0
  150. package/dist/styles/shared-input-field-styles.d.ts.map +1 -1
  151. package/dist/styles/shared-input-field-styles.js +13 -19
  152. package/dist/styles/shared-input-styles.d.ts.map +1 -1
  153. package/dist/styles/shared-input-styles.js +18 -14
  154. package/dist/types.d.ts +11 -0
  155. package/dist/types.d.ts.map +1 -1
  156. package/package.json +11 -4
  157. package/dist/pd-form-container/form-container.stories.d.ts +0 -28
  158. package/dist/pd-form-container/form-container.stories.d.ts.map +0 -1
  159. package/dist/pd-form-container/form-container2.stories.d.ts +0 -8
  160. package/dist/pd-form-container/form-container2.stories.d.ts.map +0 -1
  161. package/dist/pd-form-container/form-container3.stories.d.ts +0 -11
  162. package/dist/pd-form-container/form-container3.stories.d.ts.map +0 -1
  163. package/dist/stories/01_index.stories.d.ts +0 -58
  164. package/dist/stories/01_index.stories.d.ts.map +0 -1
@@ -1,6 +1,8 @@
1
- import { css, html } from 'lit';
2
- import { property } from 'lit/decorators.js';
1
+ import { css, nothing, html } from 'lit';
2
+ import { property, state } from 'lit/decorators.js';
3
+ import { classMap } from 'lit/directives/class-map.js';
3
4
  import { PdBaseUI } from '../base/pd-base-ui.js';
5
+ import '@progressive-development/pd-icon/pd-icon';
4
6
 
5
7
  var __defProp = Object.defineProperty;
6
8
  var __decorateClass = (decorators, target, key, kind) => {
@@ -16,122 +18,526 @@ class PdButton extends PdBaseUI {
16
18
  super(...arguments);
17
19
  this.primary = false;
18
20
  this.gradient = false;
21
+ this.selected = false;
19
22
  this.disabled = false;
23
+ this.loading = false;
24
+ this.fullWidth = false;
20
25
  this.text = "Ok";
26
+ this.iconPosition = "start";
27
+ this.size = "md";
28
+ this.type = "button";
29
+ this._isPressed = false;
21
30
  }
22
31
  static {
32
+ // ============================================================================
33
+ // STYLES
34
+ // ============================================================================
23
35
  this.styles = [
24
36
  PdBaseUI.styles,
25
37
  css`
38
+ /* ========================================
39
+ HOST ELEMENT
40
+ ======================================== */
26
41
  :host {
42
+ display: inline-block;
27
43
  font-family: var(--pd-default-font-title-family);
28
- font-size: var(--pd-button-font-size, 1em);
29
- font-weight: var(--pd-button-font-weight, normal);
30
- /*
31
- height: 100%;
32
- width: 100%; => Ohne diese Angabe eht die % Angaben icht
33
- */
34
-
35
- margin: 0.5rem;
36
- margin-left: 0;
37
- pointer-events: none;
38
44
  }
39
45
 
40
- .button-div {
41
- display: flex;
42
- justify-content: center;
43
- align-items: center;
44
- width: var(--pd-button-width, 140px);
45
- height: var(--pd-button-height, 2rem);
46
- border-radius: var(--pd-border-radius, 1px);
47
- background-color: var(--pd-button-bg-col, var(--pd-default-dark-col));
48
- color: var(--pd-button-font-col, var(--pd-default-bg-col));
49
- border: var(--pd-button-border, 0);
50
- cursor: pointer;
51
- box-shadow: var(--pd-button-box-shadow, none);
52
- pointer-events: all;
46
+ :host([full-width]) {
47
+ display: block;
48
+ width: 100%;
49
+ }
50
+
51
+ /* Grid span mode - fill grid cell width */
52
+ :host([span]) {
53
+ display: block;
54
+ width: 100%;
55
+ }
56
+
57
+ /* Add label-height padding to align with labeled inputs in form-row */
58
+ :host([row-label-padding]) {
59
+ padding-top: var(--pd-input-label-font-size, 1em);
60
+ }
61
+
62
+ :host([span]) button {
63
+ width: 100%;
64
+ /* Fit Inputs in PdFormRow */
65
+ --_height: var(--pd-input-field-height, 40px);
66
+ --_min-height: var(--pd-input-field-height, 40px);
67
+ }
68
+
69
+ /* Size presets via scale - these set --pd-button-scale which is read by button */
70
+ :host([size="sm"]) {
71
+ --pd-button-scale: 0.75;
72
+ }
73
+ :host([size="lg"]) {
74
+ --pd-button-scale: 1.25;
53
75
  }
76
+ :host([size="xl"]) {
77
+ --pd-button-scale: 1.5;
78
+ }
79
+ /* Note: size="md" intentionally omitted so external --pd-button-scale can work */
80
+
81
+ /* ========================================
82
+ BUTTON ELEMENT
83
+ ======================================== */
84
+ button {
85
+ /* Scale factor - read from host or external, default 1 */
86
+ --_scale: var(--pd-button-scale, 1);
54
87
 
55
- :host(:not([disabled])) .button-div:hover {
56
- box-shadow: var(
57
- --pd-button-box-shadow-hover,
58
- -1px 1px 2px var(--pd-default-dark-col)
88
+ /* Scale-based dimensions */
89
+ --_height: var(--pd-button-height, calc(2.5rem * var(--_scale)));
90
+ --_min-height: var(
91
+ --pd-button-min-height,
92
+ 44px
93
+ ); /* Touch target minimum */
94
+ --_padding-x: var(--pd-button-padding, calc(1rem * var(--_scale)));
95
+ --_padding-y: calc(0.5rem * var(--_scale));
96
+ --_font-size: var(--pd-button-font-size, calc(1rem * var(--_scale)));
97
+ --_border-radius: var(--pd-button-border-radius, var(--pd-radius-md));
98
+ --_gap: var(--pd-button-gap, calc(0.5rem * var(--_scale)));
99
+ /* Backward compatibility: --pd-button-width maps to --pd-button-min-width */
100
+ --_width: var(--pd-button-width, var(--pd-button-min-width, auto));
101
+
102
+ /* Colors - Default state (matches pd-panel-button) */
103
+ --_bg-col: var(--pd-button-bg-col, var(--pd-default-col));
104
+ --_font-col: var(--pd-button-font-col, var(--pd-on-primary-col));
105
+ --_border-col: var(
106
+ --pd-button-border-col,
107
+ var(--pd-default-darker-col)
59
108
  );
60
- background-color: var(
109
+
110
+ /* Colors - Hover state */
111
+ --_bg-col-hover: var(
61
112
  --pd-button-bg-col-hover,
62
113
  var(--pd-default-hover-col)
63
114
  );
64
- color: var(--pd-button-font-col-hover, var(--pd-default-dark-col));
65
- transition: background-color 0.4s ease 0s;
66
- --pd-button-border: var(--pd-button-border-hover);
67
- }
115
+ --_font-col-hover: var(
116
+ --pd-button-font-col-hover,
117
+ var(--pd-on-secondary-col)
118
+ );
68
119
 
69
- :host(:not([disabled])[primary]) .button-div:hover {
70
- background-color: var(
120
+ /* Colors - Primary state (matches pd-panel-button) */
121
+ --_primary-bg-col: var(
122
+ --pd-button-primary-bg-col,
123
+ var(--pd-secondary-col)
124
+ );
125
+ --_primary-font-col: var(
126
+ --pd-button-primary-font-col,
127
+ var(--pd-on-secondary-col)
128
+ );
129
+ --_primary-bg-col-hover: var(
71
130
  --pd-button-primary-bg-col-hover,
72
- var(--pd-default-hover-col)
131
+ var(--pd-secondary-dark-col)
73
132
  );
74
- color: var(
133
+ --_primary-font-col-hover: var(
75
134
  --pd-button-primary-font-col-hover,
76
- var(--pd-default-bg-col)
135
+ var(--pd-on-primary-col)
77
136
  );
78
- }
79
137
 
80
- :host([primary]) .button-div {
81
- background-color: var(
82
- --pd-button-primary-bg-col,
138
+ /* Colors - Disabled state (matches pd-panel-button) */
139
+ --_bg-col-disabled: var(
140
+ --pd-button-bg-col-disabled,
141
+ var(--pd-default-disabled-col)
142
+ );
143
+ --_font-col-disabled: var(
144
+ --pd-button-font-col-disabled,
145
+ var(--pd-on-disabled-col)
146
+ );
147
+
148
+ /* Colors - Selected state (matches pd-panel-button) */
149
+ --_selected-bg-col: var(
150
+ --pd-button-selected-bg-col,
151
+ var(--pd-secondary-light-col)
152
+ );
153
+ --_selected-font-col: var(
154
+ --pd-button-selected-font-col,
155
+ var(--pd-default-col)
156
+ );
157
+ --_selected-shadow: var(
158
+ --pd-button-selected-shadow,
159
+ var(--pd-shadow-inset-md),
160
+ var(--pd-shadow-outline)
161
+ );
162
+
163
+ /* Gradient colors */
164
+ --_gradient-start: var(
165
+ --pd-button-gradient-start,
83
166
  var(--pd-default-col)
84
167
  );
85
- color: var(--pd-button-primary-font-col, var(--pd-default-bg-col));
168
+ --_gradient-end: var(--pd-button-gradient-end, var(--pd-secondary-col));
169
+
170
+ /* Focus styling */
171
+ --_focus-color: var(--pd-focus-ring-col);
172
+ --_focus-width: 2px;
173
+ --_focus-offset: 2px;
174
+
175
+ /* Transition timing (matches pd-panel-button) */
176
+ --_transition-duration: 0.3s;
177
+
178
+ /* Reset native button styles */
179
+ all: unset;
180
+ box-sizing: border-box;
181
+
182
+ /* Layout */
183
+ display: inline-flex;
184
+ align-items: center;
185
+ justify-content: center;
186
+ gap: var(--_gap);
187
+
188
+ /* Sizing - use min-height instead of height to allow growth when text wraps */
189
+ width: var(--_width);
190
+ min-width: var(--_width);
191
+ min-height: max(var(--_height), var(--_min-height));
192
+ padding: var(--_padding-y) var(--_padding-x);
193
+
194
+ /* Typography */
195
+ font-family: inherit;
196
+ font-size: var(--_font-size);
197
+ font-weight: var(--pd-button-font-weight, 600);
198
+ line-height: 1.2;
199
+ text-align: center;
200
+ white-space: var(--pd-button-white-space, nowrap);
201
+
202
+ /* Appearance */
203
+ background-color: var(--_bg-col);
204
+ background-image: linear-gradient(hsla(0, 0%, 100%, 0.15), transparent);
205
+ color: var(--_font-col);
206
+ border: 1px solid var(--_border-col);
207
+ border-radius: var(--_border-radius);
208
+ text-shadow: var(--pd-text-shadow-sm);
209
+
210
+ /* Interaction */
211
+ cursor: pointer;
212
+ user-select: none;
213
+ -webkit-tap-highlight-color: transparent;
214
+
215
+ /* Transitions (matches pd-panel-button) */
216
+ transition:
217
+ background-color var(--_transition-duration) ease,
218
+ color var(--_transition-duration) ease,
219
+ border-color var(--_transition-duration) ease,
220
+ box-shadow var(--_transition-duration) ease;
221
+ }
222
+
223
+ :host([full-width]) button {
224
+ width: 100%;
225
+ }
226
+
227
+ /* ========================================
228
+ HOVER STATE
229
+ ======================================== */
230
+ button:hover:not(:disabled) {
231
+ background-color: var(--_bg-col-hover);
232
+ color: var(--_font-col-hover);
233
+ }
234
+
235
+ /* ========================================
236
+ ACTIVE/PRESSED STATE
237
+ Note: Using only inset box-shadow without transform
238
+ to prevent visual jumping on click.
239
+ ======================================== */
240
+ button:active:not(:disabled),
241
+ button.pressed:not(:disabled) {
242
+ box-shadow: var(--pd-shadow-inset-sm);
86
243
  }
87
244
 
88
- :host([gradient]) .button-div {
245
+ /* ========================================
246
+ FOCUS STATE (keyboard navigation)
247
+ ======================================== */
248
+ button:focus-visible {
249
+ outline: var(--_focus-width) solid var(--_focus-color);
250
+ outline-offset: var(--_focus-offset);
251
+ }
252
+
253
+ /* ========================================
254
+ PRIMARY VARIANT
255
+ ======================================== */
256
+ :host([primary]) button {
257
+ background-color: var(--_primary-bg-col);
258
+ color: var(--_primary-font-col);
259
+ text-shadow: none;
260
+ }
261
+
262
+ :host([primary]) button:hover:not(:disabled) {
263
+ background-color: var(--_primary-bg-col-hover);
264
+ color: var(--_primary-font-col-hover);
265
+ }
266
+
267
+ /* ========================================
268
+ GRADIENT VARIANT
269
+ ======================================== */
270
+ :host([gradient]) button {
89
271
  background: linear-gradient(
90
272
  to right,
91
- var(--my-background-gradient-color, red) 0%,
92
- var(--my-background-color, blue) 100%
273
+ var(--_gradient-start) 0%,
274
+ var(--_gradient-end) 100%
93
275
  );
276
+ border-color: transparent;
94
277
  }
95
278
 
96
- :host([disabled]) .button-div {
97
- cursor: auto;
98
- border-color: var(--pd-default-disabled-col);
99
- background-color: var(
100
- --pd-button-bg-col-disabled,
279
+ :host([gradient]) button:hover:not(:disabled) {
280
+ opacity: 0.9;
281
+ background: linear-gradient(
282
+ to right,
283
+ var(--_gradient-start) 0%,
284
+ var(--_gradient-end) 100%
285
+ );
286
+ }
287
+
288
+ /* ========================================
289
+ SELECTED STATE (matches pd-panel-button)
290
+ Used for toggle buttons and button groups.
291
+ ======================================== */
292
+ :host([selected]:not([disabled]):not([loading])) button {
293
+ background-color: var(--_selected-bg-col);
294
+ color: var(--_selected-font-col);
295
+ --pd-icon-col: var(--_selected-font-col);
296
+ --pd-icon-col-active: var(--_selected-font-col);
297
+ box-shadow: var(--_selected-shadow);
298
+ text-shadow: none;
299
+ }
300
+
301
+ :host([selected]:not([disabled]):not([loading])) button:hover {
302
+ background-color: var(--_selected-bg-col);
303
+ opacity: 0.9;
304
+ }
305
+
306
+ /* ========================================
307
+ DISABLED STATE (matches pd-panel-button)
308
+ ======================================== */
309
+ button:disabled,
310
+ :host([loading]) button {
311
+ background: linear-gradient(
312
+ to bottom,
313
+ var(--_bg-col-disabled),
101
314
  var(--pd-default-disabled-col)
102
315
  );
103
- color: var(--pd-button-font-col-disabled, black);
104
- --pd-button-border: var(--pd-button-border-disabled);
316
+ color: var(--_font-col-disabled);
317
+ border-color: var(--pd-default-disabled-col);
318
+ cursor: not-allowed;
319
+ opacity: 0.6;
320
+ text-shadow: none;
321
+ pointer-events: none;
105
322
  }
106
323
 
107
- a {
324
+ /* ========================================
325
+ LOADING STATE
326
+ ======================================== */
327
+ .loader {
108
328
  display: inline-block;
109
- text-decoration: none;
110
- white-space: nowrap;
111
- margin: 0.5rem;
112
- pointer-events: none;
329
+ width: calc(1em * var(--_scale));
330
+ height: calc(1em * var(--_scale));
331
+ border: 2px solid var(--pd-secondary-col);
332
+ border-top-color: var(--pd-secondary-light-col);
333
+ border-radius: 50%;
334
+ animation: spin 1s linear infinite;
335
+ }
336
+
337
+ @keyframes spin {
338
+ to {
339
+ transform: rotate(360deg);
340
+ }
341
+ }
342
+
343
+ /* ========================================
344
+ SLOTS
345
+ ======================================== */
346
+ ::slotted(*) {
347
+ display: inline-flex;
348
+ align-items: center;
349
+ }
350
+
351
+ .label {
352
+ display: inline-block;
353
+ }
354
+
355
+ /* ========================================
356
+ ICON STYLING
357
+ ======================================== */
358
+ .button-icon {
359
+ --pd-icon-size: var(
360
+ --pd-button-icon-size,
361
+ calc(1.25em * var(--_scale))
362
+ );
363
+ display: inline-flex;
364
+ align-items: center;
365
+ justify-content: center;
366
+ flex-shrink: 0;
367
+ }
368
+
369
+ /* Icon color inherits from button text color */
370
+ .button-icon {
371
+ --pd-icon-col: currentColor;
372
+ --pd-icon-col-active: currentColor;
373
+ }
374
+
375
+ /* Icon-only button adjustments */
376
+ :host([icon-only]) button {
377
+ padding: var(--_padding-y);
378
+ aspect-ratio: 1;
379
+ min-width: var(--_min-height);
113
380
  }
114
381
  `
115
382
  ];
116
383
  }
384
+ // ============================================================================
385
+ // RENDER
386
+ // ============================================================================
117
387
  render() {
388
+ const isInteractive = !this.disabled && !this.loading;
389
+ const isIconOnly = this.icon && !this.text;
390
+ const showIconAtStart = this.icon && this.iconPosition === "start";
391
+ const showIconAtEnd = this.icon && this.iconPosition === "end";
392
+ const buttonClasses = {
393
+ pressed: this._isPressed
394
+ };
395
+ if (isIconOnly) {
396
+ this.setAttribute("icon-only", "");
397
+ } else {
398
+ this.removeAttribute("icon-only");
399
+ }
118
400
  return html`
119
- <div class="button-div" @click=${this._handleClick}>
120
- <a ?disabled=${this.disabled}>${this.text}</a>
121
- </div>
401
+ <button
402
+ part="button"
403
+ type="${this.type}"
404
+ ?disabled="${this.disabled || this.loading}"
405
+ aria-disabled="${this.disabled || this.loading}"
406
+ aria-busy="${this.loading}"
407
+ .ariaPressed="${this.selected ? "true" : null}"
408
+ aria-label="${isIconOnly ? this.iconLabel || this.icon : nothing}"
409
+ aria-expanded="${this.buttonAriaExpanded}"
410
+ aria-haspopup="${this.buttonAriaHasPopup}"
411
+ aria-controls="${this.buttonAriaControls}"
412
+ class="${classMap(buttonClasses)}"
413
+ @click="${this.handleClick}"
414
+ @mousedown="${this._handleMouseDown}"
415
+ @mouseup="${this._handleMouseUp}"
416
+ @mouseleave="${this._handleMouseUp}"
417
+ @keydown="${this._handleKeyDown}"
418
+ @keyup="${this._handleKeyUp}"
419
+ >
420
+ ${this.loading ? html`<span class="loader" part="loader"></span>` : html`
421
+ ${showIconAtStart ? this.renderIcon() : nothing}
422
+ <slot name="prefix"></slot>
423
+ `}
424
+ ${this.text ? html`<span class="label" part="label">${this.text}</span>` : nothing}
425
+ ${isInteractive ? html`
426
+ <slot name="suffix"></slot>
427
+ ${showIconAtEnd ? this.renderIcon() : nothing}
428
+ ${this.renderSuffixContent()}
429
+ ` : nothing}
430
+ </button>
431
+ ${this.renderAfterButton()}
122
432
  `;
123
433
  }
124
- _handleClick() {
125
- if (!this.disabled) {
126
- this.dispatchEvent(
127
- new CustomEvent("button-clicked", {
128
- detail: this.value,
129
- bubbles: true,
130
- composed: true
131
- })
132
- );
434
+ // ============================================================================
435
+ // PROTECTED RENDER HOOKS (for subclasses like PdPanelButton)
436
+ // ============================================================================
437
+ /**
438
+ * Override point for aria-expanded attribute on the button.
439
+ * Used by PdPanelButton to indicate panel open state.
440
+ */
441
+ get buttonAriaExpanded() {
442
+ return "undefined";
443
+ }
444
+ /**
445
+ * Override point for aria-haspopup attribute on the button.
446
+ * Used by PdPanelButton to indicate dropdown behavior.
447
+ */
448
+ get buttonAriaHasPopup() {
449
+ return "false";
450
+ }
451
+ /**
452
+ * Override point for aria-controls attribute on the button.
453
+ * Used by PdPanelButton to link button with panel.
454
+ */
455
+ get buttonAriaControls() {
456
+ return nothing;
457
+ }
458
+ /**
459
+ * Override point for suffix content inside the button.
460
+ * Used by PdPanelButton for the toggle arrow.
461
+ */
462
+ renderSuffixContent() {
463
+ return nothing;
464
+ }
465
+ /**
466
+ * Override point for content rendered after the button element.
467
+ * Used by PdPanelButton for the dropdown panel.
468
+ */
469
+ renderAfterButton() {
470
+ return nothing;
471
+ }
472
+ /**
473
+ * Renders the icon element. Protected for subclass access.
474
+ */
475
+ renderIcon() {
476
+ if (!this.icon) return nothing;
477
+ return html`
478
+ <pd-icon class="button-icon" part="icon" icon="${this.icon}"></pd-icon>
479
+ `;
480
+ }
481
+ // ============================================================================
482
+ // EVENT HANDLERS
483
+ // ============================================================================
484
+ /**
485
+ * Handles click events on the button.
486
+ * Protected so subclasses like PdPanelButton can override.
487
+ */
488
+ handleClick() {
489
+ if (!this.disabled && !this.loading) {
490
+ this._emitButtonClicked();
491
+ }
492
+ }
493
+ /**
494
+ * Handles mousedown for visual pressed state.
495
+ */
496
+ _handleMouseDown() {
497
+ if (!this.disabled && !this.loading) {
498
+ this._isPressed = true;
499
+ }
500
+ }
501
+ /**
502
+ * Handles mouseup/mouseleave to reset pressed state.
503
+ */
504
+ _handleMouseUp() {
505
+ this._isPressed = false;
506
+ }
507
+ /**
508
+ * Handles keydown events for keyboard activation.
509
+ */
510
+ _handleKeyDown(event) {
511
+ if (this.disabled || this.loading) return;
512
+ if (event.key === "Enter" || event.key === " ") {
513
+ event.preventDefault();
514
+ this._isPressed = true;
515
+ }
516
+ }
517
+ /**
518
+ * Handles keyup events to complete keyboard activation.
519
+ */
520
+ _handleKeyUp(event) {
521
+ if (this.disabled || this.loading) return;
522
+ if (event.key === "Enter" || event.key === " ") {
523
+ event.preventDefault();
524
+ this._isPressed = false;
525
+ this.handleClick();
133
526
  }
134
527
  }
528
+ /**
529
+ * Dispatches the button-clicked event.
530
+ * @fires button-clicked
531
+ */
532
+ _emitButtonClicked() {
533
+ this.dispatchEvent(
534
+ new CustomEvent("button-clicked", {
535
+ detail: this.value,
536
+ bubbles: true,
537
+ composed: true
538
+ })
539
+ );
540
+ }
135
541
  }
136
542
  __decorateClass([
137
543
  property({ type: Boolean, reflect: true })
@@ -139,14 +545,44 @@ __decorateClass([
139
545
  __decorateClass([
140
546
  property({ type: Boolean, reflect: true })
141
547
  ], PdButton.prototype, "gradient");
548
+ __decorateClass([
549
+ property({ type: Boolean, reflect: true })
550
+ ], PdButton.prototype, "selected");
142
551
  __decorateClass([
143
552
  property({ type: Boolean, reflect: true })
144
553
  ], PdButton.prototype, "disabled");
554
+ __decorateClass([
555
+ property({ type: Boolean, reflect: true })
556
+ ], PdButton.prototype, "loading");
557
+ __decorateClass([
558
+ property({ type: Boolean, reflect: true, attribute: "full-width" })
559
+ ], PdButton.prototype, "fullWidth");
145
560
  __decorateClass([
146
561
  property({ type: String })
147
562
  ], PdButton.prototype, "text");
563
+ __decorateClass([
564
+ property({ type: String })
565
+ ], PdButton.prototype, "icon");
566
+ __decorateClass([
567
+ property({ type: String, attribute: "icon-label" })
568
+ ], PdButton.prototype, "iconLabel");
569
+ __decorateClass([
570
+ property({ type: String, attribute: "icon-position" })
571
+ ], PdButton.prototype, "iconPosition");
148
572
  __decorateClass([
149
573
  property({ type: String })
150
574
  ], PdButton.prototype, "value");
575
+ __decorateClass([
576
+ property({ type: String, reflect: true })
577
+ ], PdButton.prototype, "size");
578
+ __decorateClass([
579
+ property({ type: String })
580
+ ], PdButton.prototype, "type");
581
+ __decorateClass([
582
+ property({ type: String, reflect: true })
583
+ ], PdButton.prototype, "span");
584
+ __decorateClass([
585
+ state()
586
+ ], PdButton.prototype, "_isPressed");
151
587
 
152
588
  export { PdButton };