@styleflow.app/flowpress-astro-core 1.0.0-beta.1 → 1.0.0-beta.11

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 (74) hide show
  1. package/CHANGELOG.md +87 -1
  2. package/README.md +96 -3
  3. package/dist/astro/BaseLayout.astro +5 -1
  4. package/dist/astro/CompositionRenderer.astro +127 -0
  5. package/dist/astro/DefaultBlockAdapter.astro +35 -0
  6. package/dist/astro/DefaultTemplate.astro +6 -1
  7. package/dist/astro/GutenbergRenderer.astro +215 -55
  8. package/dist/astro/ThemeRuntime.astro +24 -0
  9. package/dist/astro/blocks/CarouselBlock.astro +198 -0
  10. package/dist/astro/blocks/CarouselItemBlock.astro +26 -0
  11. package/dist/astro/blocks/ColumnBlock.astro +2 -3
  12. package/dist/astro/blocks/FormBlock.astro +5 -5
  13. package/dist/astro/blocks/GridBlock.astro +2 -2
  14. package/dist/astro/blocks/HeroBlock.astro +2 -3
  15. package/dist/astro/blocks/ImageBlock.astro +2 -3
  16. package/dist/astro/blocks/ListItemFallback.astro +7 -5
  17. package/dist/astro/blocks/NumberSpinnerBlock.astro +24 -18
  18. package/dist/astro/blocks/SemanticElement.astro +35 -0
  19. package/dist/astro/blocks/SiteLogoBlock.astro +53 -0
  20. package/dist/astro/blocks/TextBlock.astro +27 -23
  21. package/dist/astro/blocks/ThemeToggleBlock.astro +23 -0
  22. package/dist/astro/blocks/helpers.d.ts +7 -0
  23. package/dist/astro/blocks/helpers.d.ts.map +1 -1
  24. package/dist/astro/blocks/helpers.js +51 -41
  25. package/dist/astro/blocks/helpers.js.map +1 -1
  26. package/dist/astro/blocks/helpers.ts +63 -45
  27. package/dist/block-renderers.d.ts +19 -2
  28. package/dist/block-renderers.d.ts.map +1 -1
  29. package/dist/block-renderers.js.map +1 -1
  30. package/dist/carousel.d.ts +22 -0
  31. package/dist/carousel.d.ts.map +1 -0
  32. package/dist/carousel.js +102 -0
  33. package/dist/carousel.js.map +1 -0
  34. package/dist/client.d.ts +2 -1
  35. package/dist/client.d.ts.map +1 -1
  36. package/dist/client.js +31 -0
  37. package/dist/client.js.map +1 -1
  38. package/dist/composition.d.ts +14 -0
  39. package/dist/composition.d.ts.map +1 -0
  40. package/dist/composition.js +124 -0
  41. package/dist/composition.js.map +1 -0
  42. package/dist/default-blocks.d.ts +9 -0
  43. package/dist/default-blocks.d.ts.map +1 -0
  44. package/dist/default-blocks.js +54 -0
  45. package/dist/default-blocks.js.map +1 -0
  46. package/dist/env.d.ts +9 -0
  47. package/dist/env.d.ts.map +1 -1
  48. package/dist/env.js +20 -0
  49. package/dist/env.js.map +1 -1
  50. package/dist/index.d.ts +6 -0
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +6 -0
  53. package/dist/index.js.map +1 -1
  54. package/dist/links.d.ts +5 -0
  55. package/dist/links.d.ts.map +1 -0
  56. package/dist/links.js +32 -0
  57. package/dist/links.js.map +1 -0
  58. package/dist/media.d.ts +8 -0
  59. package/dist/media.d.ts.map +1 -0
  60. package/dist/media.js +121 -0
  61. package/dist/media.js.map +1 -0
  62. package/dist/styleflow.d.ts +2 -0
  63. package/dist/styleflow.d.ts.map +1 -1
  64. package/dist/styleflow.js +47 -5
  65. package/dist/styleflow.js.map +1 -1
  66. package/dist/theme-runtime.d.ts +16 -0
  67. package/dist/theme-runtime.d.ts.map +1 -0
  68. package/dist/theme-runtime.js +77 -0
  69. package/dist/theme-runtime.js.map +1 -0
  70. package/dist/tsconfig.tsbuildinfo +1 -1
  71. package/dist/types.d.ts +84 -1
  72. package/dist/types.d.ts.map +1 -1
  73. package/dist/types.js.map +1 -1
  74. package/package.json +9 -3
