@pure-ds/core 0.7.27 → 0.7.29

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 (33) hide show
  1. package/.cursorrules +15 -0
  2. package/.github/copilot-instructions.md +15 -0
  3. package/custom-elements.json +160 -1
  4. package/dist/types/pds.d.ts +55 -1
  5. package/dist/types/public/assets/js/pds-ask.d.ts +1 -2
  6. package/dist/types/public/assets/js/pds-ask.d.ts.map +1 -1
  7. package/dist/types/public/assets/js/pds-autocomplete.d.ts +36 -25
  8. package/dist/types/public/assets/js/pds-autocomplete.d.ts.map +1 -1
  9. package/dist/types/public/assets/js/pds-enhancers.d.ts +4 -4
  10. package/dist/types/public/assets/js/pds-enhancers.d.ts.map +1 -1
  11. package/dist/types/public/assets/js/pds-manager.d.ts +159 -444
  12. package/dist/types/public/assets/js/pds-manager.d.ts.map +1 -1
  13. package/dist/types/public/assets/js/pds-toast.d.ts +6 -7
  14. package/dist/types/public/assets/js/pds-toast.d.ts.map +1 -1
  15. package/dist/types/public/assets/js/pds.d.ts +3 -4
  16. package/dist/types/public/assets/js/pds.d.ts.map +1 -1
  17. package/dist/types/public/assets/pds/components/pds-omnibox.d.ts +46 -0
  18. package/dist/types/public/assets/pds/components/pds-omnibox.d.ts.map +1 -1
  19. package/dist/types/src/js/common/ask.d.ts.map +1 -1
  20. package/dist/types/src/js/pds-core/pds-generator.d.ts.map +1 -1
  21. package/package.json +1 -1
  22. package/public/assets/js/app.js +1 -1
  23. package/public/assets/js/pds-ask.js +6 -6
  24. package/public/assets/js/pds-manager.js +110 -56
  25. package/public/assets/pds/components/pds-omnibox.js +70 -3
  26. package/public/assets/pds/components/pds-tags.js +160 -122
  27. package/public/assets/pds/core/pds-ask.js +6 -6
  28. package/public/assets/pds/core/pds-manager.js +110 -56
  29. package/public/assets/pds/custom-elements.json +175 -1
  30. package/public/assets/pds/pds-css-complete.json +1 -1
  31. package/public/assets/pds/vscode-custom-data.json +32 -0
  32. package/src/js/pds-core/pds-generator.js +98 -26
  33. package/src/js/pds.d.ts +55 -1
