@lystech/sections 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -11,6 +11,8 @@
11
11
  */
12
12
  export { SectionsProvider, useSectionsContext } from './SectionsProvider';
13
13
  export { SignatureLystech } from './SignatureLystech';
14
+ export { adaptateurI18next, appliquerAuxTextes } from './sourceTexte';
15
+ export type { Dictionnaire, SourceTexte } from './sourceTexte';
14
16
  export { useSection, useSectionList } from './useSection';
15
17
  export type { BlocDeclare, ChampDeclare, SectionPubliee, TypeDeChamp, } from './types';
16
18
  export type { AncrageEdition, ResultatSection } from './useSection';
package/dist/index.js CHANGED
@@ -1,153 +1,178 @@
1
- import { jsx as h, jsxs as j, Fragment as F } from "react/jsx-runtime";
2
- import { useState as m, useRef as _, useEffect as A, useCallback as I, useMemo as C, useContext as M, createContext as T } from "react";
3
- const d = "lystech-edit", U = T(null), $ = "https://api.lystech.ca/api";
4
- function J() {
1
+ import { jsx as S, jsxs as L, Fragment as F } from "react/jsx-runtime";
2
+ import { useState as h, useRef as P, useEffect as x, useCallback as O, useMemo as _, useContext as M, createContext as N } from "react";
3
+ import { appliquerAuxTextes as T } from "./morceaux/sourceTexte-BMPMpNg9.js";
4
+ import { adaptateurI18next as rt } from "./morceaux/sourceTexte-BMPMpNg9.js";
5
+ const d = "lystech-edit", k = N(null), q = "https://api.lystech.ca/api";
6
+ function H() {
5
7
  if (typeof window > "u") return null;
6
- const e = (t) => {
8
+ const t = (n) => {
7
9
  try {
8
- window.sessionStorage.setItem(d, t);
10
+ window.sessionStorage.setItem(d, n);
9
11
  } catch {
10
12
  }
11
- return t;
13
+ return n;
12
14
  };
13
15
  try {
14
- const t = window.location.hash.replace(/^#/, "");
15
- if (t.includes(d + "=")) {
16
- const o = new URLSearchParams(t), c = o.get(d);
17
- if (c) {
18
- o.delete(d);
19
- const a = o.toString();
16
+ const n = window.location.hash.replace(/^#/, "");
17
+ if (n.includes(d + "=")) {
18
+ const c = new URLSearchParams(n), o = c.get(d);
19
+ if (o) {
20
+ c.delete(d);
21
+ const i = c.toString();
20
22
  return window.history.replaceState(
21
23
  {},
22
24
  "",
23
- window.location.pathname + window.location.search + (a ? "#" + a : "")
24
- ), e(c);
25
+ window.location.pathname + window.location.search + (i ? "#" + i : "")
26
+ ), t(o);
25
27
  }
26
28
  }
27
- const n = new URL(window.location.href), r = n.searchParams.get(d);
28
- return r ? (n.searchParams.delete(d), window.history.replaceState({}, "", n.toString()), e(r)) : window.sessionStorage.getItem(d);
29
+ const e = new URL(window.location.href), r = e.searchParams.get(d);
30
+ return r ? (e.searchParams.delete(d), window.history.replaceState({}, "", e.toString()), t(r)) : window.sessionStorage.getItem(d);
29
31
  } catch {
30
32
  return null;
31
33
  }
32
34
  }
33
- function q({
34
- site: e,
35
- page: t,
36
- langue: n = "fr",
37
- apiBaseUrl: r = $,
38
- sectionsInitiales: o,
39
- children: c
35
+ function X({
36
+ site: t,
37
+ page: n,
38
+ langue: e = "fr",
39
+ apiBaseUrl: r = q,
40
+ sectionsInitiales: c,
41
+ sourceTexte: o,
42
+ pagesPartagees: i,
43
+ children: m
40
44
  }) {
41
- const [a, p] = m(
42
- o ?? []
43
- ), [u, y] = m(
44
- o?.length ? "pret" : "chargement"
45
- ), [g, b] = m(0), [P, z] = m({}), [v, O] = m(!1), D = _(null);
46
- A(() => {
47
- if (!e || !t) return;
45
+ const [u, g] = h(
46
+ c ?? []
47
+ ), [w, p] = h(
48
+ c?.length ? "pret" : "chargement"
49
+ ), [y, A] = h(0), [R, J] = h({}), [U, $] = h(!1), D = P(null);
50
+ x(() => {
51
+ if (!t || !n) return;
48
52
  D.current?.abort();
49
- const i = new AbortController();
50
- D.current = i, y("chargement");
51
- const f = r + "/site-sections/public/" + encodeURIComponent(e) + "/" + encodeURIComponent(t);
52
- return fetch(f, { signal: i.signal }).then(
53
+ const a = new AbortController();
54
+ D.current = a, p("chargement");
55
+ const f = r + "/site-sections/public/" + encodeURIComponent(t) + "/" + encodeURIComponent([n, ...i ?? []].join(","));
56
+ return fetch(f, { signal: a.signal }).then(
53
57
  (s) => s.ok ? s.json() : Promise.reject(new Error(String(s.status)))
54
58
  ).then((s) => {
55
- i.signal.aborted || (p(Array.isArray(s) ? s : []), y("pret"));
59
+ a.signal.aborted || (g(Array.isArray(s) ? s : []), p("pret"));
56
60
  }).catch((s) => {
57
- i.signal.aborted || s?.name === "AbortError" || y("erreur");
58
- }), () => i.abort();
59
- }, [e, t, r, g]);
60
- const E = I(() => b((i) => i + 1), []), x = I(
61
- (i, f) => z((s) => ({ ...s, [i]: f })),
61
+ a.signal.aborted || s?.name === "AbortError" || p("erreur");
62
+ }), () => a.abort();
63
+ }, [t, n, r, y, (i ?? []).join(",")]);
64
+ const E = O(() => A((a) => a + 1), []);
65
+ x(() => {
66
+ !o || !u.length || T(u, o);
67
+ }, [u, o]);
68
+ const j = O(
69
+ (a, f) => J((s) => ({ ...s, [a]: f })),
62
70
  []
63
- ), l = _({
64
- site: e,
65
- page: t,
66
- langue: n,
71
+ ), l = P({
72
+ site: t,
73
+ page: n,
74
+ langue: e,
67
75
  poserApercu: () => {
68
76
  },
69
77
  recharger: () => {
70
78
  }
71
79
  });
72
- l.current.site = e, l.current.page = t, l.current.langue = n, l.current.poserApercu = x, l.current.recharger = E, A(() => {
73
- l.current.surChangementDePage?.(t);
74
- }, [t]), A(() => {
75
- const i = J();
76
- if (!i) return;
80
+ l.current.site = t, l.current.page = n, l.current.langue = e, l.current.poserApercu = j, l.current.sourceTexte = o, l.current.recharger = E, x(() => {
81
+ l.current.surChangementDePage?.(n);
82
+ }, [n]), x(() => {
83
+ const a = H();
84
+ if (!a) return;
77
85
  let f = !0, s;
78
- return import("@lystech/sections/editeur").then((w) => {
79
- f && (O(!0), s = w.monterEditeur({
80
- jeton: i,
81
- site: e,
86
+ return import("@lystech/sections/editeur").then((b) => {
87
+ f && ($(!0), s = b.monterEditeur({
88
+ jeton: a,
89
+ site: t,
82
90
  apiBaseUrl: r,
83
91
  pont: l.current
84
92
  }));
85
- }).catch((w) => {
86
- console.error("[lystech] éditeur indisponible:", w?.message ?? w);
93
+ }).catch((b) => {
94
+ console.error("[lystech] éditeur indisponible:", b?.message ?? b);
87
95
  }), () => {
88
96
  f = !1, s?.();
89
97
  };
90
- }, [e, r]);
91
- const k = C(
98
+ }, [t, r]);
99
+ const z = _(
92
100
  () => ({
93
- site: e,
94
- page: t,
95
- langue: n,
101
+ site: t,
102
+ page: n,
103
+ langue: e,
96
104
  apiBaseUrl: r,
97
- sections: a,
98
- etat: u,
105
+ sections: u,
106
+ etat: w,
99
107
  recharger: E,
100
- apercu: P,
101
- poserApercu: x,
102
- modeEdition: v
108
+ apercu: R,
109
+ poserApercu: j,
110
+ modeEdition: U
103
111
  }),
104
112
  [
105
- e,
106
113
  t,
107
114
  n,
115
+ e,
108
116
  r,
109
- a,
110
117
  u,
118
+ w,
111
119
  E,
112
- P,
113
- x,
114
- v
120
+ R,
121
+ j,
122
+ U
115
123
  ]
116
124
  );
117
- return /* @__PURE__ */ h(U.Provider, { value: k, children: c });
125
+ return /* @__PURE__ */ S(k.Provider, { value: z, children: m });
118
126
  }
119
- function R() {
120
- return M(U);
127
+ function I() {
128
+ return M(k);
121
129
  }
122
- const W = "https://api.lystech.ca/api";
123
- function G() {
124
- if (typeof window > "u") return null;
125
- try {
126
- const e = new URL(window.location.href), t = e.searchParams.get("lystech-acces");
127
- return t ? (e.searchParams.delete("lystech-acces"), window.history.replaceState({}, "", e.toString()), t) : null;
128
- } catch {
129
- return null;
130
- }
131
- }
132
- const L = {
133
- "sans-acces": "Vous n'avez pas encore accès à la modification de ce site.",
134
- "demande-envoyee": "Demande envoyée. La personne responsable du site vous répondra.",
135
- "trop-de-demandes": "Trop de demandes aujourd'hui. Réessayez demain."
136
- };
137
- function K({
138
- site: e,
139
- apiBaseUrl: t,
140
- className: n,
130
+ const W = "https://api.lystech.ca/api", v = "lystech-edit";
131
+ function Y({
132
+ site: t,
133
+ apiBaseUrl: n,
134
+ className: e,
141
135
  mention: r = "Réalisé avec Lystech",
142
- connexion: o = "Connexion"
136
+ connexion: c = "Connexion"
143
137
  }) {
144
- const c = R(), a = e ?? c?.site ?? "", p = t ?? c?.apiBaseUrl ?? W, [u, y] = m(null);
145
- if (A(() => y(G()), []), !a) return null;
146
- const g = (b) => p + "/site-sections/edit-entry?site=" + encodeURIComponent(a) + (b ? "&demander=1" : "");
147
- return /* @__PURE__ */ j(
138
+ const o = I(), i = t ?? o?.site ?? "", m = n ?? o?.apiBaseUrl ?? W, [u, g] = h(!1);
139
+ if (!i) return null;
140
+ const w = async () => {
141
+ if (!u) {
142
+ g(!0);
143
+ try {
144
+ (await import("@lystech/sections/editeur")).monterConnexion({
145
+ site: i,
146
+ apiBaseUrl: m,
147
+ surJeton: (A) => {
148
+ try {
149
+ window.sessionStorage.setItem(v, A);
150
+ } catch {
151
+ window.location.hash = v + "=" + encodeURIComponent(A);
152
+ }
153
+ window.location.reload();
154
+ }
155
+ });
156
+ } catch (y) {
157
+ console.error("[lystech] connexion indisponible:", y?.message ?? y);
158
+ } finally {
159
+ g(!1);
160
+ }
161
+ }
162
+ }, p = {
163
+ color: "inherit",
164
+ font: "inherit",
165
+ background: "none",
166
+ border: 0,
167
+ padding: 0,
168
+ cursor: "pointer",
169
+ textDecoration: "underline",
170
+ textUnderlineOffset: "0.2em"
171
+ };
172
+ return /* @__PURE__ */ L(
148
173
  "div",
149
174
  {
150
- className: n,
175
+ className: e,
151
176
  style: {
152
177
  display: "flex",
153
178
  flexWrap: "wrap",
@@ -158,7 +183,7 @@ function K({
158
183
  lineHeight: 1.5
159
184
  },
160
185
  children: [
161
- /* @__PURE__ */ h(
186
+ /* @__PURE__ */ S(
162
187
  "a",
163
188
  {
164
189
  href: "https://lystech.ca",
@@ -168,95 +193,92 @@ function K({
168
193
  children: r
169
194
  }
170
195
  ),
171
- !c?.modeEdition && !u && /* @__PURE__ */ j(F, { children: [
172
- /* @__PURE__ */ h("span", { "aria-hidden": "true", children: "·" }),
173
- /* @__PURE__ */ h("a", { href: g(!1), style: { color: "inherit" }, children: o })
174
- ] }),
175
- u && /* @__PURE__ */ j("span", { style: { display: "inline-flex", gap: "0.5em", flexWrap: "wrap" }, children: [
176
- /* @__PURE__ */ h("span", { "aria-hidden": "true", children: "·" }),
177
- /* @__PURE__ */ h("span", { children: L[u] ?? L["sans-acces"] }),
178
- u === "sans-acces" && /* @__PURE__ */ h("a", { href: g(!0), style: { color: "inherit" }, children: "Demander l'accès" })
196
+ !o?.modeEdition && /* @__PURE__ */ L(F, { children: [
197
+ /* @__PURE__ */ S("span", { "aria-hidden": "true", children: "·" }),
198
+ /* @__PURE__ */ S("button", { type: "button", style: p, onClick: w, children: u ? "…" : c })
179
199
  ] })
180
200
  ]
181
201
  }
182
202
  );
183
203
  }
184
- function H(e) {
185
- return !!e && typeof e == "object" && !Array.isArray(e) && Object.keys(e).every((t) => /^[a-z]{2}(-[A-Za-z]{2})?$/.test(t));
204
+ function Z(t) {
205
+ return !!t && typeof t == "object" && !Array.isArray(t) && Object.keys(t).every((n) => /^[a-z]{2}(-[A-Za-z]{2})?$/.test(n));
186
206
  }
187
- function S(e, t) {
188
- if (Array.isArray(e)) return e.map((n) => S(n, t));
189
- if (H(e)) {
190
- const n = e, r = t.slice(0, 2);
191
- return n[t] ?? n[r] ?? Object.values(n).find((c) => c != null) ?? "";
207
+ function C(t, n) {
208
+ if (Array.isArray(t)) return t.map((e) => C(e, n));
209
+ if (Z(t)) {
210
+ const e = t, r = n.slice(0, 2);
211
+ return e[n] ?? e[r] ?? Object.values(e).find((o) => o != null) ?? "";
192
212
  }
193
- if (e && typeof e == "object") {
194
- const n = {};
195
- for (const [r, o] of Object.entries(e))
196
- n[r] = S(o, t);
197
- return n;
213
+ if (t && typeof t == "object") {
214
+ const e = {};
215
+ for (const [r, c] of Object.entries(t))
216
+ e[r] = C(c, n);
217
+ return e;
198
218
  }
199
- return e;
219
+ return t;
200
220
  }
201
- function N(e, t) {
202
- if (!t || typeof t != "object" || Array.isArray(t))
203
- return e;
204
- const n = { ...e };
205
- for (const [r, o] of Object.entries(t))
206
- o != null && (n[r] = o);
207
- return n;
221
+ function G(t, n) {
222
+ if (!n || typeof n != "object" || Array.isArray(n))
223
+ return t;
224
+ const e = { ...t };
225
+ for (const [r, c] of Object.entries(n))
226
+ c != null && (e[r] = c);
227
+ return e;
208
228
  }
209
- function Q(e, t) {
210
- const n = R(), r = n?.apercu?.[e];
211
- return C(() => {
212
- const o = n?.sections.find(
213
- (p) => p.blockType === e
214
- ), c = r ?? o?.data ?? null, a = c ? S(c, n?.langue ?? "fr") : null;
229
+ function B(t, n) {
230
+ const e = I(), r = e?.apercu?.[t];
231
+ return _(() => {
232
+ const c = e?.sections.find(
233
+ (m) => m.blockType === t
234
+ ), o = r ?? c?.data ?? null, i = o ? C(o, e?.langue ?? "fr") : null;
215
235
  return {
216
- contenu: N(t.defaut, a),
217
- publie: !!o?.data,
218
- UID: o?.UID ?? null,
219
- chargement: n?.etat === "chargement",
220
- ancrage: { "data-lystech-section": e }
236
+ contenu: G(n.defaut, i),
237
+ publie: !!c?.data,
238
+ UID: c?.UID ?? null,
239
+ chargement: e?.etat === "chargement",
240
+ ancrage: { "data-lystech-section": t }
221
241
  };
222
242
  }, [
223
- n?.sections,
224
- n?.langue,
225
- n?.etat,
243
+ e?.sections,
244
+ e?.langue,
245
+ e?.etat,
226
246
  r,
227
- e,
228
- t.defaut
247
+ t,
248
+ n.defaut
229
249
  ]);
230
250
  }
231
- function X(e, t) {
232
- const n = R();
233
- return C(() => {
234
- const r = { "data-lystech-section": e }, o = (n?.sections ?? []).filter(
235
- (c) => c.blockType === e
251
+ function tt(t, n) {
252
+ const e = I();
253
+ return _(() => {
254
+ const r = { "data-lystech-section": t }, c = (e?.sections ?? []).filter(
255
+ (o) => o.blockType === t
236
256
  );
237
- return o.length === 0 ? {
238
- items: (t?.defaut ?? []).map((c, a) => ({
239
- ...c,
240
- __uid: `defaut-${a}`
257
+ return c.length === 0 ? {
258
+ items: (n?.defaut ?? []).map((o, i) => ({
259
+ ...o,
260
+ __uid: `defaut-${i}`
241
261
  })),
242
262
  publie: !1,
243
- chargement: n?.etat === "chargement",
263
+ chargement: e?.etat === "chargement",
244
264
  ancrage: r
245
265
  } : {
246
- items: o.map((c) => ({
247
- ...S(c.data ?? {}, n?.langue ?? "fr"),
248
- __uid: c.UID
266
+ items: c.map((o) => ({
267
+ ...C(o.data ?? {}, e?.langue ?? "fr"),
268
+ __uid: o.UID
249
269
  })),
250
270
  publie: !0,
251
- chargement: n?.etat === "chargement",
271
+ chargement: e?.etat === "chargement",
252
272
  ancrage: r
253
273
  };
254
- }, [n?.sections, n?.langue, n?.etat, e, t?.defaut]);
274
+ }, [e?.sections, e?.langue, e?.etat, t, n?.defaut]);
255
275
  }
256
276
  export {
257
- q as SectionsProvider,
258
- K as SignatureLystech,
259
- Q as useSection,
260
- X as useSectionList,
261
- R as useSectionsContext
277
+ X as SectionsProvider,
278
+ Y as SignatureLystech,
279
+ rt as adaptateurI18next,
280
+ T as appliquerAuxTextes,
281
+ B as useSection,
282
+ tt as useSectionList,
283
+ I as useSectionsContext
262
284
  };
@@ -0,0 +1,71 @@
1
+ function y(t, o) {
2
+ const e = t.split("."), r = {};
3
+ let n = r;
4
+ for (let s = 0; s < e.length - 1; s++) {
5
+ const c = e[s];
6
+ n[c] = {}, n = n[c];
7
+ }
8
+ return n[e[e.length - 1]] = o, r;
9
+ }
10
+ function l(t, o = "", e = {}) {
11
+ if (!t || typeof t != "object") return e;
12
+ for (const [r, n] of Object.entries(t)) {
13
+ const s = o ? o + "." + r : r;
14
+ typeof n == "string" ? e[s] = n : n && typeof n == "object" && !Array.isArray(n) && l(n, s, e);
15
+ }
16
+ return e;
17
+ }
18
+ function h(t) {
19
+ return {
20
+ langues: () => {
21
+ const o = t?.options?.supportedLngs, e = Array.isArray(o) ? o.filter((r) => r !== "cimode") : [];
22
+ return e.length ? e : [t?.language ?? "fr"];
23
+ },
24
+ langueCourante: () => String(t?.language ?? "fr").slice(0, 2),
25
+ dictionnaire: (o) => {
26
+ const e = Array.isArray(t?.options?.ns) ? t.options.ns : [t?.options?.defaultNS ?? "translation"], r = {};
27
+ for (const n of e) {
28
+ const s = t?.getResourceBundle?.(o, n);
29
+ s && (r[n] = l(s));
30
+ }
31
+ return r;
32
+ },
33
+ poser: (o, e, r, n) => {
34
+ t?.addResourceBundle?.(
35
+ o,
36
+ e,
37
+ y(r, n),
38
+ !0,
39
+ !0
40
+ );
41
+ }
42
+ };
43
+ }
44
+ const d = /^i18n:([^:]+):(.*)$/;
45
+ function A(t, o) {
46
+ if (typeof t == "string") return t;
47
+ if (!t || typeof t != "object" || Array.isArray(t)) return null;
48
+ const e = t, r = o.slice(0, 2), n = e[o] ?? e[r];
49
+ return typeof n == "string" ? n : null;
50
+ }
51
+ function j(t, o) {
52
+ const e = o.langues();
53
+ let r = 0;
54
+ for (const n of t ?? []) {
55
+ const s = d.exec(n.blockType ?? "");
56
+ if (!s || !n.data) continue;
57
+ const c = s[1], u = s[2];
58
+ for (const [a, p] of Object.entries(n.data)) {
59
+ const g = u ? u + "." + a : a;
60
+ for (const f of e) {
61
+ const i = A(p, f);
62
+ i === null || i === "" || (o.poser(f, c, g, i), r++);
63
+ }
64
+ }
65
+ }
66
+ return r;
67
+ }
68
+ export {
69
+ h as adaptateurI18next,
70
+ j as appliquerAuxTextes
71
+ };
@@ -0,0 +1,34 @@
1
+ /** Un dictionnaire aplati : espace de noms → chemin pointé → texte. */
2
+ export type Dictionnaire = Record<string, Record<string, string>>;
3
+ export type SourceTexte = {
4
+ /** Les langues que le site sait rendre. */
5
+ langues: () => string[];
6
+ /** Celle qu'il affiche en ce moment. */
7
+ langueCourante: () => string;
8
+ /** Tout ce que le site sait dire, dans une langue. */
9
+ dictionnaire: (langue: string) => Dictionnaire;
10
+ /** Remplacer un texte. Le site doit se redessiner ensuite. */
11
+ poser: (langue: string, espace: string, chemin: string, valeur: string) => void;
12
+ };
13
+ /**
14
+ * Branche une instance i18next.
15
+ *
16
+ * `bindI18nStore: "added"` doit être actif dans la configuration du site,
17
+ * sinon React ne se redessine pas quand on remplace un texte — la
18
+ * modification serait enregistrée mais invisible, ce qui est la pire des
19
+ * deux issues : la personne réécrit, republie, et finit par croire que rien
20
+ * ne fonctionne.
21
+ */
22
+ export declare function adaptateurI18next(i18n: any): SourceTexte;
23
+ /**
24
+ * Applique des sections publiées à la source de textes du site.
25
+ *
26
+ * Utilisée à deux moments, et c'est ce qui rend le référencement juste :
27
+ * pendant le PRÉ-RENDU, pour que le HTML livré porte le bon texte et les
28
+ * bonnes balises ; puis dans le NAVIGATEUR, pour rattraper ce qui aurait été
29
+ * publié depuis la dernière reconstruction.
30
+ */
31
+ export declare function appliquerAuxTextes(sections: Array<{
32
+ blockType: string;
33
+ data: Record<string, unknown> | null;
34
+ }>, source: SourceTexte): number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lystech/sections",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Contenu de site editable par le client — lecture legere, edition chargee a la demande.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,7 +17,9 @@
17
17
  }
18
18
  },
19
19
  "sideEffects": false,
20
- "files": ["dist"],
20
+ "files": [
21
+ "dist"
22
+ ],
21
23
  "scripts": {
22
24
  "build": "tsc -b && vite build",
23
25
  "dev": "vite build --watch"
@@ -35,5 +37,7 @@
35
37
  "vite": "^7.0.0",
36
38
  "vite-plugin-dts": "^4.5.4"
37
39
  },
38
- "publishConfig": { "access": "public" }
40
+ "publishConfig": {
41
+ "access": "public"
42
+ }
39
43
  }