@@ -0,0 +1,198 @@
1
+ ---
2
+ import "@splidejs/splide/css/core";
3
+ import S from "@styleflow.app/astro/S.astro";
4
+ import { carouselOptions, carouselSettings } from "../../carousel.js";
5
+ import type { FlowpressBlock } from "../../types.js";
6
+ import type { StyleflowContract } from "../../styleflow.js";
7
+ import { blockHtmlAttributes, semanticProps } from "./helpers.js";
8
+
9
+ interface Props {
10
+ block: FlowpressBlock;
11
+ contract?: StyleflowContract;
12
+ validChildren: boolean;
13
+ invalidChildNames?: string[];
14
+ }
15
+
16
+ const { block, contract, validChildren, invalidChildNames = [] } = Astro.props;
17
+ const settings = carouselSettings(block.attributes);
18
+ const options = carouselOptions(settings);
19
+ const semantic = semanticProps(block.attributes, contract, {
20
+ surface: "default",
21
+ layoutRole: "container",
22
+ density: "regular"
23
+ });
24
+ const htmlAttributes = blockHtmlAttributes(
25
+ block.attributes,
26
+ `flowpress-carousel${validChildren ? " splide" : " flowpress-carousel--static"}`
27
+ );
28
+ const style = [
29
+ `--flowpress-carousel-gap:${settings.gap}px`,
30
+ `--flowpress-carousel-base:${settings.itemsPerView.base}`,
31
+ `--flowpress-carousel-sm:${settings.itemsPerView.sm}`,
32
+ `--flowpress-carousel-md:${settings.itemsPerView.md}`,
33
+ `--flowpress-carousel-lg:${settings.itemsPerView.lg}`,
34
+ `--flowpress-carousel-xl:${settings.itemsPerView.xl}`,
35
+ `--flowpress-carousel-2xl:${settings.itemsPerView["2xl"]}`
36
+ ].join(";");
37
+
38
+ if (!validChildren && import.meta.env.DEV) {
39
+ console.warn(
40
+ `[flowpress-carousel-invalid-children] sf/carousel accepts only sf/carousel-item; received: ${invalidChildNames.join(", ") || "unknown"}. Rendering static content.`
41
+ );
42
+ }
43
+ ---
44
+
45
+ {validChildren ? (
46
+ <flowpress-carousel>
47
+ <S.section
48
+ {...semantic}
49
+ {...htmlAttributes}
50
+ aria-label={settings.ariaLabel}
51
+ data-flowpress-carousel-root
52
+ data-carousel-options={JSON.stringify(options)}
53
+ style={style}
54
+ >
55
+ {settings.showArrows ? (
56
+ <div class="splide__arrows" data-flowpress-carousel-controls>
57
+ <button class="splide__arrow splide__arrow--prev" type="button">
58
+ <span aria-hidden="true">←</span>
59
+ </button>
60
+ <button class="splide__arrow splide__arrow--next" type="button">
61
+ <span aria-hidden="true">→</span>
62
+ </button>
63
+ </div>
64
+ ) : null}
65
+ <div class="splide__track">
66
+ <ul class="splide__list">
67
+ <slot />
68
+ </ul>
69
+ </div>
70
+ {settings.showPagination ? <ul class="splide__pagination"></ul> : null}
71
+ {settings.autoplay ? (
72
+ <button
73
+ class="splide__toggle"
74
+ type="button"
75
+ data-flowpress-carousel-controls
76
+ >
77
+ <span class="splide__toggle__play">Avvia</span>
78
+ <span class="splide__toggle__pause">Pausa</span>
79
+ </button>
80
+ ) : null}
81
+ </S.section>
82
+ </flowpress-carousel>
83
+ ) : (
84
+ <S.section
85
+ {...semantic}
86
+ {...htmlAttributes}
87
+ aria-label={settings.ariaLabel}
88
+ data-flowpress-carousel-invalid
89
+ data-invalid-children={invalidChildNames.join(",")}
90
+ style={style}
91
+ >
92
+ <slot />
93
+ </S.section>
94
+ )}
95
+
96
+ <script>
97
+ import Splide from "@splidejs/splide";
98
+ import type { Options } from "@splidejs/splide";
99
+
100
+ if (!customElements.get("flowpress-carousel")) {
101
+ customElements.define("flowpress-carousel", class extends HTMLElement {
102
+ private instance?: Splide;
103
+
104
+ connectedCallback() {
105
+ if (this.instance) return;
106
+ const root = this.querySelector<HTMLElement>("[data-flowpress-carousel-root]");
107
+ if (!root) return;
108
+ try {
109
+ const options = JSON.parse(root.dataset.carouselOptions || "{}") as Options;
110
+ this.instance = new Splide(root, options);
111
+ this.instance.mount();
112
+ } catch (error) {
113
+ console.error("[flowpress-carousel-init] Unable to initialize carousel.", error);
114
+ }
115
+ }
116
+
117
+ disconnectedCallback() {
118
+ this.instance?.destroy(true);
119
+ this.instance = undefined;
120
+ }
121
+ });
122
+ }
123
+ </script>
124
+
125
+ <style>
126
+ flowpress-carousel { display: block; }
127
+ .flowpress-carousel { min-width: 0; }
128
+ .flowpress-carousel:not(.is-initialized) .splide__list {
129
+ display: grid;
130
+ grid-template-columns: repeat(var(--flowpress-carousel-base), minmax(0, 1fr));
131
+ gap: var(--flowpress-carousel-gap);
132
+ }
133
+ .flowpress-carousel:not(.is-initialized) [data-flowpress-carousel-controls],
134
+ .flowpress-carousel:not(.is-initialized) .splide__pagination {
135
+ display: none;
136
+ }
137
+ .flowpress-carousel--static {
138
+ display: grid;
139
+ gap: var(--flowpress-carousel-gap);
140
+ }
141
+ .splide__arrows {
142
+ display: flex;
143
+ justify-content: space-between;
144
+ gap: 0.5rem;
145
+ margin-block-end: 0.75rem;
146
+ }
147
+ .splide__arrow:disabled { opacity: 0.45; }
148
+ .splide__pagination {
149
+ display: flex;
150
+ justify-content: center;
151
+ gap: 0.5rem;
152
+ margin: 0.75rem 0 0;
153
+ padding: 0;
154
+ }
155
+ :global(.splide__pagination__page) {
156
+ width: 0.75rem;
157
+ height: 0.75rem;
158
+ border-radius: 999px;
159
+ }
160
+ .splide__toggle { margin-block-start: 0.75rem; }
161
+ .splide__toggle__pause { display: none; }
162
+ .splide__toggle.is-active .splide__toggle__play { display: none; }
163
+ .splide__toggle.is-active .splide__toggle__pause { display: inline; }
164
+ .splide__arrow:focus-visible,
165
+ :global(.splide__pagination__page:focus-visible),
166
+ .splide__toggle:focus-visible {
167
+ outline: 3px solid currentColor;
168
+ outline-offset: 3px;
169
+ }
170
+ @media (min-width: 40rem) {
171
+ .flowpress-carousel:not(.is-initialized) .splide__list {
172
+ grid-template-columns: repeat(var(--flowpress-carousel-sm), minmax(0, 1fr));
173
+ }
174
+ }
175
+ @media (min-width: 48rem) {
176
+ .flowpress-carousel:not(.is-initialized) .splide__list {
177
+ grid-template-columns: repeat(var(--flowpress-carousel-md), minmax(0, 1fr));
178
+ }
179
+ }
180
+ @media (min-width: 64rem) {
181
+ .flowpress-carousel:not(.is-initialized) .splide__list {
182
+ grid-template-columns: repeat(var(--flowpress-carousel-lg), minmax(0, 1fr));
183
+ }
184
+ }
185
+ @media (min-width: 80rem) {
186
+ .flowpress-carousel:not(.is-initialized) .splide__list {
187
+ grid-template-columns: repeat(var(--flowpress-carousel-xl), minmax(0, 1fr));
188
+ }
189
+ }
190
+ @media (min-width: 96rem) {
191
+ .flowpress-carousel:not(.is-initialized) .splide__list {
192
+ grid-template-columns: repeat(var(--flowpress-carousel-2xl), minmax(0, 1fr));
193
+ }
194
+ }
195
+ @media (prefers-reduced-motion: reduce) {
196
+ .flowpress-carousel * { scroll-behavior: auto !important; }
197
+ }
198
+ </style>
@@ -0,0 +1,26 @@
1
+ ---
2
+ import S from "@styleflow.app/astro/S.astro";
3
+ import type { FlowpressBlock } from "../../types.js";
4
+ import type { StyleflowContract } from "../../styleflow.js";
5
+ import { blockHtmlAttributes, semanticProps } from "./helpers.js";
6
+
7
+ interface Props {
8
+ block: FlowpressBlock;
9
+ contract?: StyleflowContract;
10
+ }
11
+
12
+ const { block, contract } = Astro.props;
13
+ const semantic = semanticProps(block.attributes, contract);
14
+ const htmlAttributes = blockHtmlAttributes(
15
+ block.attributes,
16
+ "splide__slide flowpress-carousel-item"
17
+ );
18
+ ---
19
+
20
+ <S.li {...semantic} {...htmlAttributes}>
21
+ <slot />
22
+ </S.li>
23
+
24
+ <style>
25
+ .flowpress-carousel-item { min-width: 0; }
26
+ </style>
@@ -33,8 +33,7 @@ const style = [
33
33
  ].join(";");