@@ -3280,7 +3280,7 @@
3280
3280
  {
3281
3281
  "kind": "field",
3282
3282
  "name": "innerHTML",
3283
- "default": "`\r\n <style>\r\n :host {\r\n --rating-star-size: var(--spacing-lg);\r\n --rating-star-gap: var(--spacing-2xs);\r\n --rating-star-off: var(--color-text-muted);\r\n --rating-star-on: var(--color-warning-500);\r\n --rating-focus: var(--color-primary-500);\r\n --rating-fill-pct: 0%;\r\n display: inline-block;\r\n inline-size: fit-content;\r\n max-inline-size: 100%;\r\n touch-action: none;\r\n }\r\n\r\n ::slotted(input[type=\"range\"]) {\r\n position: absolute !important;\r\n inset-inline-start: 0 !important;\r\n inset-block-start: 0 !important;\r\n inline-size: 1px !important;\r\n block-size: 1px !important;\r\n min-inline-size: 1px !important;\r\n min-block-size: 1px !important;\r\n margin: -1px !important;\r\n border: 0 !important;\r\n padding: 0 !important;\r\n opacity: 0 !important;\r\n overflow: hidden !important;\r\n clip: rect(0 0 0 0) !important;\r\n clip-path: inset(50%) !important;\r\n white-space: nowrap !important;\r\n appearance: none !important;\r\n -webkit-appearance: none !important;\r\n pointer-events: none !important;\r\n }\r\n\r\n .wrap {\r\n position: relative;\r\n display: inline-grid;\r\n gap: var(--spacing-2xs);\r\n align-items: center;\r\n justify-items: start;\r\n min-block-size: calc(var(--rating-star-size) + var(--spacing-xs));\r\n }\r\n\r\n .interactive {\r\n display: inline-grid;\r\n place-items: center start;\r\n inline-size: 100%;\r\n cursor: pointer;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n touch-action: pan-x;\r\n }\r\n\r\n :host([disabled]) .interactive,\r\n :host([readonly]) .interactive {\r\n cursor: default;\r\n }\r\n\r\n :host([disabled]) {\r\n opacity: 0.5;\r\n }\r\n\r\n .stars {\r\n display: block;\r\n inline-size: auto;\r\n block-size: var(--rating-star-size);\r\n overflow: visible;\r\n transition: transform 220ms ease, opacity 220ms ease;\r\n }\r\n\r\n :host([data-in-view=\"false\"]) .stars {\r\n opacity: 0;\r\n transform: translateY(var(--spacing-xs)) scale(0.98);\r\n }\r\n\r\n :host([data-in-view=\"true\"]) .stars {\r\n opacity: 1;\r\n transform: translateY(0) scale(1);\r\n }\r\n\r\n input[type=\"range\"] {\r\n position: absolute !important;\r\n inset-inline-start: 0 !important;\r\n inset-block-start: 0 !important;\r\n inline-size: 1px !important;\r\n block-size: 1px !important;\r\n min-inline-size: 1px !important;\r\n min-block-size: 1px !important;\r\n margin: -1px !important;\r\n border: 0 !important;\r\n padding: 0 !important;\r\n opacity: 0 !important;\r\n overflow: hidden !important;\r\n clip: rect(0 0 0 0) !important;\r\n clip-path: inset(50%) !important;\r\n white-space: nowrap !important;\r\n appearance: none !important;\r\n -webkit-appearance: none !important;\r\n pointer-events: none !important;\r\n }\r\n\r\n :host(:focus-within) .interactive {\r\n outline: 2px solid var(--rating-focus);\r\n outline-offset: var(--spacing-3xs);\r\n border-radius: var(--radius-sm);\r\n }\r\n\r\n @media (prefers-reduced-motion: reduce) {\r\n .stars {\r\n transition: none;\r\n }\r\n }\r\n </style>\r\n\r\n <div class=\"wrap\" part=\"control\">\r\n <div class=\"interactive\" part=\"interactive\" aria-hidden=\"true\">\r\n <svg class=\"stars\" part=\"stars\" focusable=\"false\" aria-hidden=\"true\"></svg>\r\n </div>\r\n <slot></slot>\r\n </div>\r\n `"
3283
+ "default": "`\r\n <style>\r\n :host {\r\n --rating-star-size: var(--spacing-lg);\r\n --rating-star-gap: var(--spacing-2xs);\r\n --rating-star-off: var(--color-text-muted);\r\n --rating-star-on: var(--color-warning-500);\r\n --rating-focus: var(--color-primary-500);\r\n --rating-fill-pct: 0%;\r\n display: inline-block;\r\n inline-size: fit-content;\r\n max-inline-size: 100%;\r\n touch-action: none;\r\n }\r\n\r\n .wrap {\r\n position: relative;\r\n display: inline-grid;\r\n gap: var(--spacing-2xs);\r\n align-items: center;\r\n justify-items: start;\r\n min-block-size: calc(var(--rating-star-size) + var(--spacing-xs));\r\n }\r\n\r\n .interactive {\r\n display: inline-grid;\r\n place-items: center start;\r\n inline-size: 100%;\r\n cursor: pointer;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n touch-action: pan-x;\r\n }\r\n\r\n :host([disabled]) .interactive,\r\n :host([readonly]) .interactive {\r\n cursor: default;\r\n }\r\n\r\n :host([disabled]) {\r\n opacity: 0.5;\r\n }\r\n\r\n .stars {\r\n display: block;\r\n inline-size: auto;\r\n block-size: var(--rating-star-size);\r\n overflow: visible;\r\n transition: transform 220ms ease, opacity 220ms ease;\r\n }\r\n\r\n :host([data-in-view=\"false\"]) .stars {\r\n opacity: 0;\r\n transform: translateY(var(--spacing-xs)) scale(0.98);\r\n }\r\n\r\n :host([data-in-view=\"true\"]) .stars {\r\n opacity: 1;\r\n transform: translateY(0) scale(1);\r\n }\r\n\r\n input[type=\"range\"] {\r\n position: absolute !important;\r\n inset-inline-start: 0 !important;\r\n inset-block-start: 0 !important;\r\n inline-size: 1px !important;\r\n block-size: 1px !important;\r\n min-inline-size: 1px !important;\r\n min-block-size: 1px !important;\r\n margin: -1px !important;\r\n border: 0 !important;\r\n padding: 0 !important;\r\n opacity: 0 !important;\r\n overflow: hidden !important;\r\n clip: rect(0 0 0 0) !important;\r\n clip-path: inset(50%) !important;\r\n white-space: nowrap !important;\r\n appearance: none !important;\r\n -webkit-appearance: none !important;\r\n pointer-events: none !important;\r\n }\r\n\r\n :host(:focus-within) .interactive {\r\n outline: 2px solid var(--rating-focus);\r\n outline-offset: var(--spacing-3xs);\r\n border-radius: var(--radius-sm);\r\n }\r\n\r\n @media (prefers-reduced-motion: reduce) {\r\n .stars {\r\n transition: none;\r\n }\r\n }\r\n </style>\r\n\r\n <div class=\"wrap\" part=\"control\">\r\n <div class=\"interactive\" part=\"interactive\" aria-hidden=\"true\">\r\n <svg class=\"stars\" part=\"stars\" focusable=\"false\" aria-hidden=\"true\"></svg>\r\n </div>\r\n <input class=\"native-input\" type=\"range\" />\r\n </div>\r\n `"
3284
3284
  }
