@swiftwc/ui 0.0.0-dev.95 → 0.0.0-dev.97

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 (63) hide show
  1. package/generated/client/index.js +7 -7
  2. package/generated/components/alert-dialog.d.ts +1 -1
  3. package/generated/components/alert-dialog.js +1 -1
  4. package/generated/components/content-unavailable.js +11 -11
  5. package/generated/components/date-picker.js +15 -15
  6. package/generated/components/fine-tooltip.d.ts +3 -0
  7. package/generated/components/fine-tooltip.js +5 -1
  8. package/generated/components/image-view.js +3 -2
  9. package/generated/components/label-view.d.ts +4 -0
  10. package/generated/components/label-view.js +11 -7
  11. package/generated/components/labeled-content.d.ts +5 -0
  12. package/generated/components/labeled-content.js +18 -12
  13. package/generated/components/menu-view.js +12 -12
  14. package/generated/components/navigation-title.js +2 -1
  15. package/generated/components/picker-view.d.ts +1 -1
  16. package/generated/components/picker-view.js +51 -50
  17. package/generated/components/progress-view.js +20 -19
  18. package/generated/components/scroll-view.js +14 -14
  19. package/generated/components/section-view.js +11 -11
  20. package/generated/components/table-view.js +34 -34
  21. package/generated/components/text-field.d.ts +2 -0
  22. package/generated/components/text-field.js +13 -11
  23. package/generated/components/toggle-view.js +30 -13
  24. package/generated/components/tool-bar.js +27 -27
  25. package/generated/css/index.css +67 -15
  26. package/generated/events/alert-dialog.d.ts +3 -0
  27. package/generated/events/confirmation-dialog.d.ts +3 -0
  28. package/generated/events/date-picker.d.ts +3 -0
  29. package/generated/events/lifecycle-observer.d.ts +4 -0
  30. package/generated/events/picker-view.d.ts +6 -0
  31. package/generated/events/scroll-view.d.ts +4 -0
  32. package/generated/events/tab-view.d.ts +10 -0
  33. package/generated/events/text-field.d.ts +3 -0
  34. package/generated/events/toggle-view.d.ts +3 -0
  35. package/generated/internal/utils/cash/index.d.ts +4 -3
  36. package/generated/internal/utils/cash/index.js +4 -2
  37. package/generated/internal/utils/ensure-placeholder.js +2 -1
  38. package/generated/morphdom/index.d.ts +4 -2
  39. package/generated/morphdom/index.js +4 -2
  40. package/generated/morphdom/morph.d.ts +2 -2
  41. package/generated/morphdom/morph.js +3 -2
  42. package/generated/morphdom/query-morph.d.ts +2 -2
  43. package/generated/morphdom/query-morph.js +1 -1
  44. package/generated/morphdom/render-to-string.d.ts +12 -0
  45. package/generated/morphdom/render-to-string.js +48 -0
  46. package/generated/morphdom/unsafe-html.d.ts +2 -0
  47. package/generated/morphdom/unsafe-html.js +4 -0
  48. package/generated/tpl/html.js +4 -0
  49. package/generated/tpl/index.d.ts +2 -0
  50. package/generated/tpl/index.js +2 -0
  51. package/generated/tpl/is-template-result.d.ts +3 -0
  52. package/generated/tpl/is-template-result.js +1 -0
  53. package/package.json +1 -1
  54. package/scss/_maps.scss +19 -13
  55. package/scss/base/_root.scss +1 -1
  56. package/scss/components/_picker-view.scss +7 -1
  57. package/scss/components/_scroll-view-toolbars.scss +8 -2
  58. package/scss/components/_toggle-view.scss +2 -1
  59. package/scss/mixins/_index.scss +8 -2
  60. package/scss/placeholders/_lists.scss +27 -1
  61. package/web-components.html-data/en.json +111 -128
  62. package/generated/morphdom/html.d.ts +0 -8
  63. package/generated/morphdom/html.js +0 -37
@@ -7,4 +7,7 @@ declare global {
7
7
  interface HTMLElementEventMap {
8
8
  selection: DatePickerSelectionEvent;
9
9
  }
10
+ interface DocumentEventMap {
11
+ selection: DatePickerSelectionEvent;
12
+ }
10
13
  }