34
34
  ---
35
35
 
36
- <S
37
- as="div"
36
+ <S.div
38
37
  {...semantic}
39
38
  {...htmlAttributes}
40
39
  data-partial={partial}
@@ -42,7 +41,7 @@ const style = [
42
41
  style={style}
43
42
  >
44
43
  <slot />
45
- </S>
44
+ </S.div>
46
45
 
47
46
  <style>
48
47
  .flowpress-column {
@@ -39,11 +39,11 @@ const optionLabel = (field: FormField, index: number): string =>
39
39
  ---
40
40
 
41
41
  {schema?.available ? (
42
- <S as="div" {...semantic} {...htmlAttributes}>
42
+ <S.div {...semantic} {...htmlAttributes}>
43
43
  <flowpress-cf7-form>
44
44
  <form action={schema.submitUrl} method="post" enctype="multipart/form-data" novalidate>
45
45
  {block.attributes.title || schema.title ? (
46
- <S as="h2">{String(block.attributes.title || schema.title)}</S>
46
+ <S.h2>{String(block.attributes.title || schema.title)}</S.h2>
47
47
  ) : null}
48
48
  {schema.fields.map((field) => {
49
49
  if (field.type === "submit") {
@@ -130,11 +130,11 @@ const optionLabel = (field: FormField, index: number): string =>
130
130
  <p data-form-status role="status" aria-live="polite"></p>
131
131
  </form>
132
132
  </flowpress-cf7-form>
133
- </S>
133
+ </S.div>
134
134
  ) : (
135
- <S as="p" {...semantic} {...htmlAttributes} role="status">
135
+ <S.p {...semantic} {...htmlAttributes} role="status">
136
136
  Il modulo non è temporaneamente disponibile.
137
- </S>
137
+ </S.p>
138
138
  )}
139
139
 
140
140
  <script>
@@ -38,9 +38,9 @@ const style = [
38
38
  ].join(";");
39
39
  ---
40
40
 
41
- <S as="div" {...semantic} {...htmlAttributes} data-align={align} style={style}>
41
+ <S.div {...semantic} {...htmlAttributes} data-align={align} style={style}>
42
42
  <slot />
43
- </S>
43
+ </S.div>
44
44
 
45
45
  <style>
46
46
  .flowpress-grid {
@@ -34,8 +34,7 @@ const scrimEnabled = Boolean(attributes.scrimEnabled) && backgroundType !== "col
34
34
  const scrimIntensity = Math.min(10, Math.max(1, Number(attributes.scrimIntensity) || 6));
35
35
  ---
36
36
 
37
- <S
38
- as="section"
37
+ <S.section
39
38
  {...semantic}
40
39
  {...htmlAttributes}
41
40
  style={[
@@ -71,7 +70,7 @@ const scrimIntensity = Math.min(10, Math.max(1, Number(attributes.scrimIntensity
71
70
  <div class="flowpress-hero__content">
72
71
  <slot />
73
72
  </div>
74
- </S>
73
+ </S.section>
75
74
 
76
75
  <style>
77
76
  .flowpress-hero {
@@ -69,8 +69,7 @@ const fetchPriority = fetchPriorityValue(attributes.fetchPriority);
69
69
  ---
70
70
 
71
71
  {src ? (
72
- <S
73
- as="div"
72
+ <S.div
74
73
  {...semanticProps(attributes, contract)}
75
74
  {...blockHtmlAttributes(attributes)}
76
75
  >
@@ -86,5 +85,5 @@ const fetchPriority = fetchPriorityValue(attributes.fetchPriority);
86
85
  decoding={decoding}
87
86
  fetchpriority={fetchPriority}
88
87
  />
89
- </S>
88
+ </S.div>
90
89
  ) : null}
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  import S from "@styleflow.app/astro/S.astro";
3
+ import { flowpressLinkHref } from "../../links.js";
3
4
 
4
5
  interface Props {
5
6
  item: Record<string, unknown>;
@@ -9,6 +10,7 @@ const { item } = Astro.props;
9
10
  const image = item.image && typeof item.image === "object" && !Array.isArray(item.image)
10
11
  ? item.image as Record<string, unknown>
11
12
  : {};
13
+ const href = flowpressLinkHref(item.uri);
12
14
  ---
13
15
 
14
16
  {image.url ? (
@@ -19,10 +21,10 @@ const image = item.image && typeof item.image === "object" && !Array.isArray(ite
19
21
  decoding="async"
20
22
  />
21
23
  ) : null}
22
- {item.uri ? (
23
- <S as="a" href={String(item.uri)}>{String(item.title ?? "")}</S>
24
+ {href ? (
25
+ <S.a href={href}>{String(item.title ?? "")}</S.a>
24
26
  ) : (
25
- <S as="span">{String(item.title ?? "")}</S>
27
+ <S.span>{String(item.title ?? "")}</S.span>
26
28
  )}
27
- {item.excerpt ? <S as="p">{String(item.excerpt)}</S> : null}
28
- {item.priceHtml ? <S as="div" set:html={String(item.priceHtml)} /> : null}
29
+ {item.excerpt ? <S.p>{String(item.excerpt)}</S.p> : null}
30
+ {item.priceHtml ? <S.div set:html={String(item.priceHtml)} /> : null}
@@ -12,6 +12,7 @@ import {
12
12
  semanticProps,
13
13
  textHtmlTag
14
14
  } from "./helpers.js";
15
+ import SemanticElement from "./SemanticElement.astro";
15
16
 
16
17
  interface Props {
17
18
  block: FlowpressBlock;
@@ -56,8 +57,7 @@ const numberTag = textHtmlTag(attributes.numberTag);
56
57
  const suffixTag = textHtmlTag(attributes.suffixTag);
57
58
  ---
58
59
 
59
- <S
60
- as="div"
60
+ <S.div
61
61
  {...semantic}
62
62
  {...htmlAttributes}
63
63
  data-flowpress-number-spinner
@@ -67,18 +67,22 @@ const suffixTag = textHtmlTag(attributes.suffixTag);
67
67
  data-spinner-locale={locale || undefined}
68
68
  >
69
69
  {prefix ? (
70
- <S
71
- as={prefixTag}
72
- class="flowpress-number-spinner__segment"
73
- {...prefixSemantic}
70
+ <SemanticElement
71
+ tag={prefixTag}
72
+ attributes={{
73
+ class: "flowpress-number-spinner__segment",
74
+ ...prefixSemantic
75
+ }}
74
76
  >
75
77
  {prefix}
76
- </S>
78
+ </SemanticElement>
77
79
  ) : null}
78
- <S
79
- as={numberTag}
80
- class="flowpress-number-spinner__segment flowpress-number-spinner__number"
81
- {...numberSemantic}
80
+ <SemanticElement
81
+ tag={numberTag}
82
+ attributes={{
83
+ class: "flowpress-number-spinner__segment flowpress-number-spinner__number",
84
+ ...numberSemantic
85
+ }}
82
86
  >
83
87
  <span class="flowpress-number-spinner__accessible-value">
84
88
  {numberText}
@@ -89,17 +93,19 @@ const suffixTag = textHtmlTag(attributes.suffixTag);
89
93
  >
90
94
  {numberText}
91
95
  </span>
92
- </S>
96
+ </SemanticElement>
93
97
  {suffix ? (
94
- <S
95
- as={suffixTag}
96
- class="flowpress-number-spinner__segment"
97
- {...suffixSemantic}
98
+ <SemanticElement
99
+ tag={suffixTag}
100
+ attributes={{
101
+ class: "flowpress-number-spinner__segment",
102
+ ...suffixSemantic
103
+ }}
98
104
  >
99
105
  {suffix}
100
- </S>
106
+ </SemanticElement>
101
107
  ) : null}
102
- </S>
108
+ </S.div>
103
109
 
104
110
  <script>
105
111
  import { initializeNumberSpinners } from "../../number-spinner.js";
@@ -0,0 +1,35 @@
1
+ ---
2
+ import S from "@styleflow.app/astro/S.astro";
3
+
4
+ type SemanticElementTag =
5
+ | "div" | "span" | "p" | "a" | "li" | "ol" | "ul" | "blockquote"
6
+ | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "strong" | "em"
7
+ | "small" | "mark";
8
+
9
+ interface Props {
10
+ tag: SemanticElementTag;
11
+ attributes?: Record<string, unknown>;
12
+ html?: string;
13
+ }
14
+
15
+ const { tag, attributes = {}, html } = Astro.props;
16
+ ---
17
+
18
+ {tag === "div" ? <S.div {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.div>
19
+ : tag === "span" ? <S.span {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.span>
20
+ : tag === "p" ? <S.p {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.p>
21
+ : tag === "a" ? <S.a {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.a>
22
+ : tag === "li" ? <S.li {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.li>
23
+ : tag === "ol" ? <S.ol {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.ol>
24
+ : tag === "ul" ? <S.ul {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.ul>
25
+ : tag === "blockquote" ? <S.blockquote {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.blockquote>
26
+ : tag === "h1" ? <S.h1 {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.h1>
27
+ : tag === "h2" ? <S.h2 {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.h2>
28
+ : tag === "h3" ? <S.h3 {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.h3>
29
+ : tag === "h4" ? <S.h4 {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.h4>
30
+ : tag === "h5" ? <S.h5 {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.h5>
31
+ : tag === "h6" ? <S.h6 {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.h6>
32
+ : tag === "strong" ? <S.strong {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.strong>
33
+ : tag === "em" ? <S.em {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.em>
34
+ : tag === "small" ? <S.small {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.small>
35
+ : <S.mark {...attributes}>{html === undefined ? <slot /> : <Fragment set:html={html} />}</S.mark>}
@@ -0,0 +1,53 @@
1
+ ---
2
+ import S from "@styleflow.app/astro/S.astro";
3
+ import type { FlowpressBlockRendererProps } from "../../block-renderers.js";
4
+
5
+ type LogoImage = { url?: string; width?: number; height?: number; alt?: string };
6
+ type LogoData = {
7
+ images?: { positive?: LogoImage; negative?: LogoImage };
8
+ homeUrl?: string;
9
+ override?: "auto" | "positive" | "negative";
10
+ };
11
+
12
+ const { block, styleflowProps, htmlProps } = Astro.props as FlowpressBlockRendererProps;
13
+ const data = (block.resolvedData ?? {}) as LogoData;
14
+ const positive = data.images?.positive ?? {};
15
+ const negative = data.images?.negative ?? {};
16
+ const homeUrl = typeof data.homeUrl === "string" && data.homeUrl ? data.homeUrl : "/";
17
+ const override = data.override === "positive" || data.override === "negative"
18
+ ? data.override
19
+ : "auto";
20
+ const rootHtmlProps = {
21
+ ...htmlProps,
22
+ class: ["flowpress-site-logo", htmlProps.class].filter(Boolean).join(" ")
23
+ };
24
+ ---
25
+
26
+ {positive.url || negative.url ? (
27
+ <S.a
28
+ {...rootHtmlProps}
29
+ {...styleflowProps}
30
+ href={homeUrl}
31
+ data-flowpress-logo-override={override === "auto" ? undefined : override}
32
+ aria-label="Home"
33
+ >
34
+ {positive.url ? (
35
+ <img
36
+ class="flowpress-site-logo__image flowpress-site-logo__image--positive"
37
+ src={positive.url}
38
+ width={positive.width || undefined}
39
+ height={positive.height || undefined}
40
+ alt={positive.alt ?? ""}
41
+ />
42
+ ) : null}
43
+ {negative.url ? (
44
+ <img
45
+ class="flowpress-site-logo__image flowpress-site-logo__image--negative"
46
+ src={negative.url}
47
+ width={negative.width || undefined}
48
+ height={negative.height || undefined}
49
+ alt={negative.alt ?? ""}
50
+ />
51
+ ) : null}
52
+ </S.a>
53
+ ) : null}
@@ -7,10 +7,12 @@ import {
7
7
  preserveEmptyTextBlock,
8
8
  preserveRichTextSpacing,
9
9
  semanticProps,
10
+ textBlockSemanticDefaults,
10
11
  textAlignmentStyle,
11
12
  textValue,
12
13
  unwrapCoreHtml
13
14
  } from "./helpers.js";
15
+ import SemanticElement from "./SemanticElement.astro";
14
16
 
15
17
  interface Props {
16
18
  block: FlowpressBlock;
@@ -24,19 +26,7 @@ const attributes = block.attributes;
24
26
  const heading = name === "heading" || name === "core/heading";
25
27
  const level = Math.min(6, Math.max(1, Number(attributes.level ?? 2)));
26
28
  const headingTag = `h${level}` as "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
27
- const defaults = heading
28
- ? {
29
- ty: "heading",
30
- v: String(attributes.v ?? attributes.variant ?? level),
31
- w: String(attributes.w ?? attributes.weight ?? "strong"),
32
- foreground: "primary"
33
- }
34
- : {
35
- ty: "body",
36
- v: String(attributes.v ?? (name.includes("quote") ? "lg" : "md")),
37
- w: String(attributes.w ?? "default"),
38
- foreground: "primary"
39
- };
29
+ const defaults = textBlockSemanticDefaults(name, attributes, contract);
40
30
  const semantic = semanticProps(attributes, contract, defaults);
41
31
  const htmlAttributes = blockHtmlAttributes(attributes);
42
32
  const alignmentStyle = textAlignmentStyle(attributes);
@@ -60,24 +50,38 @@ const listTag = Boolean(attributes.ordered) ? "ol" : "ul";
60
50
  ---
61
51
 
62
52
  {heading ? (
63
- <S as={headingTag} {...semantic} {...htmlAttributes} style={alignmentStyle} set:html={html} />
53
+ <SemanticElement
54
+ tag={headingTag}
55
+ attributes={{ ...semantic, ...htmlAttributes, style: alignmentStyle }}
56
+ html={html}
57
+ />
64
58
  ) : name === "core/list" ? (
65
- <S as={listTag} {...semantic} {...htmlAttributes} style={alignmentStyle}>
66
- {hasChildren ? <slot /> : <Fragment set:html={html} />}
67
- </S>
59
+ <SemanticElement
60
+ tag={listTag}
61
+ attributes={{ ...semantic, ...htmlAttributes, style: alignmentStyle }}
62
+ html={hasChildren ? undefined : html}
63
+ >
64
+ {hasChildren ? <slot /> : null}
65
+ </SemanticElement>
68
66
  ) : name === "core/list-item" ? (
69
- <S as="li" {...semantic} {...htmlAttributes} style={alignmentStyle}>
67
+ <S.li {...semantic} {...htmlAttributes} style={alignmentStyle}>
70
68
  <span set:html={html}></span>
71
69
  {hasChildren ? <slot /> : null}
72
- </S>
70
+ </S.li>
73
71
  ) : name === "quote" || name === "core/quote" ? (
74
- <S as="blockquote" {...semantic} {...htmlAttributes} style={alignmentStyle}>
72
+ <S.blockquote {...semantic} {...htmlAttributes} style={alignmentStyle}>
75
73
  {hasChildren ? <slot /> : <div set:html={html}></div>}
76
74
  {attributes.citation ? <cite>{String(attributes.citation)}</cite> : null}
77
- </S>
75
+ </S.blockquote>
76
+ ) : name === "core/paragraph" ? (
77
+ <S.p
78
+ {...semantic}
79
+ {...htmlAttributes}
80
+ style={alignmentStyle}
81
+ set:html={html}
82
+ />
78
83
  ) : (
79
- <S
80
- as={name === "core/paragraph" ? "p" : "div"}
84
+ <S.div
81
85
  {...semantic}
82
86
  {...htmlAttributes}
83
87
  style={alignmentStyle}
@@ -0,0 +1,23 @@
1
+ ---
2
+ import S from "@styleflow.app/astro/S.astro";
3
+ import type { FlowpressBlockRendererProps } from "../../block-renderers.js";
4
+
5
+ const { block, styleflowProps, htmlProps, composition } = Astro.props as FlowpressBlockRendererProps;
6
+ const label = typeof block.attributes.label === "string" && block.attributes.label.trim()
7
+ ? block.attributes.label.trim()
8
+ : "Change color theme";
9
+ const showThemeName = block.attributes.showThemeName !== false;
10
+ const themeName = "Theme";
11
+ ---
12
+
13
+ <S.button
14
+ {...htmlProps}
15
+ {...styleflowProps}
16
+ type="button"
17
+ aria-label={label}
18
+ data-styleflow-theme-toggle
19
+ >
20
+ <span data-styleflow-theme-label aria-hidden="true">
21
+ {showThemeName ? String(themeName) : "Theme"}
22
+ </span>
23
+ </S.button>
@@ -13,6 +13,13 @@ export declare function blockHtmlAttributes(attributes: Record<string, unknown>,
13
13
  };
14
14
  export declare const TEXT_HTML_TAGS: readonly ["span", "p", "h1", "h2", "h3", "h4", "h5", "h6", "strong", "em", "small", "mark"];
15
15
  export type TextHtmlTag = (typeof TEXT_HTML_TAGS)[number];
16
+ /**
17
+ * Derive a variant only when Gutenberg omitted it. The selected typography
18
+ * type can differ from the block's native type, so a paragraph styled as a
19
+ * heading must not inherit the paragraph-only `md` variant.
20
+ */
21
+ export declare function compatibleTypographyVariant(type: string, preferred: string, contract?: StyleflowContract): string;
22
+ export declare function textBlockSemanticDefaults(blockName: string, attributes: Record<string, unknown>, contract?: StyleflowContract): Record<string, unknown>;
16
23
  export declare function textHtmlTag(value: unknown): TextHtmlTag;
17
24
  export declare function semanticProps(attributes: Record<string, unknown>, contract?: StyleflowContract, defaults?: Record<string, unknown>): Record<string, unknown>;
18
25
  /** Resolve only Gutenberg's supported text-alignment values to inline CSS. */
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/astro/blocks/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,eAAO,MAAM,sBAAsB;;;;CAIlC,CAAC;AAEF,eAAO,MAAM,4BAA4B,YAAY,CAAC;AAEtD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAmBzD;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,SAAS,SAAK,GACb;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAgBjC;AAsBD,eAAO,MAAM,cAAc,6FAajB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAKvD;AAED,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAA0B,GACzD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoBzB;AAWD,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,GAAG,SAAS,CAYpB;AAED,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACrC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,cAAc,EACrB,GAAG,EAAE,MAAM,GACV,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,SAAS,GAAG,MAAM,CAErE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoB5D;AAED,sFAAsF;AACtF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,SAAS,GAAG,MAAM,CAMrE;AAED,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,MAAM,EAAE,SAAS,GAAG,MAAM,EAC1B,QAAQ,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EAAE,MAAM,CAAC,CAe5D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnD"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/astro/blocks/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,eAAO,MAAM,sBAAsB;;;;CAIlC,CAAC;AAEF,eAAO,MAAM,4BAA4B,YAAY,CAAC;AAEtD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAmBzD;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,SAAS,SAAK,GACb;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAgBjC;AAED,eAAO,MAAM,cAAc,6FAajB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAQ1D;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,iBAAiB,GAC3B,MAAM,CAcR;AAED,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,QAAQ,CAAC,EAAE,iBAAiB,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAmBzB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAKvD;AAED,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAA0B,GACzD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB;AAWD,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,GAAG,SAAS,CAYpB;AAED,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACrC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,cAAc,EACrB,GAAG,EAAE,MAAM,GACV,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,SAAS,GAAG,MAAM,CAErE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoB5D;AAED,sFAAsF;AACtF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,SAAS,GAAG,MAAM,CAErE;AAED,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,MAAM,EAAE,SAAS,GAAG,MAAM,EAC1B,QAAQ,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EAAE,MAAM,CAAC,CAe5D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnD"}