3285
3285
  ],
3286
3286
  "events": [
@@ -4200,6 +4200,180 @@
4200
4200
  }
4201
4201
  ]
4202
4202
  },
4203
+ {
4204
+ "kind": "javascript-module",
4205
+ "path": "public/assets/pds/components/pds-tags.js",
4206
+ "declarations": [
4207
+ {
4208
+ "kind": "class",
4209
+ "description": "Form-associated multi-select tags control built on top of `pds-omnibox`.\r\n\r\nUsers select suggestions from the omnibox and each selection is rendered as a removable\r\nchip. The component keeps selection state synchronized across:\r\n- the `value` attribute (comma-separated ids)\r\n- the `value` property (`string[]`)\r\n- form value via ElementInternals\r\n\r\nIf `settings` is not provided, the component derives omnibox categories from `options`.\r\nWhen `required` is set, at least one selected value is required for validity.",
4210
+ "name": "PdsTags",
4211
+ "members": [
4212
+ {
4213
+ "kind": "field",
4214
+ "name": "formAssociated",
4215
+ "type": {
4216
+ "text": "boolean"
4217
+ },
4218
+ "static": true,
4219
+ "default": "true"
4220
+ },
4221
+ {
4222
+ "kind": "field",
4223
+ "name": "name"
4224
+ },
4225
+ {
4226
+ "kind": "field",
4227
+ "name": "placeholder"
4228
+ },
4229
+ {
4230
+ "kind": "field",
4231
+ "name": "options",
4232
+ "type": {
4233
+ "text": "Array<string|Object>"
4234
+ },
4235
+ "description": "Option source used to build omnibox suggestions"
4236
+ },
4237
+ {
4238
+ "kind": "field",
4239
+ "name": "settings",
4240
+ "type": {
4241
+ "text": "Object|null"
4242
+ },
4243
+ "description": "Omnibox-compatible settings source"
4244
+ },
4245
+ {
4246
+ "kind": "field",
4247
+ "name": "value",
4248
+ "type": {
4249
+ "text": "string[]"
4250
+ },
4251
+ "description": "Selected option ids (array form)"
4252
+ },
4253
+ {
4254
+ "kind": "field",
4255
+ "name": "disabled"
4256
+ },
4257
+ {
4258
+ "kind": "field",
4259
+ "name": "required"
4260
+ },
4261
+ {
4262
+ "kind": "method",
4263
+ "name": "formResetCallback"
4264
+ },
4265
+ {
4266
+ "kind": "method",
4267
+ "name": "formStateRestoreCallback",
4268
+ "parameters": [
4269
+ {
4270
+ "name": "state"
4271
+ }
4272
+ ]
4273
+ },
4274
+ {
4275
+ "kind": "method",
4276
+ "name": "formDisabledCallback",
4277
+ "parameters": [
4278
+ {
4279
+ "name": "disabled"
4280
+ }
4281
+ ]
4282
+ },
4283
+ {
4284
+ "kind": "method",
4285
+ "name": "checkValidity"
4286
+ },
4287
+ {
4288
+ "kind": "method",
4289
+ "name": "reportValidity"
4290
+ }
4291
+ ],
4292
+ "events": [
4293
+ {
4294
+ "name": "input",
4295
+ "type": {
4296
+ "text": "Event"
4297
+ },
4298
+ "description": "Fired whenever selection changes"
4299
+ },
4300
+ {
4301
+ "name": "change",
4302
+ "type": {
4303
+ "text": "Event"
4304
+ },
4305
+ "description": "Fired whenever selection changes"
4306
+ }
4307
+ ],
4308
+ "attributes": [
4309
+ {
4310
+ "name": "name",
4311
+ "type": {
4312
+ "text": "string"
4313
+ },
4314
+ "description": "Form field name; selected values are submitted under this name"
4315
+ },
4316
+ {
4317
+ "name": "placeholder",
4318
+ "type": {
4319
+ "text": "string"
4320
+ },
4321
+ "description": "Placeholder shown in omnibox input (default: \"Search tags...\")"
4322
+ },
4323
+ {
4324
+ "name": "value",
4325
+ "type": {
4326
+ "text": "string"
4327
+ },
4328
+ "description": "Comma-separated selected item ids"
4329
+ },
4330
+ {
4331
+ "name": "options",
4332
+ "type": {
4333
+ "text": "string"
4334
+ },
4335
+ "description": "JSON array of options (`string[]` or object[] with id/text metadata)"
4336
+ },
4337
+ {
4338
+ "name": "settings",
4339
+ "type": {
4340
+ "text": "string"
4341
+ },
4342
+ "description": "JSON omnibox settings; takes precedence over derived options settings"
4343
+ },
4344
+ {
4345
+ "name": "disabled",
4346
+ "type": {
4347
+ "text": "boolean"
4348
+ },
4349
+ "description": "Disables omnibox interaction and chip remove actions"
4350
+ },
4351
+ {
4352
+ "name": "required",
4353
+ "type": {
4354
+ "text": "boolean"
4355
+ },
4356
+ "description": "Requires at least one selected value for validity"
4357
+ }
4358
+ ],
4359
+ "superclass": {
4360
+ "name": "HTMLElement"
4361
+ },
4362
+ "tagName": "pds-tags",
4363
+ "customElement": true
4364
+ }
4365
+ ],
4366
+ "exports": [
4367
+ {
4368
+ "kind": "custom-element-definition",
4369
+ "name": "pds-tags",
4370
+ "declaration": {
4371
+ "name": "PdsTags",
4372
+ "module": "public/assets/pds/components/pds-tags.js"
4373
+ }
4374
+ }
4375
+ ]
4376
+ },
4203
4377
  {
4204
4378
  "kind": "javascript-module",
4205
4379
  "path": "public/assets/pds/components/pds-theme.js",
@@ -2297,7 +2297,7 @@
2297
2297
  ],
