@swiftwc/ui 0.0.0-dev.49 → 0.0.0-dev.50

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.
@@ -113,6 +113,8 @@ const handleHelp = ({ target, relatedTarget }) => {
113
113
  const trigger = target.closest('[help]');
114
114
  if (!trigger)
115
115
  return;
116
+ if ('PICKER-VIEW' === trigger.tagName)
117
+ return;
116
118
  if (relatedTarget instanceof HTMLElement && trigger.contains(relatedTarget))
117
119
  return;
118
120
  const newAnchorName = `--help-${self.crypto.randomUUID()}`;
@@ -130,6 +132,8 @@ const handleHelp = ({ target, relatedTarget }) => {
130
132
  const trigger = target.closest('[help]');
131
133
  if (!trigger)
132
134
  return;
135
+ if ('PICKER-VIEW' === trigger.tagName)
136
+ return;
133
137
  if (relatedTarget instanceof HTMLElement && trigger.contains(relatedTarget))
134
138
  return;
135
139
  const anchorName = trigger.style.anchorName;
@@ -412,13 +412,13 @@ export class DatePicker extends FormAssociatedBase {
412
412
  for (const el of this.#slots?.get('validity-options')?.assignedElements({ flatten: true }) ?? []) {
413
413
  if (!el.matches('option'))
414
414
  continue;
415
- const option = el;
416
- if (`${kebabCase(key)}` === option.value) {
417
- message = option.label;
415
+ const { label, value } = el;
416
+ if (`${kebabCase(key)}` === value) {
417
+ message = label;
418
418
  break;
419
419
  }
420
- else if (`${kebabCase(key)}:${message}` === option.value) {
421
- message = option.label;
420
+ else if (`${kebabCase(key)}:${message}` === value) {
421
+ message = label;
422
422
  break;
423
423
  }
424
424
  }
@@ -19,6 +19,7 @@ export class LabelView extends HTMLElement {
19
19
  ));
20
20
  }
21
21
  #shadowRoot;
22
+ // #reflectScheduled = false
22
23
  constructor() {
23
24
  super();
24
25
  this.#shadowRoot = this.attachShadow({ mode: 'closed' });
@@ -29,6 +30,7 @@ export class LabelView extends HTMLElement {
29
30
  console.debug(`${LabelView.name} ⚡️ attr-change [${name}] ("${oldValue}" → "${newValue}")`);
30
31
  if (oldValue === newValue)
31
32
  return;
33
+ // this.#scheduleReflect()
32
34
  switch (name) {
33
35
  case 'system-image':
34
36
  renderLabelIcon(this, newValue);
@@ -10,6 +10,7 @@ export declare class PickerView extends FormAssociatedBase {
10
10
  SELECTION: string;
11
11
  SEARCHABLE: string;
12
12
  CURRENT_VALUE_LABEL: string;
13
+ TRIGGER_HELP: string;
13
14
  };
14
15
  static get observedAttributes(): string[];
15
16
  get selection(): string;
@@ -78,6 +78,7 @@ export class PickerView extends FormAssociatedBase {
78
78
  SELECTION: 'selection',
79
79
  SEARCHABLE: 'searchable',
80
80
  CURRENT_VALUE_LABEL: 'current-value-label',
81
+ TRIGGER_HELP: 'help',
81
82
  };
82
83
  }
83
84
  static get observedAttributes() {
@@ -157,9 +158,9 @@ export class PickerView extends FormAssociatedBase {
157
158
  break;
158
159
  }
159
160
  default: {
160
- const btn = $(`<button type="button" tabindex="0"><label-view></label-view></button>`, '>1'), label = btn.querySelector(':scope>label-view');
161
- if (el.dataset.label)
162
- label?.setAttribute('title', el.dataset.label);
161
+ const btn = $(`<button type="button" tabindex="0" is="navigation-link"><h-stack distribution="leading" template="auto spacer"><label-view data-role="check" style="visibility: hidden"><image-view slot="icon" system-name="check"></image-view></label-view><label-view><span></span></label-view></h-stack></button>`, '>1'), label = btn.querySelector(':scope>h-stack>label-view:nth-child(2)');
162
+ if (label && el.dataset.label)
163
+ renderLabelTitle(label, el.dataset.label); //label?.setAttribute('title', el.dataset.label)
163
164
  btn.addEventListener('click', async (evt) => {
164
165
  evt.stopImmediatePropagation();
165
166
  evt.preventDefault();
@@ -233,6 +234,8 @@ export class PickerView extends FormAssociatedBase {
233
234
  renderLabelIcon(currentValueLabel, 'dots-three'); // overwritten
234
235
  renderLabelTitle(currentValueLabel, this.#currentValueLabel); // overwritten
235
236
  }
237
+ if (this.hasAttribute('help'))
238
+ currentValueLabel?.setAttribute('help', this.getAttribute('help') ?? '');
236
239
  _a.#reflectButtons([...(this.#slots?.get('list')?.assignedElements() ?? [])], menu);
237
240
  break;
238
241
  }
@@ -248,8 +251,9 @@ export class PickerView extends FormAssociatedBase {
248
251
  el.remove();
249
252
  const value = this.getAttribute(this.constructor.ATTR.LABEL);
250
253
  if (value) {
251
- const label = $(`<label-view></label-view>`, '>1');
252
- label.setAttribute('title', value);
254
+ const label = $(`<label-view><span></span></label-view>`, '>1');
255
+ if (label)
256
+ renderLabelTitle(label, value); //label.setAttribute('title', value)
253
257
  section.insertAdjacentElement('beforeend', label);
254
258
  }
255
259
  _a.#reflectButtons([...(this.#slots?.get('list')?.assignedElements({ flatten: true }) ?? [])].filter((el) => el.matches('option')), section);
@@ -408,6 +412,10 @@ export class PickerView extends FormAssociatedBase {
408
412
  // if (oldValue === newValue) break
409
413
  this.#reflectCurrentValueLabel();
410
414
  break;
415
+ case this.constructor.ATTR.TRIGGER_HELP:
416
+ // if (oldValue === newValue) break
417
+ this.#reflectTriggerHelp();
418
+ break;
411
419
  case this.constructor.ATTR.SELECTION:
412
420
  // nothing happens
413
421
  break;
@@ -562,19 +570,20 @@ export class PickerView extends FormAssociatedBase {
562
570
  btn.setAttribute('value', extractTagFromOption(node));
563
571
  // if (selection !== btn.getAttribute('value')) chevron?.style.setProperty('visibility', 'hidden')
564
572
  const label = $(`<label-view><span></span></label-view>`, '>1');
565
- label.querySelector('span').textContent = extractCurrentValueFromOption(node); //label.setAttribute('title', extractCurrentValueFromOption(node))
573
+ renderLabelTitle(label, extractCurrentValueFromOption(node)); // label.querySelector('span')!.textContent = extractCurrentValueFromOption(node) //label.setAttribute('title', extractCurrentValueFromOption(node))
566
574
  hStack?.appendChild(label);
567
575
  return btn;
568
576
  }
569
577
  static #wrapOptgroupTag(node) {
570
578
  if (devFlags.debug)
571
579
  console.debug(`${_a.name} #wrapOptgroupTag`);
572
- const labelT = `<label-view></label-view>`, summaryT = `<summary>${labelT}</summary>`;
573
- const group = $(`<details is="disclosure-group">${summaryT}</details>`, '>1'), summary = group.querySelector(':scope>summary') ?? group.appendChild($(summaryT, '>1')), summaryLabel = summary.querySelector(':scope>label-view') ?? summary.appendChild($(labelT, '>1'));
574
- if (node.hasAttribute('label'))
575
- summaryLabel.setAttribute('title', node.getAttribute('label') ?? '');
576
- if (node.hasAttribute('data-system-image'))
577
- summaryLabel.setAttribute('system-image', node.getAttribute('data-system-image') ?? '');
580
+ const labelT = `<label-view><span></span></label-view>`, summaryT = `<summary><h-stack distribution="leading" template="auto spacer"><label-view data-role="check" style="visibility: hidden"><image-view slot="icon" system-name="check"></image-view></label-view>${labelT}</h-stack></summary>`;
581
+ const group = $(`<details is="disclosure-group">${summaryT}</details>`, '>1'), hStack = group.querySelector(':scope>summary>h-stack'); // ?? group.appendChild($(summaryT, '>1'))
582
+ // summaryLabel = summary.querySelector(':scope>label-view') ?? summary.appendChild($(labelT, '>1'))
583
+ // if (node.hasAttribute('label')) summaryLabel.setAttribute('title', node.getAttribute('label') ?? '')
584
+ // if (node.hasAttribute('data-system-image')) summaryLabel.setAttribute('system-image', node.getAttribute('data-system-image') ?? '')
585
+ if (hStack)
586
+ renderLabel(hStack, ':scope>label-view:nth-child(2)', labelT, node.getAttribute('label'), node.getAttribute('data-system-image'));
578
587
  return group;
579
588
  }
580
589
  static #reflectButtons(nodes, container) {
@@ -583,11 +592,11 @@ export class PickerView extends FormAssociatedBase {
583
592
  for (const node of nodes)
584
593
  switch (node.tagName) {
585
594
  case 'DATALIST': {
586
- const group = $(`<menu-view tabindex="0"></menu-view>`, '>1'), label = group.querySelector(':scope>label-view[slot=label]') ?? group.appendChild($(`<label-view slot="label"></label-view>`, '>1'));
587
- if (node.hasAttribute('data-label'))
588
- label.setAttribute('title', node.getAttribute('data-label') ?? '');
589
- if (node.hasAttribute('data-system-image'))
590
- label.setAttribute('system-image', node.getAttribute('data-system-image') ?? '');
595
+ const group = $(`<menu-view tabindex="0"></menu-view>`, '>1');
596
+ // label = group.querySelector(':scope>label-view[slot=label]') ?? group.appendChild($(`<label-view slot="label"></label-view>`, '>1'))
597
+ // if (node.hasAttribute('data-label')) label.setAttribute('title', node.getAttribute('data-label') ?? '')
598
+ // if (node.hasAttribute('data-system-image')) label.setAttribute('system-image', node.getAttribute('data-system-image') ?? '')
599
+ renderLabel(group, ':scope>label-view[slot=label]', `<label-view slot="label"><span></span></label-view>`, node.getAttribute('data-label'), node.getAttribute('data-system-image'));
591
600
  _a.#reflectButtons([...node.children], group);
592
601
  container.appendChild(group);
593
602
  break;
@@ -672,6 +681,28 @@ export class PickerView extends FormAssociatedBase {
672
681
  }
673
682
  }
674
683
  }
684
+ #reflectTriggerHelp() {
685
+ if (devFlags.debug)
686
+ console.debug(`${_a.name} #reflectTriggerHelp`);
687
+ let trigger;
688
+ switch (this.pickerStyle) {
689
+ case 'sheet':
690
+ case 'navigation-link': {
691
+ trigger = this.querySelector(':scope>label-view:not([slot])') ?? undefined;
692
+ }
693
+ case 'menu': {
694
+ trigger = this.querySelector(':scope>menu-view:not([slot])>label-view[slot=label]') ?? undefined;
695
+ }
696
+ case 'inline':
697
+ default: {
698
+ //udnefined
699
+ }
700
+ }
701
+ if (this.hasAttribute('help'))
702
+ trigger?.setAttribute('help', this.getAttribute('help') ?? '');
703
+ else
704
+ trigger?.removeAttribute('help');
705
+ }
675
706
  // Optional: form participation properties
676
707
  get name() {
677
708
  return this.getAttribute('name') ?? this.getAttribute('label') ?? this.querySelector(':scope>[slot=label]')?.textContent ?? '';
@@ -686,13 +717,13 @@ export class PickerView extends FormAssociatedBase {
686
717
  for (const el of this.#slots?.get('validity-options')?.assignedElements({ flatten: true }) ?? []) {
687
718
  if (!el.matches('option'))
688
719
  continue;
689
- const option = el;
690
- if (`${kebabCase(key)}` === option.value) {
691
- message = option.label;
720
+ const { label, value } = el;
721
+ if (`${kebabCase(key)}` === value) {
722
+ message = label;
692
723
  break;
693
724
  }
694
- else if (`${kebabCase(key)}:${message}` === option.value) {
695
- message = option.label;
725
+ else if (`${kebabCase(key)}:${message}` === value) {
726
+ message = label;
696
727
  break;
697
728
  }
698
729
  }
@@ -451,13 +451,13 @@ export class TextField extends FormAssociatedBase {
451
451
  for (const el of this.#slots?.get('validity-options')?.assignedElements({ flatten: true }) ?? []) {
452
452
  if (!el.matches('option'))
453
453
  continue;
454
- const option = el;
455
- if (`${kebabCase(key)}` === option.value) {
456
- message = option.label;
454
+ const { label, value } = el;
455
+ if (`${kebabCase(key)}` === value) {
456
+ message = label;
457
457
  break;
458
458
  }
459
- else if (`${kebabCase(key)}:${message}` === option.value) {
460
- message = option.label;
459
+ else if (`${kebabCase(key)}:${message}` === value) {
460
+ message = label;
461
461
  break;
462
462
  }
463
463
  }
@@ -1054,6 +1054,10 @@
1054
1054
  --toolbar-cell-filter: blur(10px);
1055
1055
  --toolbar-cell-opacity: 0;
1056
1056
  }
1057
+ :where(:is(navigation-stack, dialog, body-view):has(> body-view > body-view) > scroll-view,
1058
+ :is(navigation-stack, dialog, body-view):has(> body-view > body-view) > tool-bar) {
1059
+ content-visibility: hidden;
1060
+ }
1057
1061
  }
1058
1062
  @layer sw-components {
1059
1063
  :where(navigation-stack:not([hidden]),
@@ -1348,6 +1352,7 @@
1348
1352
  }
1349
1353
  }
1350
1354
  }
1355
+ @layer sw-components {}
1351
1356
  @layer sw-components {
1352
1357
  :where(h-divider) {
1353
1358
  inline-size: 100%;
@@ -1701,6 +1706,11 @@
1701
1706
  place-items: center;
1702
1707
  text-align: center;
1703
1708
  row-gap: 1rem;
1709
+ padding-inline: 1rem;
1710
+ padding-block: 1rem;
1711
+ }
1712
+ :where(content-unavailable-view)::part(content-unavailable-actions-stack), :where(content-unavailable-view)::part(content-unavailable-title-stack), :where(content-unavailable-view)::part(content-unavailable-description-stack) {
1713
+ max-inline-size: 20rem;
1704
1714
  }
1705
1715
  :where(content-unavailable-view)::part(content-unavailable-actions-stack) {
1706
1716
  row-gap: 0.2rem;
@@ -1760,6 +1770,14 @@
1760
1770
  gap: 1rem;
1761
1771
  --confirmation--dialog-scale: scale(0.7);
1762
1772
  --confirmation--dialog-opacity: 0.8;
1773
+ --confirmation--inner-scale: scale3d(1, 1, 1);
1774
+ }
1775
+ :where([is=confirmation-dialog] > *) {
1776
+ transform: var(--confirmation--inner-scale, );
1777
+ transform-origin: top;
1778
+ }
1779
+ :where([is=confirmation-dialog] > :nth-child(1)) {
1780
+ transform-origin: bottom;
1763
1781
  }
1764
1782
  :where([is=confirmation-dialog][open]) {
1765
1783
  --confirmation--dialog-inline-size: min(20rem, 80vw);
@@ -1769,11 +1787,13 @@
1769
1787
  --confirmation--dialog-margin-inline: max(env(safe-area-inset-left), var(--menu-spacing)) max(env(safe-area-inset-right), var(--menu-spacing));
1770
1788
  --confirmation--dialog-scale: scale(1);
1771
1789
  --confirmation--dialog-opacity: 1;
1790
+ --confirmation--inner-scale: scale3d(1, 1, 1);
1772
1791
  }
1773
1792
  @starting-style {
1774
1793
  :where([is=confirmation-dialog][open]) {
1775
1794
  --confirmation--dialog-scale: scale(0.7);
1776
1795
  --confirmation--dialog-opacity: 0.8;
1796
+ --confirmation--inner-scale: scale3d(0, 0, 1);
1777
1797
  }
1778
1798
  }
1779
1799
  :where([is=confirmation-dialog][closing]) {
@@ -1782,6 +1802,7 @@
1782
1802
  --confirmation--dialog-max-block-size: anchor-size();
1783
1803
  --confirmation--dialog-scale: scale(0.7);
1784
1804
  --confirmation--dialog-opacity: 0;
1805
+ --confirmation--inner-scale: scale3d(0, 0, 1);
1785
1806
  }
1786
1807
  }
1787
1808
  @layer sw-components {
@@ -2522,6 +2543,8 @@
2522
2543
  box-shadow: var(--menu-popover-box-shadow, );
2523
2544
  border-radius: var(--pill-border-radius);
2524
2545
  padding-inline: 1rem;
2546
+ appearance: none;
2547
+ outline: none;
2525
2548
  }
2526
2549
  }
2527
2550
  @layer sw-components {
@@ -2631,7 +2654,6 @@
2631
2654
  -webkit-box-orient: var(--label--box-orient, );
2632
2655
  line-clamp: var(--label--line-clamp, );
2633
2656
  -webkit-line-clamp: var(--label--line-clamp, );
2634
- text-decoration: underline;
2635
2657
  font-size: var(--label--titlestack-font-size, );
2636
2658
  line-height: var(--label--titlestack-line-height, );
2637
2659
  font-weight: var(--label--titlestack-font-weight, );
@@ -7152,6 +7174,10 @@
7152
7174
  :where([is=confirmation-dialog]) {
7153
7175
  transition: all var(--touchglass-transition-duration) allow-discrete ease-out;
7154
7176
  }
7177
+ :where([is=confirmation-dialog] > *) {
7178
+ transition: transform var(--touchglass-transition-duration) allow-discrete ease-out;
7179
+ will-change: transform;
7180
+ }
7155
7181
  }
7156
7182
  }
7157
7183
  @layer sw-transitions {
@@ -8262,13 +8288,13 @@
8262
8288
  :where(tool-bar-item[tint]:not(tool-bar-item-group tool-bar-item),
8263
8289
  tool-bar-item-group[tint],
8264
8290
  tool-bar-item-group[tint] > tool-bar-item:not([tint])) > button {
8265
- --secondary: var(--btntext);
8266
- --blue: var(--btntext);
8267
- --red: var(--btntext);
8268
- --green: var(--btntext);
8269
- --orange: var(--btntext);
8270
- --accentColor: var(--btntext);
8271
- --accentColorEffective: var(--btntext);
8291
+ --secondary: var(--toolbaritemtext);
8292
+ --blue: var(--toolbaritemtext);
8293
+ --red: var(--toolbaritemtext);
8294
+ --green: var(--toolbaritemtext);
8295
+ --orange: var(--toolbaritemtext);
8296
+ --accentColor: var(--toolbaritemtext);
8297
+ --accentColorEffective: var(--toolbaritemtext);
8272
8298
  }
8273
8299
  :where(sidebar-toggle) {
8274
8300
  --toolbaritemhighlightface: light-dark(var(--toolbar-cell-focus-bg), var(--toolbar-cell-focus-bg-dark));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swiftwc/ui",
3
- "version": "0.0.0-dev.49",
3
+ "version": "0.0.0-dev.50",
4
4
  "description": "Elegant SwiftUI-inspired web components for standalone web apps and web extensions.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -4,6 +4,8 @@
4
4
 
5
5
  @forward 'components/disclosure-group';
6
6
 
7
+ @forward 'components/image-view';
8
+
7
9
  @forward 'components/h-divider';
8
10
  @forward 'components/v-divider';
9
11
 
@@ -52,4 +52,13 @@
52
52
  }
53
53
  }
54
54
  }
55
+
56
+ :is(navigation-stack, dialog, body-view):has(> body-view > body-view) {
57
+ > scroll-view,
58
+ > tool-bar {
59
+ :where(&) {
60
+ content-visibility: hidden;
61
+ }
62
+ }
63
+ }
55
64
  }
@@ -636,7 +636,7 @@ $colors: map.merge(
636
636
  @include mixins.wire-tinted-glass(toolbaritem);
637
637
 
638
638
  > button {
639
- @include mixins.takeover-color-vars(btn);
639
+ @include mixins.takeover-color-vars(toolbaritem);
640
640
  // --secondary: var(--btntext);
641
641
  // --blue: var(--btntext);
642
642
 
@@ -45,6 +45,18 @@
45
45
  // finally
46
46
  --confirmation--dialog-scale: scale(0.7);
47
47
  --confirmation--dialog-opacity: 0.8;
48
+
49
+ --confirmation--inner-scale: scale3d(1, 1, 1);
50
+ }
51
+
52
+ :where(& > *) {
53
+ transform: var(--confirmation--inner-scale,);
54
+
55
+ transform-origin: top;
56
+ }
57
+
58
+ :where(& > :nth-child(1)) {
59
+ transform-origin: bottom;
48
60
  }
49
61
 
50
62
  &[open] {
@@ -61,9 +73,13 @@
61
73
  --confirmation--dialog-scale: scale(1);
62
74
  --confirmation--dialog-opacity: 1;
63
75
 
76
+ --confirmation--inner-scale: scale3d(1, 1, 1);
77
+
64
78
  @starting-style {
65
79
  --confirmation--dialog-scale: scale(0.7);
66
80
  --confirmation--dialog-opacity: 0.8;
81
+
82
+ --confirmation--inner-scale: scale3d(0, 0, 1);
67
83
  }
68
84
  }
69
85
  }
@@ -78,6 +94,8 @@
78
94
 
79
95
  --confirmation--dialog-scale: scale(0.7);
80
96
  --confirmation--dialog-opacity: 0;
97
+
98
+ --confirmation--inner-scale: scale3d(0, 0, 1);
81
99
  }
82
100
  }
83
101
  }
@@ -11,6 +11,15 @@
11
11
 
12
12
  row-gap: 1rem;
13
13
 
14
+ padding-inline: 1rem;
15
+ padding-block: 1rem;
16
+
17
+ &::part(content-unavailable-actions-stack),
18
+ &::part(content-unavailable-title-stack),
19
+ &::part(content-unavailable-description-stack) {
20
+ max-inline-size: 20rem;
21
+ }
22
+
14
23
  &::part(content-unavailable-actions-stack) {
15
24
  row-gap: 0.2rem;
16
25
  }
@@ -201,7 +201,7 @@ $label-line-ifs: (
201
201
  line-clamp: var(--label--line-clamp,);
202
202
  -webkit-line-clamp: var(--label--line-clamp,);
203
203
 
204
- text-decoration: underline;
204
+ // text-decoration: underline;
205
205
 
206
206
  font-size: var(--label--titlestack-font-size,);
207
207
 
@@ -13,6 +13,10 @@
13
13
  border-radius: var(--pill-border-radius);
14
14
 
15
15
  padding-inline: 1rem;
16
+
17
+ appearance: none;
18
+
19
+ outline: none;
16
20
  }
17
21
  }
18
22
  }
@@ -17,6 +17,11 @@
17
17
  transition: all var(--touchglass-transition-duration) allow-discrete ease-out;
18
18
  // will-change: block-size, inline-size, transform, overlay, display;
19
19
  }
20
+
21
+ :where(& > *) {
22
+ transition: transform var(--touchglass-transition-duration) allow-discrete ease-out;
23
+ will-change: transform;
24
+ }
20
25
  }
21
26
  }
22
27
  }