@progressive-development/pd-forms 0.9.2 → 1.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.
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 +171 -37
  23. package/dist/pd-button/PdButton.d.ts.map +1 -1
  24. package/dist/pd-button/PdButton.js +502 -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,521 @@ 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
131
  var(--pd-default-hover-col)
73
132
  );
74
- color: var(
75
- --pd-button-primary-font-col-hover,
76
- var(--pd-default-bg-col)
133
+
134
+ /* Colors - Disabled state (matches pd-panel-button) */
135
+ --_bg-col-disabled: var(
136
+ --pd-button-bg-col-disabled,
137
+ var(--pd-default-disabled-col)
138
+ );
139
+ --_font-col-disabled: var(
140
+ --pd-button-font-col-disabled,
141
+ var(--pd-on-disabled-col)
77
142
  );
78
- }
79
143
 
80
- :host([primary]) .button-div {
81
- background-color: var(
82
- --pd-button-primary-bg-col,
144
+ /* Colors - Selected state (matches pd-panel-button) */
145
+ --_selected-bg-col: var(
146
+ --pd-button-selected-bg-col,
147
+ var(--pd-secondary-light-col)
148
+ );
149
+ --_selected-font-col: var(
150
+ --pd-button-selected-font-col,
83
151
  var(--pd-default-col)
84
152
  );
85
- color: var(--pd-button-primary-font-col, var(--pd-default-bg-col));
153
+ --_selected-shadow: var(
154
+ --pd-button-selected-shadow,
155
+ var(--pd-shadow-inset-md),
156
+ var(--pd-shadow-outline)
157
+ );
158
+
159
+ /* Gradient colors */
160
+ --_gradient-start: var(
161
+ --pd-button-gradient-start,
162
+ var(--pd-default-col)
163
+ );
164
+ --_gradient-end: var(--pd-button-gradient-end, var(--pd-secondary-col));
165
+
166
+ /* Focus styling */
167
+ --_focus-color: var(--pd-focus-ring-col);
168
+ --_focus-width: 2px;
169
+ --_focus-offset: 2px;
170
+
171
+ /* Transition timing (matches pd-panel-button) */
172
+ --_transition-duration: 0.3s;
173
+
174
+ /* Reset native button styles */
175
+ all: unset;
176
+ box-sizing: border-box;
177
+
178
+ /* Layout */
179
+ display: inline-flex;
180
+ align-items: center;
181
+ justify-content: center;
182
+ gap: var(--_gap);
183
+
184
+ /* Sizing - use min-height instead of height to allow growth when text wraps */
185
+ width: var(--_width);
186
+ min-width: var(--_width);
187
+ min-height: max(var(--_height), var(--_min-height));
188
+ padding: var(--_padding-y) var(--_padding-x);
189
+
190
+ /* Typography */
191
+ font-family: inherit;
192
+ font-size: var(--_font-size);
193
+ font-weight: var(--pd-button-font-weight, 600);
194
+ line-height: 1.2;
195
+ text-align: center;
196
+ white-space: var(--pd-button-white-space, nowrap);
197
+
198
+ /* Appearance */
199
+ background-color: var(--_bg-col);
200
+ background-image: linear-gradient(hsla(0, 0%, 100%, 0.15), transparent);
201
+ color: var(--_font-col);
202
+ border: 1px solid var(--_border-col);
203
+ border-radius: var(--_border-radius);
204
+ text-shadow: var(--pd-text-shadow-sm);
205
+
206
+ /* Interaction */
207
+ cursor: pointer;
208
+ user-select: none;
209
+ -webkit-tap-highlight-color: transparent;
210
+
211
+ /* Transitions (matches pd-panel-button) */
212
+ transition:
213
+ background-color var(--_transition-duration) ease,
214
+ color var(--_transition-duration) ease,
215
+ border-color var(--_transition-duration) ease,
216
+ box-shadow var(--_transition-duration) ease;
86
217
  }
87
218
 
88
- :host([gradient]) .button-div {
219
+ :host([full-width]) button {
220
+ width: 100%;
221
+ }
222
+
223
+ /* ========================================
224
+ HOVER STATE
225
+ ======================================== */
226
+ button:hover:not(:disabled) {
227
+ background-color: var(--_bg-col-hover);
228
+ color: var(--_font-col-hover);
229
+ }
230
+
231
+ /* ========================================
232
+ ACTIVE/PRESSED STATE
233
+ Note: Using only inset box-shadow without transform
234
+ to prevent visual jumping on click.
235
+ ======================================== */
236
+ button:active:not(:disabled),
237
+ button.pressed:not(:disabled) {
238
+ box-shadow: var(--pd-shadow-inset-sm);
239
+ }
240
+
241
+ /* ========================================
242
+ FOCUS STATE (keyboard navigation)
243
+ ======================================== */
244
+ button:focus-visible {
245
+ outline: var(--_focus-width) solid var(--_focus-color);
246
+ outline-offset: var(--_focus-offset);
247
+ }
248
+
249
+ /* ========================================
250
+ PRIMARY VARIANT
251
+ ======================================== */
252
+ :host([primary]) button {
253
+ background-color: var(--_primary-bg-col);
254
+ color: var(--_primary-font-col);
255
+ text-shadow: none;
256
+ }
257
+
258
+ :host([primary]) button:hover:not(:disabled) {
259
+ background-color: var(--_primary-bg-col-hover);
260
+ }
261
+
262
+ /* ========================================
263
+ GRADIENT VARIANT
264
+ ======================================== */
265
+ :host([gradient]) button {
89
266
  background: linear-gradient(
90
267
  to right,
91
- var(--my-background-gradient-color, red) 0%,
92
- var(--my-background-color, blue) 100%
268
+ var(--_gradient-start) 0%,
269
+ var(--_gradient-end) 100%
93
270
  );
271
+ border-color: transparent;
94
272
  }
95
273
 
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,
274
+ :host([gradient]) button:hover:not(:disabled) {
275
+ opacity: 0.9;
276
+ background: linear-gradient(
277
+ to right,
278
+ var(--_gradient-start) 0%,
279
+ var(--_gradient-end) 100%
280
+ );
281
+ }
282
+
283
+ /* ========================================
284
+ SELECTED STATE (matches pd-panel-button)
285
+ Used for toggle buttons and button groups.
286
+ ======================================== */
287
+ :host([selected]:not([disabled]):not([loading])) button {
288
+ background-color: var(--_selected-bg-col);
289
+ color: var(--_selected-font-col);
290
+ --pd-icon-col: var(--_selected-font-col);
291
+ --pd-icon-col-active: var(--_selected-font-col);
292
+ box-shadow: var(--_selected-shadow);
293
+ text-shadow: none;
294
+ }
295
+
296
+ :host([selected]:not([disabled]):not([loading])) button:hover {
297
+ background-color: var(--_selected-bg-col);
298
+ opacity: 0.9;
299
+ }
300
+
301
+ /* ========================================
302
+ DISABLED STATE (matches pd-panel-button)
303
+ ======================================== */
304
+ button:disabled,
305
+ :host([loading]) button {
306
+ background: linear-gradient(
307
+ to bottom,
308
+ var(--_bg-col-disabled),
101
309
  var(--pd-default-disabled-col)
102
310
  );
103
- color: var(--pd-button-font-col-disabled, black);
104
- --pd-button-border: var(--pd-button-border-disabled);
311
+ color: var(--_font-col-disabled);
312
+ border-color: var(--pd-default-disabled-col);
313
+ cursor: not-allowed;
314
+ opacity: 0.6;
315
+ text-shadow: none;
316
+ pointer-events: none;
105
317
  }
106
318
 
107
- a {
319
+ /* ========================================
320
+ LOADING STATE
321
+ ======================================== */
322
+ .loader {
323
+ display: inline-block;
324
+ width: calc(1em * var(--_scale));
325
+ height: calc(1em * var(--_scale));
326
+ border: 2px solid var(--pd-secondary-col);
327
+ border-top-color: var(--pd-secondary-light-col);
328
+ border-radius: 50%;
329
+ animation: spin 1s linear infinite;
330
+ }
331
+
332
+ @keyframes spin {
333
+ to {
334
+ transform: rotate(360deg);
335
+ }
336
+ }
337
+
338
+ /* ========================================
339
+ SLOTS
340
+ ======================================== */
341
+ ::slotted(*) {
342
+ display: inline-flex;
343
+ align-items: center;
344
+ }
345
+
346
+ .label {
108
347
  display: inline-block;
109
- text-decoration: none;
110
- white-space: nowrap;
111
- margin: 0.5rem;
112
- pointer-events: none;
348
+ }
349
+
350
+ /* ========================================
351
+ ICON STYLING
352
+ ======================================== */
353
+ .button-icon {
354
+ --pd-icon-size: var(
355
+ --pd-button-icon-size,
356
+ calc(1.25em * var(--_scale))
357
+ );
358
+ display: inline-flex;
359
+ align-items: center;
360
+ justify-content: center;
361
+ flex-shrink: 0;
362
+ }
363
+
364
+ /* Icon color inherits from button text color */
365
+ .button-icon {
366
+ --pd-icon-col: currentColor;
367
+ --pd-icon-col-active: currentColor;
368
+ }
369
+
370
+ /* Icon-only button adjustments */
371
+ :host([icon-only]) button {
372
+ padding: var(--_padding-y);
373
+ aspect-ratio: 1;
374
+ min-width: var(--_min-height);
113
375
  }
114
376
  `
115
377
  ];
116
378
  }
379
+ // ============================================================================
380
+ // RENDER
381
+ // ============================================================================
117
382
  render() {
383
+ const isInteractive = !this.disabled && !this.loading;
384
+ const isIconOnly = this.icon && !this.text;
385
+ const showIconAtStart = this.icon && this.iconPosition === "start";
386
+ const showIconAtEnd = this.icon && this.iconPosition === "end";
387
+ const buttonClasses = {
388
+ pressed: this._isPressed
389
+ };
390
+ if (isIconOnly) {
391
+ this.setAttribute("icon-only", "");
392
+ } else {
393
+ this.removeAttribute("icon-only");
394
+ }
118
395
  return html`
119
- <div class="button-div" @click=${this._handleClick}>
120
- <a ?disabled=${this.disabled}>${this.text}</a>
121
- </div>
396
+ <button
397
+ part="button"
398
+ type="${this.type}"
399
+ ?disabled="${this.disabled || this.loading}"
400
+ aria-disabled="${this.disabled || this.loading}"
401
+ aria-busy="${this.loading}"
402
+ .ariaPressed="${this.selected ? "true" : null}"
403
+ aria-label="${isIconOnly ? this.iconLabel || this.icon : nothing}"
404
+ aria-expanded="${this.buttonAriaExpanded}"
405
+ aria-haspopup="${this.buttonAriaHasPopup}"
406
+ aria-controls="${this.buttonAriaControls}"
407
+ class="${classMap(buttonClasses)}"
408
+ @click="${this.handleClick}"
409
+ @mousedown="${this._handleMouseDown}"
410
+ @mouseup="${this._handleMouseUp}"
411
+ @mouseleave="${this._handleMouseUp}"
412
+ @keydown="${this._handleKeyDown}"
413
+ @keyup="${this._handleKeyUp}"
414
+ >
415
+ ${this.loading ? html`<span class="loader" part="loader"></span>` : html`
416
+ ${showIconAtStart ? this.renderIcon() : nothing}
417
+ <slot name="prefix"></slot>
418
+ `}
419
+ ${this.text ? html`<span class="label" part="label">${this.text}</span>` : nothing}
420
+ ${isInteractive ? html`
421
+ <slot name="suffix"></slot>
422
+ ${showIconAtEnd ? this.renderIcon() : nothing}
423
+ ${this.renderSuffixContent()}
424
+ ` : nothing}
425
+ </button>
426
+ ${this.renderAfterButton()}
122
427
  `;
123
428
  }
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
- );
429
+ // ============================================================================
430
+ // PROTECTED RENDER HOOKS (for subclasses like PdPanelButton)
431
+ // ============================================================================
432
+ /**
433
+ * Override point for aria-expanded attribute on the button.
434
+ * Used by PdPanelButton to indicate panel open state.
435
+ */
436
+ get buttonAriaExpanded() {
437
+ return "undefined";
438
+ }
439
+ /**
440
+ * Override point for aria-haspopup attribute on the button.
441
+ * Used by PdPanelButton to indicate dropdown behavior.
442
+ */
443
+ get buttonAriaHasPopup() {
444
+ return "false";
445
+ }
446
+ /**
447
+ * Override point for aria-controls attribute on the button.
448
+ * Used by PdPanelButton to link button with panel.
449
+ */
450
+ get buttonAriaControls() {
451
+ return nothing;
452
+ }
453
+ /**
454
+ * Override point for suffix content inside the button.
455
+ * Used by PdPanelButton for the toggle arrow.
456
+ */
457
+ renderSuffixContent() {
458
+ return nothing;
459
+ }
460
+ /**
461
+ * Override point for content rendered after the button element.
462
+ * Used by PdPanelButton for the dropdown panel.
463
+ */
464
+ renderAfterButton() {
465
+ return nothing;
466
+ }
467
+ /**
468
+ * Renders the icon element. Protected for subclass access.
469
+ */
470
+ renderIcon() {
471
+ if (!this.icon) return nothing;
472
+ return html`
473
+ <pd-icon class="button-icon" part="icon" icon="${this.icon}"></pd-icon>
474
+ `;
475
+ }
476
+ // ============================================================================
477
+ // EVENT HANDLERS
478
+ // ============================================================================
479
+ /**
480
+ * Handles click events on the button.
481
+ * Protected so subclasses like PdPanelButton can override.
482
+ */
483
+ handleClick() {
484
+ if (!this.disabled && !this.loading) {
485
+ this._emitButtonClicked();
486
+ }
487
+ }
488
+ /**
489
+ * Handles mousedown for visual pressed state.
490
+ */
491
+ _handleMouseDown() {
492
+ if (!this.disabled && !this.loading) {
493
+ this._isPressed = true;
494
+ }
495
+ }
496
+ /**
497
+ * Handles mouseup/mouseleave to reset pressed state.
498
+ */
499
+ _handleMouseUp() {
500
+ this._isPressed = false;
501
+ }
502
+ /**
503
+ * Handles keydown events for keyboard activation.
504
+ */
505
+ _handleKeyDown(event) {
506
+ if (this.disabled || this.loading) return;
507
+ if (event.key === "Enter" || event.key === " ") {
508
+ event.preventDefault();
509
+ this._isPressed = true;
510
+ }
511
+ }
512
+ /**
513
+ * Handles keyup events to complete keyboard activation.
514
+ */
515
+ _handleKeyUp(event) {
516
+ if (this.disabled || this.loading) return;
517
+ if (event.key === "Enter" || event.key === " ") {
518
+ event.preventDefault();
519
+ this._isPressed = false;
520
+ this.handleClick();
133
521
  }
134
522
  }
523
+ /**
524
+ * Dispatches the button-clicked event.
525
+ * @fires button-clicked
526
+ */
527
+ _emitButtonClicked() {
528
+ this.dispatchEvent(
529
+ new CustomEvent("button-clicked", {
530
+ detail: this.value,
531
+ bubbles: true,
532
+ composed: true
533
+ })
534
+ );
535
+ }
135
536
  }
136
537
  __decorateClass([
137
538
  property({ type: Boolean, reflect: true })
@@ -139,14 +540,44 @@ __decorateClass([
139
540
  __decorateClass([
140
541
  property({ type: Boolean, reflect: true })
141
542
  ], PdButton.prototype, "gradient");
543
+ __decorateClass([
544
+ property({ type: Boolean, reflect: true })
545
+ ], PdButton.prototype, "selected");
142
546
  __decorateClass([
143
547
  property({ type: Boolean, reflect: true })
144
548
  ], PdButton.prototype, "disabled");
549
+ __decorateClass([
550
+ property({ type: Boolean, reflect: true })
551
+ ], PdButton.prototype, "loading");
552
+ __decorateClass([
553
+ property({ type: Boolean, reflect: true, attribute: "full-width" })
554
+ ], PdButton.prototype, "fullWidth");
145
555
  __decorateClass([
146
556
  property({ type: String })
147
557
  ], PdButton.prototype, "text");
558
+ __decorateClass([
559
+ property({ type: String })
560
+ ], PdButton.prototype, "icon");
561
+ __decorateClass([
562
+ property({ type: String, attribute: "icon-label" })
563
+ ], PdButton.prototype, "iconLabel");
564
+ __decorateClass([
565
+ property({ type: String, attribute: "icon-position" })
566
+ ], PdButton.prototype, "iconPosition");
148
567
  __decorateClass([
149
568
  property({ type: String })
150
569
  ], PdButton.prototype, "value");
570
+ __decorateClass([
571
+ property({ type: String, reflect: true })
572
+ ], PdButton.prototype, "size");
573
+ __decorateClass([
574
+ property({ type: String })
575
+ ], PdButton.prototype, "type");
576
+ __decorateClass([
577
+ property({ type: String, reflect: true })
578
+ ], PdButton.prototype, "span");
579
+ __decorateClass([
580
+ state()
581
+ ], PdButton.prototype, "_isPressed");
151
582
 
152
583
  export { PdButton };