2298
2298
  "metadata": {
2299
2299
  "generator": "PDS CSS Data Generator",
2300
- "generatedAt": "2026-03-03T08:40:38.831Z",
2300
+ "generatedAt": "2026-03-04T14:29:06.155Z",
2301
2301
  "totalProperties": 169,
2302
2302
  "totalClasses": 170,
2303
2303
  "totalAttributes": 5
@@ -950,6 +950,38 @@
950
950
  }
951
951
  ]
952
952
  },
953
+ {
954
+ "name": "pds-tags",
955
+ "description": "Form-associated multi-select tags control built on top of `pds-omnibox`.\r\n\r\nUsers select suggestions from the omnibox and each selection is rendered as a removable\r\nchip. The component keeps selection state synchronized across:\r\n- the `value` attribute (comma-separated ids)\r\n- the `value` property (`string[]`)\r\n- form value via ElementInternals\r\n\r\nThe `options` object uses the same structure as `pds-omnibox.settings`.\r\nSee `pds-omnibox` JSDoc for the full options schema.\r\nBefore applying it, the component deep-merges internal defaults:\r\n- `hideCategory: true`\r\n- `itemGrid: \"0 1fr 0\"`\r\n- `iconHandler: () => \"\"`\r\n\r\nWhen `required` is set, at least one selected value is required for validity.",
956
+ "attributes": [
957
+ {
958
+ "name": "name",
959
+ "description": "Form field name; selected values are submitted under this name"
960
+ },
961
+ {
962
+ "name": "placeholder",
963
+ "description": "Placeholder shown in omnibox input (default: \"Search tags...\")"
964
+ },
965
+ {
966
+ "name": "value",
967
+ "description": "Comma-separated selected item ids"
968
+ },
969
+ {
970
+ "name": "options",
971
+ "description": "JSON object with the same shape as `pds-omnibox.settings`"
972
+ },
973
+ {
974
+ "name": "disabled",
975
+ "description": "Disables omnibox interaction and chip remove actions",
976
+ "valueSet": "v"
977
+ },
978
+ {
979
+ "name": "required",
980
+ "description": "Requires at least one selected value for validity",
981
+ "valueSet": "v"
982
+ }
983
+ ]
984
+ },
953
985
  {
954
986
  "name": "pds-theme",
955
987
  "description": "PdsTheme component"
@@ -2731,18 +2731,23 @@ select {
2731
2731
 
2732
2732
  /* Button styling */
2733
2733
  button, .btn, input[type="submit"], input[type="button"], input[type="reset"] {
2734
+ --btn-pad-y: max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2));
2735
+ --btn-target-h: max(${minButtonHeight}px, calc(var(--font-size-base) + (var(--btn-pad-y) * 2) + (var(--border-width-medium) * 2)));
2734
2736
  display: inline-flex;
2735
2737
  gap: var(--spacing-1);
2736
2738
  align-items: center;
2737
2739
  justify-content: center;
2738
- min-height: ${minButtonHeight}px;
2739
- padding: max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2)) var(--spacing-6);
2740
+ min-height: var(--btn-target-h);
2741
+ height: var(--btn-target-h);
2742
+ padding: var(--btn-pad-y) var(--spacing-6);
2740
2743
  border: var(--border-width-medium) solid transparent;