@@ -11,4 +11,8 @@ declare global {
11
11
  pageshow: PageShowEvent;
12
12
  pagehide: PageHideEvent;
13
13
  }
14
+ interface DocumentEventMap {
15
+ pageshow: PageShowEvent;
16
+ pagehide: PageHideEvent;
17
+ }
14
18
  }
@@ -20,4 +20,10 @@ declare global {
20
20
  'picker:searchblur': PickerSearchblurEvent;
21
21
  'picker:searchinput': PickerSearchinputEvent;
22
22
  }
23
+ interface DocumentEventMap {
24
+ selection: PickerSelectionEvent;
25
+ 'picker:searchfocus': PickerSearchfocusEvent;
26
+ 'picker:searchblur': PickerSearchblurEvent;
27
+ 'picker:searchinput': PickerSearchinputEvent;
28
+ }
23
29
  }
@@ -11,4 +11,8 @@ declare global {
11
11
  pagereveal: PagerevealEvent;
12
12
  pageswap: PageswapEvent;
13
13
  }
14
+ interface DocumentEventMap {
15
+ pagereveal: PagerevealEvent;
16
+ pageswap: PageswapEvent;
17
+ }
14
18
  }
@@ -41,4 +41,14 @@ declare global {
41
41
  'tab-view:toggle': TabViewToggleEvent;
42
42
  'tab-view:adaptable-tab-bar-placement-change': TabViewAdaptableTabBarPlacementChangeEvent;
43
43
  }
44
+ interface DocumentEventMap {
45
+ tabshow: TabshowEvent;
46
+ tabhide: TabhideEvent;
47
+ tabreveal: TabrevealEvent;
48
+ tabswap: TabswapEvent;
49
+ beforetabreveal: BeforetabrevealEvent;
50
+ beforetabswap: BeforetabswapEvent;
51
+ 'tab-view:toggle': TabViewToggleEvent;
52
+ 'tab-view:adaptable-tab-bar-placement-change': TabViewAdaptableTabBarPlacementChangeEvent;
53
+ }
44
54
  }
@@ -7,4 +7,7 @@ declare global {
7
7
  interface HTMLElementEventMap {
8
8
  commit: TextFieldCommitEvent;
9
9
  }
10
+ interface DocumentEventMap {
11
+ commit: TextFieldCommitEvent;
12
+ }
10
13
  }
@@ -8,4 +8,7 @@ declare global {
8
8
  interface HTMLElementEventMap {
9
9
  'toggle:change': ToggleChangeEvent;
10
10
  }
11
+ interface DocumentEventMap {
12
+ 'toggle:change': ToggleChangeEvent;
13
+ }
11
14
  }
@@ -1,3 +1,4 @@
1
+ import { type TemplateResult } from '../../../tpl';
1
2
  import ancestors from './ancestors';
2
3
  import next from './next';
3
4
  import nextAll from './next-all';
@@ -7,9 +8,9 @@ import prop from './prop';
7
8
  import siblings from './siblings';
8
9
  declare const DEFAULT: ">1";