2741
2744
  border-radius: var(--radius-md);
2745
+ box-sizing: border-box;
2742
2746
  font-family: var(--font-family-body);
2743
2747
  font-size: var(--font-size-base);
2744
2748
  font-weight: var(--font-weight-medium);
2745
2749
  line-height: 1;
2750
+ white-space: nowrap;
2746
2751
  cursor: pointer;
2747
2752
  transition: all var(--transition-fast);
2748
2753
  text-decoration: none;
@@ -2896,22 +2901,31 @@ button, .btn, input[type="submit"], input[type="button"], input[type="reset"] {
2896
2901
  }
2897
2902
 
2898
2903
  .btn-sm {
2899
- padding: calc(max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2)) * 0.85) calc(var(--spacing-6) * 0.8);
2904
+ --btn-pad-y: calc(max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2)) * 0.85);
2905
+ --btn-target-h: max(calc(${minButtonHeight}px * 0.85), calc(var(--font-size-sm) + (var(--btn-pad-y) * 2) + (var(--border-width-medium) * 2)));
2906
+ padding: var(--btn-pad-y) calc(var(--spacing-6) * 0.8);
2900
2907
  font-size: var(--font-size-sm);
2901
- min-height: calc(${minButtonHeight}px * 0.85);
2908
+ min-height: var(--btn-target-h);
2909
+ height: var(--btn-target-h);
2902
2910
  }
2903
2911
 
2904
2912
  .btn-xs {
2905
- padding: calc(max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2)) * 0.7) calc(var(--spacing-6) * 0.65);
2913
+ --btn-pad-y: calc(max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2)) * 0.7);
2914
+ --btn-target-h: max(calc(${minButtonHeight}px * 0.7), calc(var(--font-size-xs) + (var(--btn-pad-y) * 2) + (var(--border-width-medium) * 2)));
2915
+ padding: var(--btn-pad-y) calc(var(--spacing-6) * 0.65);
2906
2916
  font-size: var(--font-size-xs);
2907
- min-height: calc(${minButtonHeight}px * 0.7);
2917
+ min-height: var(--btn-target-h);
2918
+ height: var(--btn-target-h);
2908
2919
  }
2909
2920
 
2910
2921
 
2911
2922
  .btn-lg {
2912
- padding: calc(max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2)) * 1.15) calc(var(--spacing-6) * 1.35);
2923
+ --btn-pad-y: calc(max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2)) * 1.15);
2924
+ --btn-target-h: max(calc(${minButtonHeight}px * 1.15), calc(var(--font-size-lg) + (var(--btn-pad-y) * 2) + (var(--border-width-medium) * 2)));
2925
+ padding: var(--btn-pad-y) calc(var(--spacing-6) * 1.35);
2913
2926
  font-size: var(--font-size-lg);
2914
- min-height: calc(${minButtonHeight}px * 1.15);
2927
+ min-height: var(--btn-target-h);
2928
+ height: var(--btn-target-h);
2915
2929
  }
2916
2930
 
2917
2931
  /* Working/loading state for buttons */