9
10
  interface CashFn {
10
- (innerHTML: string): DocumentFragment;
11
- <T extends Element = Element>(innerHTML: string, selector: typeof DEFAULT): T;
12
- <T extends Element = Element>(innerHTML: string, selector: string): T;
11
+ (markup: TemplateResult): DocumentFragment;
12
+ <T extends Element = Element>(markup: TemplateResult, selector: typeof DEFAULT): T;
13
+ <T extends Element = Element>(markup: TemplateResult, selector: string): T;
13
14
  prop: typeof prop;
14
15
  nextAll: typeof nextAll;
15
16
  prevAll: typeof prevAll;
@@ -1,3 +1,4 @@
1
+ import { renderToString } from '../../../morphdom';
1
2
  import ancestors from './ancestors';
2
3
  import next from './next';
3
4
  import nextAll from './next-all';
@@ -6,8 +7,9 @@ import prevAll from './prev-all';
6
7
  import prop from './prop';
7
8
  import siblings from './siblings';
8
9
  const DEFAULT = '>1';
9
- const cash = ((innerHTML, selector) => {
10
- const template = Object.assign(document.createElement('template'), { innerHTML });
10
+ const cash = ((markup, selector) => {
11
+ // NOTE: Use also runtime check isTemplateResult()??
12
+ const template = Object.assign(document.createElement('template'), { innerHTML: renderToString(markup).toString() });
11
13
  if (!selector)
12
14
  return template.content;
13
15
  if (selector === DEFAULT)
@@ -1,5 +1,6 @@
1
1
  import { I18n } from '../../i18n';
2
- import { html, queryMorph } from '../../morphdom';
2
+ import { queryMorph } from '../../morphdom';
3
+ import { html } from '../../tpl';
3
4
  export default function (target, role, titleKey, config) {
4
5
  if (!target)
5
6
  return;
@@ -1,6 +1,8 @@
1
- export { default as html } from './html';
2
- export * from './html';
3
1
  export { default as morph } from './morph';
4
2
  export * from './morph';
5
3
  export { default as queryMorph } from './query-morph';
6
4
  export * from './query-morph';
5
+ export { default as renderToString } from './render-to-string';
6
+ export * from './render-to-string';
7
+ export { default as unsafeHtml } from './unsafe-html';
8
+ export * from './unsafe-html';
@@ -1,6 +1,8 @@
1
- export { default as html } from './html';
2
- export * from './html';
3
1
  export { default as morph } from './morph';
4
2
  export * from './morph';
5
3
  export { default as queryMorph } from './query-morph';
6
4
  export * from './query-morph';
5
+ export { default as renderToString } from './render-to-string';
6
+ export * from './render-to-string';
7
+ export { default as unsafeHtml } from './unsafe-html';
8
+ export * from './unsafe-html';
@@ -1,4 +1,4 @@
1
- import type { TrustedMarkup } from './html';
2
- export default function (template: TrustedMarkup, fromEl?: Element, options?: {
1
+ import type { TemplateResult } from '../tpl';
2
+ export default function (markup: TemplateResult, fromEl?: Element, options?: {
3
3
  cb: () => void;
4
4
  }): void;
@@ -1,8 +1,9 @@
1
1
  import morphdom from '../internal/vendor/morphdom';
2
- export default function (template, fromEl, options) {
2
+ import renderToString from './render-to-string';
3
+ export default function (markup, fromEl, options) {
3
4
  if (!fromEl)
4
5
  return;
5
- morphdom(fromEl, template.toString(), {
6
+ morphdom(fromEl, renderToString(markup).toString(), {
6
7
  onBeforeElUpdated: (fromEl, toEl) => !fromEl.isEqualNode(toEl),
7
8
  onBeforeElChildrenUpdated: (fromEl, toEl) => !toEl.matches('image-view,navigation-title'), // NOTE: image-view will alter it's contents! This is required to not empty it up again!
8
9
  });
@@ -1,5 +1,5 @@
1
- import type { TrustedMarkup } from './html';
2
- export default function (scopedSelector: string, template: TrustedMarkup, container?: Element, options?: {
1
+ import type { TemplateResult } from '../tpl';
2
+ export default function (scopedSelector: string, template: TemplateResult, container?: Element, options?: {
3
3
  cb?: () => boolean;
4
4
  removeIf?: boolean;
5
5
  }): void;
@@ -5,7 +5,7 @@ export default function (scopedSelector, template, container, options) {
5
5
  return;
6
6
  if ('boolean' === typeof options?.removeIf && options?.removeIf)
7
7
  return container?.querySelector(`:scope>${scopedSelector}`)?.remove();
8
- const fromEl = container?.querySelector(`:scope>${scopedSelector}`) ?? container?.appendChild($(template.toString(), '>1'));
8
+ const fromEl = container?.querySelector(`:scope>${scopedSelector}`) ?? container?.appendChild($(template, '>1'));
9
9
  if (!fromEl)
10
10
  return;
11
11
  morph(template, fromEl);
@@ -0,0 +1,12 @@
1
+ import { type TemplateResult } from '../tpl';
2
+ export declare class TrustedMarkup {
3
+ readonly value: string;
4
+ constructor(value: string);
5
+ toString(): string;
6
+ }
7
+ /**
8
+ * Flatten a TemplateResult (from `html`) into an escaped TrustedMarkup
9
+ * string. Use this only at morph/queryMorph call sites — anywhere feeding
10
+ * `render()` should keep passing the raw TemplateResult straight through.
11
+ */
12
+ export default function renderToString(template: TemplateResult): TrustedMarkup;
@@ -0,0 +1,48 @@
1
+ import { isTemplateResult } from '../tpl';
2
+ // morph.ts and queryMorph.ts only need something with `.toString()` that
3
+ // yields a safe, escaped HTML string — this is that, built on top of the
4
+ // same TemplateResult instead of a separate tag function.
5
+ // values built via `raw` itself are trusted markup; wrap them so `stringify`
6
+ // knows to skip escaping — same idea as lit-html's `unsafeHTML`
7
+ export class TrustedMarkup {
8
+ value;
9
+ constructor(value) {
10
+ this.value = value;
11
+ }
12
+ toString() {
13
+ return this.value;
14
+ }
15
+ }
16
+ const ESCAPE_MAP = {
17
+ '&': '&amp;',
18
+ '<': '&lt;',
19
+ '>': '&gt;',
20
+ '"': '&quot;',
21
+ "'": '&#39;',
22
+ };
23
+ function escapeHtml(str) {
24
+ return str.replace(/[&<>"']/g, (ch) => ESCAPE_MAP[ch]);
25
+ }
26
+ function stringifyValue(value) {
27
+ if (value === null || value === undefined || value === false)
28
+ return '';
29
+ if (value instanceof TrustedMarkup)
30
+ return value.value;
31
+ if (isTemplateResult(value))
32
+ return renderToString(value).value;
33
+ if (Array.isArray(value))
34
+ return value.map(stringifyValue).join('');
35
+ return escapeHtml(String(value));
36
+ }
37
+ /**
38
+ * Flatten a TemplateResult (from `html`) into an escaped TrustedMarkup
39
+ * string. Use this only at morph/queryMorph call sites — anywhere feeding
40
+ * `render()` should keep passing the raw TemplateResult straight through.
41
+ */
42
+ export default function renderToString(template) {
43
+ let out = template.strings[0];
44
+ for (let i = 0; i < template.values.length; i++) {
45
+ out += stringifyValue(template.values[i]) + template.strings[i + 1];
46
+ }
47
+ return new TrustedMarkup(out.replace(/>\s+</g, '><').trim());
48
+ }
@@ -0,0 +1,2 @@
1
+ import { TrustedMarkup } from './render-to-string';
2
+ export default function (value: string): TrustedMarkup;
@@ -0,0 +1,4 @@
1
+ import { TrustedMarkup } from './render-to-string';
2
+ export default function (value) {
3
+ return new TrustedMarkup(value);
4
+ }
@@ -1,3 +1,7 @@
1
+ // Purely structural — captures strings/values as-is. render.ts relies on
2
+ // `strings` identity (TemplateStringsArray) for its template cache, so this
3
+ // must stay exactly this shape: no wrapping, no cloning, no new object
4
+ // allocation beyond the literal { strings, values }.
1
5
  export default function (strings, ...values) {
2
6
  return { strings, values };
3
7
  }
@@ -1,4 +1,6 @@
1
1
  export { default as html } from './html';
2
2
  export * from './html';
3
+ export { default as isTemplateResult } from './is-template-result';
4
+ export * from './is-template-result';
3
5
  export { default as render } from './render';
4
6
  export * from './render';
@@ -1,4 +1,6 @@
1
1
  export { default as html } from './html';
2
2
  export * from './html';
3
+ export { default as isTemplateResult } from './is-template-result';
4
+ export * from './is-template-result';
3
5
  export { default as render } from './render';
4
6
  export * from './render';
@@ -0,0 +1,3 @@
1
+ import type { TemplateResult } from './html';
2
+ declare const _default: (v: unknown) => v is TemplateResult;
3
+ export default _default;
@@ -0,0 +1 @@
1
+ export default (v) => !!v && typeof v === 'object' && 'strings' in v && 'values' in v;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swiftwc/ui",
3
- "version": "0.0.0-dev.95",
3
+ "version": "0.0.0-dev.97",
4
4
  "description": "Elegant SwiftUI-inspired web components for standalone web apps and web extensions.",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/scss/_maps.scss CHANGED
@@ -151,62 +151,67 @@ $block-placement-map: (
151
151
  $label-fonts-map: (
152
152
  footnote: (
153
153
  size: 1rem,
154
- line: 1rem,
154
+ leading: calc(1.1875 / 1),
155
155
  weight: 400,
156
156
  ),
157
157
  caption2: (
158
158
  size: 0.75rem,
159
- line: calc(1 / 0.75),
159
+ leading: calc(1.0625 / 0.75),
160
160
  weight: 400,
161
161
  ),
162
162
  caption: (
163
- size: 0.875rem,
164
- line: calc(1.25 / 0.875),
163
+ size: 0.8125rem,
164
+ leading: calc(1.25 / 0.8125),
165
165
  weight: 400,
166
166
  ),
167
167
  callout: (
168
168
  size: 0.875rem,
169
- line: 0.875rem,
169
+ leading: calc(1.1875 / 0.875),
170
170
  weight: 400,
171
171
  ),
172
172
  body: (
173
173
  size: 1rem,
174
- line: calc(1.5 / 1),
174
+ leading: calc(1.5 / 1),
175
175
  weight: 400,
176
176
  ),
177
177
  subheadline: (
178
178
  size: 1.125rem,
179
- line: calc(1.75 / 1.125),
179
+ leading: calc(1.6875 / 1.125),
180
180
  weight: 400,
181
181
  ),
182
182
  headline: (
183
183
  size: 1.25rem,
184
- line: calc(1.75 / 1.25),
184
+ leading: calc(1.75 / 1.25),
185
185
  weight: 500,
186
186
  ),
187
187
  title3: (
188
188
  size: 1.5rem,
189
- line: calc(2 / 1.5),
189
+ leading: calc(2 / 1.5),
190
190
  weight: 600,
191
191
  ),
192
192
  title2: (
193
193
  size: 1.875rem,
194
- line: calc(2.25 / 1.875),
194
+ leading: calc(2.25 / 1.875),
195
195
  weight: 600,
196
196
  ),
197
197
  title: (
198
198
  size: 2.25rem,
199
- line: calc(2.5 / 2.25),
199
+ leading: calc(2.5 / 2.25),
200
200
  weight: 600,
201
201
  ),
202
202
  large-title: (
203
203
  size: 3rem,
204
- line: 1,
204
+ leading: 1,
205
205
  weight: 700,
206
206
  ),
207
207
  extra-large-title: (
208
208
  size: 3.75rem,
209
- line: 1,
209
+ leading: 1,
210
+ weight: 700,
211
+ ),
212
+ extra-large-title2: (
213
+ size: 4.5rem,
214
+ leading: 1,
210
215
  weight: 700,
211
216
  ),
212
217
  );
@@ -258,6 +263,7 @@ $button-sizes-map: (
258
263
  $tint-names: gray, blue, red, green, orange, purple;
259
264
 
260
265
  $foreground-tokens: (
266
+ primary: --primary,
261
267
  secondary: --secondary,
262
268
  blue: --blue,
263
269
  red: --red,
@@ -234,7 +234,7 @@
234
234
 
235
235
  @each $label, $props in maps.$label-fonts-map {
236
236
  --label-#{$label}-font-size: #{map.get($props, size)};
237
- --label-#{$label}-line-height: #{map.get($props, line)};
237
+ --label-#{$label}-line-height: #{map.get($props, leading)};
238
238
  --label-#{$label}-font-weight: #{map.get($props, weight)};
239
239
  }
240
240
 
@@ -152,13 +152,19 @@ $picker-ifs: (
152
152
  &::part(picker-label-stack) {
153
153
  display: var(--picker--labelstack-display, none); // display: none;
154
154
 
155
- color: var(--secondary);
155
+ // color: var(--secondary);
156
156
 
157
157
  --label-truncation-mode: tail;
158
158
 
159
159
  --label-line-limit: 1;
160
160
  }
161
161
 
162
+ form & {
163
+ :where(&)::part(picker-label-stack) {
164
+ color: var(--secondary);
165
+ }
166
+ }
167
+
162
168
  --picker--stack-grid-template-columns: minmax(30%, 1fr) auto;
163
169
 
164
170
  --picker--stack-grid-template-rows: minmax(0, 1fr);
@@ -25,8 +25,14 @@
25
25
  }
26
26
  }
27
27
 
28
- scroll-view:has(~ tool-bar > [slot^='top-bar']),
29
- scroll-view:has(> [slot^='top-bar']) {
28
+ scroll-view:has(
29
+ ~ tool-bar > [slot^='top-bar'],
30
+ ~ tool-bar > [slot='cancellation-action'],
31
+ ~ tool-bar > [slot='primary-action'],
32
+ ~ tool-bar > [slot='confirmation-action'],
33
+ ~ tool-bar > [slot='destructive-action']
34
+ ),
35
+ scroll-view:has(> [slot^='top-bar'], > [slot='cancellation-action'], > [slot='primary-action'], > [slot='confirmation-action'], > [slot='destructive-action']) {
30
36
  :where(&)::part(scroll-view-navbar) {
31
37
  visibility: visible;
32
38
  }
@@ -20,7 +20,8 @@
20
20
  }
21
21
 
22
22
  // &::part(toggle-label-stack) {
23
- // color: var(--secondary);
23
+ // // color: var(--secondary);
24
+ // padding-inline-start: var(--toggle-padding-inline-start,);
24
25
  // }
25
26
 
26
27
  &::part(toggle-input-stack) {
@@ -80,8 +80,14 @@
80
80
  grid-area: main;
81
81
  }
82
82
 
83
- &:has(~ tool-bar > [slot^='top-bar']),
84
- &:has(> [slot^='top-bar']) {
83
+ &:has(
84
+ ~ tool-bar > [slot^='top-bar'],
85
+ ~ tool-bar > [slot='cancellation-action'],
86
+ ~ tool-bar > [slot='primary-action'],
87
+ ~ tool-bar > [slot='confirmation-action'],
88
+ ~ tool-bar > [slot='destructive-action']
89
+ ),
90
+ &:has(> [slot^='top-bar'], > [slot='cancellation-action'], > [slot='primary-action'], > [slot='confirmation-action'], > [slot='destructive-action']) {
85
91
  grid-template-rows: var(--navigation-bar-block-size) minmax(max-content, 1fr);
86
92
  }
87
93
  }
@@ -364,7 +364,7 @@ $list-item-selector: ':not([slot], section-view, [is="disclosure-group"], picker
364
364
  }
365
365
 
366
366
  &::part(section-header-stack) {
367
- top: calc(var(--list--sticky-block-size, 0px) + var(--navigation-bar-block-size));
367
+ top: var(--list--sticky-block-size, 0px); // + var(--navigation-bar-block-size));
368
368
 
369
369
  position: sticky;
370
370
 
@@ -373,6 +373,32 @@ $list-item-selector: ':not([slot], section-view, [is="disclosure-group"], picker
373
373
  // text-shadow: 0 0 5px var(--face);
374
374
  }
375
375
  }
376
+
377
+ // &:is([list-style*='inset'] section-view, [form-style*='inset'] section-view) {
378
+ // :where(&) {
379
+ // &::part(section-header-stack) {
380
+ // top: calc(var(--list--sticky-block-size, 0px) + 1rem);
381
+ // }
382
+ // }
383
+ // }
384
+
385
+ &:is(
386
+ scroll-view:has(
387
+ ~ tool-bar > [slot^='top-bar'],
388
+ ~ tool-bar > [slot='cancellation-action'],
389
+ ~ tool-bar > [slot='primary-action'],
390
+ ~ tool-bar > [slot='confirmation-action'],
391
+ ~ tool-bar > [slot='destructive-action']
392
+ )
393
+ section-view,
394
+ scroll-view:has(> [slot^='top-bar'], > [slot='cancellation-action'], > [slot='primary-action'], > [slot='confirmation-action'], > [slot='destructive-action']) section-view
395
+ ) {
396
+ :where(&) {
397
+ &::part(section-header-stack) {
398
+ top: calc(var(--list--sticky-block-size, 0px) + var(--navigation-bar-block-size));
399
+ }
400
+ }
401
+ }
376
402
  }
377
403
 
378
404
  // SECTION: Enable 2-col layout