@@ -3887,7 +3901,25 @@ pds-tabstrip {
3887
3901
 
3888
3902
  #generateIconStyles() {
3889
3903
  const { layout = {} } = this.options.design;
3890
- const iconOnlySize = layout.buttonMinHeight || 30;
3904
+ const minButtonHeight = layout.buttonMinHeight || 30;
3905
+ const buttonPaddingValue = layout.buttonPadding || 1.0;
3906
+ const buttonPaddingDefault = `max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2))`;
3907
+ const buttonPaddingSm = `calc(max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2)) * 0.85)`;
3908
+ const buttonPaddingXs = `calc(max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2)) * 0.7)`;
3909
+ const buttonPaddingLg = `calc(max(calc(var(--spacing-1) * ${buttonPaddingValue}), var(--spacing-2)) * 1.15)`;
3910
+ const iconOnlyPaddingScale = 0.72;
3911
+ const iconOnlyPaddingDefault = `calc(${buttonPaddingDefault} * ${iconOnlyPaddingScale})`;
3912
+ const iconOnlyPaddingSm = `calc(${buttonPaddingSm} * ${iconOnlyPaddingScale})`;
3913
+ const iconOnlyPaddingXs = `calc(${buttonPaddingXs} * ${iconOnlyPaddingScale})`;
3914
+ const iconOnlyPaddingLg = `calc(${buttonPaddingLg} * ${iconOnlyPaddingScale})`;
3915
+ const iconOnlyMinDefault = `${minButtonHeight}px`;
3916
+ const iconOnlyMinSm = `calc(${minButtonHeight}px * 0.85)`;
3917
+ const iconOnlyMinXs = `calc(${minButtonHeight}px * 0.7)`;
3918
+ const iconOnlyMinLg = `calc(${minButtonHeight}px * 1.15)`;
3919
+ const iconOnlySizeDefault = `max(${iconOnlyMinDefault}, calc(var(--font-size-base) + (${buttonPaddingDefault} * 2) + (var(--border-width-medium) * 2)))`;
3920
+ const iconOnlySizeSm = `max(${iconOnlyMinSm}, calc(var(--font-size-sm) + (${buttonPaddingSm} * 2) + (var(--border-width-medium) * 2)))`;
3921
+ const iconOnlySizeXs = `max(${iconOnlyMinXs}, calc(var(--font-size-xs) + (${buttonPaddingXs} * 2) + (var(--border-width-medium) * 2)))`;
3922
+ const iconOnlySizeLg = `max(${iconOnlyMinLg}, calc(var(--font-size-lg) + (${buttonPaddingLg} * 2) + (var(--border-width-medium) * 2)))`;
3891
3923
 
3892
3924
  return /*css*/ `/* Icon System */
3893
3925
 
@@ -3927,37 +3959,77 @@ pds-icon {
3927
3959
  .icon-text-end { flex-direction: row-reverse; }
3928
3960
 
3929
3961
  /* Button icon utilities */
3930
- button, a {
3931
- pds-icon {
3962
+ button,
3963
+ a.btn,
3964
+ a.btn-primary,
3965
+ a.btn-secondary,
3966
+ a.btn-outline,
3967
+ a.btn-danger,
3968
+ a.icon-only {
3969
+ pds-icon,
3970
+ pds-icon[size] {
3932
3971
  flex-shrink: 0;
3972
+ width: 1em;
3973
+ height: 1em;
3933
3974
  }
3934
3975
 
3935
3976
  &.icon-only {
3936
- padding: var(--spacing-2);
3937
- min-width: ${iconOnlySize}px;
3938
- width: ${iconOnlySize}px;
3939
- height: ${iconOnlySize}px;
3977
+ padding: ${iconOnlyPaddingDefault};
3978
+ min-width: ${iconOnlySizeDefault};
3979
+ min-height: ${iconOnlySizeDefault};
3980
+ width: ${iconOnlySizeDefault};
3981
+ height: ${iconOnlySizeDefault};
3940
3982
  display: inline-flex;
3941
3983
  align-items: center;
3942
3984
  justify-content: center;
3985
+
3986
+ pds-icon,
3987
+ pds-icon[size] {
3988
+ width: 1.2em;
3989
+ height: 1.2em;
3990
+ }
3943
3991
  }
3944
3992
 
3945
3993
  &.btn-sm.icon-only {
3946
- min-width: calc(${iconOnlySize}px * 0.8);
3947
- width: calc(${iconOnlySize}px * 0.8);
3948
- height: calc(${iconOnlySize}px * 0.8);
3994
+ padding: ${iconOnlyPaddingSm};
3995
+ min-width: ${iconOnlySizeSm};
3996
+ min-height: ${iconOnlySizeSm};
3997
+ width: ${iconOnlySizeSm};
3998
+ height: ${iconOnlySizeSm};
3999
+
4000
+ pds-icon,
4001
+ pds-icon[size] {
4002
+ width: 1.15em;
4003
+ height: 1.15em;
4004
+ }
3949
4005
  }
3950
4006
 
3951
4007
  &.btn-xs.icon-only {
3952
- min-width: calc(${iconOnlySize}px * 0.6);
3953
- width: calc(${iconOnlySize}px * 0.6);
3954
- height: calc(${iconOnlySize}px * 0.6);
4008
+ padding: ${iconOnlyPaddingXs};
4009
+ min-width: ${iconOnlySizeXs};
4010
+ min-height: ${iconOnlySizeXs};
4011
+ width: ${iconOnlySizeXs};
4012
+ height: ${iconOnlySizeXs};
4013
+
4014
+ pds-icon,
4015
+ pds-icon[size] {
4016
+ width: 1.1em;
4017
+ height: 1.1em;
4018
+ }
3955
4019
  }
3956
4020
 
3957
4021
  &.btn-lg.icon-only {
3958
- min-width: calc(${iconOnlySize}px * 1.2);
3959
- width: calc(${iconOnlySize}px * 1.2);
3960
- height: calc(${iconOnlySize}px * 1.2);
4022
+ padding: ${iconOnlyPaddingLg};
4023
+ min-width: ${iconOnlySizeLg};
4024
+ min-height: ${iconOnlySizeLg};
4025
+ width: ${iconOnlySizeLg};
4026
+ height: ${iconOnlySizeLg};
4027
+
4028
+ pds-icon,
4029
+ pds-icon[size] {
4030
+ width: 1.25em;
4031
+ height: 1.25em;
4032
+ }
3961
4033
  }
3962
4034
  }
3963
4035
 
@@ -4354,9 +4426,9 @@ nav[data-dropdown] {
4354
4426
  }
4355
4427
 
4356
4428
  /* Touch device optimizations */
4357
- @media (hover: none) and (pointer: coarse) {
4429
+ @media (pointer: coarse) {
4358
4430
  /* Touch devices - larger touch targets for interactive elements */
4359
- button:not(.icon-only), a:not(.icon-only), select, textarea,
4431
+ select, textarea,
4360
4432
  input:not([type="radio"]):not([type="checkbox"]) {
4361
4433
  min-height: ${minTouchTarget}px;
4362
4434
  min-width: ${minTouchTarget}px;
package/src/js/pds.d.ts CHANGED
@@ -160,6 +160,60 @@ export interface PDSEventMap {
160
160
  'pds:docs:view': CustomEvent<{ file: string }>;
161
161
  }
162
162
 
163
+ export type AskActionKind = 'ok' | 'cancel' | 'dismiss' | 'custom';
164
+
165
+ export interface AskButtonOption {
166
+ name: string;
167
+ primary?: boolean;
168
+ cancel?: boolean;
169
+ formNoValidate?: boolean;
170
+ [key: string]: any;
171
+ }
172
+
173
+ export interface AskBeforeCloseContext {
174
+ actionCode: string;
175
+ actionKind: AskActionKind;
176
+ dialog: HTMLDialogElement;
177
+ form: HTMLFormElement | null;
178
+ formData: FormData | null;
179
+ submitter?: HTMLElement | null;
180
+ originalEvent?: Event;
181
+ options: AskOptions;
182
+ button: AskButtonOption | null;
183
+ defaultResult: any;
184
+ }
185
+
186
+ export interface AskBeforeCloseResult {
187
+ allow?: boolean;
188
+ result?: any;
189
+ value?: any;
190
+ reason?: string;
191
+ }
192
+
193
+ export type AskBeforeCloseHandler = (
194
+ context: AskBeforeCloseContext
195
+ ) => Promise<boolean | AskBeforeCloseResult | void> | boolean | AskBeforeCloseResult | void;
196
+
197
+ export type AskMessage =
198
+ | string
199
+ | Node
200
+ | Array<any>
201
+ | { strings: any[]; values: any[] };
202
+
203
+ export interface AskOptions {
204
+ title?: string;
205
+ type?: string;
206
+ buttons?: Record<string, AskButtonOption>;
207
+ useForm?: boolean;
208
+ size?: 'sm' | 'md' | 'lg' | 'xl' | string;
209
+ class?: string | string[];
210
+ maxHeight?: string;
211
+ liquidGlassEffects?: boolean;
212
+ rendered?: (dialog: HTMLDialogElement) => void;
213
+ beforeClose?: AskBeforeCloseHandler;
214
+ [key: string]: any;
215
+ }
216
+
163
217
  export class PDS extends EventTarget {
164
218
  // Static surface
165
219
  static registry: PDSRegistry;
@@ -273,7 +327,7 @@ export class PDS extends EventTarget {
273
327
  * @example
274
328
  * const name = await PDS.ask('Enter your name:', { type: 'prompt' });
275
329
  */
276
- static ask(message: string, options?: any): Promise<any>;
330
+ static ask(message: AskMessage, options?: AskOptions): Promise<any>;
277
331
 
278
332
  /**
279
333
  * Current configuration after PDS.start() completes - read-only, frozen after initialization.