origam 2.35.0 → 2.36.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/src/assets/locales/en.json +5 -0
  3. package/dist/src/assets/locales/fr.json +5 -0
  4. package/dist/src/components/Code/OrigamCode.vue +28 -9
  5. package/dist/src/components/CodeGroup/OrigamCodeGroup.vue +215 -0
  6. package/dist/src/components/CodeGroup/index.cjs +13 -0
  7. package/dist/src/components/CodeGroup/index.d.ts +1 -0
  8. package/dist/src/components/CodeGroup/index.js +1 -0
  9. package/dist/src/components/index.cjs +11 -0
  10. package/dist/src/components/index.d.ts +1 -0
  11. package/dist/src/components/index.js +1 -0
  12. package/dist/src/composables/Code/code.composable.cjs +3 -2
  13. package/dist/src/composables/Code/code.composable.js +3 -2
  14. package/dist/src/consts/CodeGroup/code-group.const.cjs +17 -0
  15. package/dist/src/consts/CodeGroup/code-group.const.d.ts +16 -0
  16. package/dist/src/consts/CodeGroup/code-group.const.js +11 -0
  17. package/dist/src/consts/index.cjs +11 -0
  18. package/dist/src/consts/index.d.ts +1 -0
  19. package/dist/src/consts/index.js +1 -0
  20. package/dist/src/interfaces/Code/code.interface.d.ts +20 -0
  21. package/dist/src/interfaces/CodeGroup/code-group.interface.cjs +1 -0
  22. package/dist/src/interfaces/CodeGroup/code-group.interface.d.ts +102 -0
  23. package/dist/src/interfaces/CodeGroup/code-group.interface.js +0 -0
  24. package/dist/src/interfaces/index.cjs +11 -0
  25. package/dist/src/interfaces/index.d.ts +1 -0
  26. package/dist/src/interfaces/index.js +1 -0
  27. package/dist/src/types/CodeGroup/code-group.type.cjs +1 -0
  28. package/dist/src/types/CodeGroup/code-group.type.d.ts +2 -0
  29. package/dist/src/types/CodeGroup/code-group.type.js +0 -0
  30. package/dist/src/types/index.cjs +11 -0
  31. package/dist/src/types/index.d.ts +1 -0
  32. package/dist/src/types/index.js +1 -0
  33. package/dist/src/utils/CodeGroup/code-group.util.cjs +99 -0
  34. package/dist/src/utils/CodeGroup/code-group.util.d.ts +51 -0
  35. package/dist/src/utils/CodeGroup/code-group.util.js +66 -0
  36. package/dist/src/utils/index.cjs +11 -0
  37. package/dist/src/utils/index.d.ts +1 -0
  38. package/dist/src/utils/index.js +1 -0
  39. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -18,6 +18,26 @@ This project follows [Semantic Versioning](https://semver.org).
18
18
 
19
19
  ## [Unreleased]
20
20
 
21
+ ## [2.36.0] - 2026-10-19
22
+
23
+ ### Added — `OrigamCodeGroup` : groupe de code à onglets (npm / pnpm / yarn) en une seule surface (#1179)
24
+
25
+ - Nouveau composant `OrigamCodeGroup`, qui réunit `OrigamTabs` et `OrigamCode` : une seule surface (bordure, rayon et élévation portés par le groupe, blocs internes aplatis et sans en-tête), un seul bouton copier qui copie le code de l'onglet actif (slot `copy` pour le remplacer), `v-model` sur l'onglet actif.
26
+ - Deux formes : prop `items` (`{ label, code, lang?, filename?, value? }`) ou slot avec des `<origam-code>` enfants ; le libellé de l'onglet vient de `label`, sinon de `filename`, sinon de la position.
27
+ - Chaque zone défilante porte un nom accessible distinct (`{groupe}, {onglet}, code block {n} of {total}, scrollable region`, clés `origam.code_group.*` en `en` et `fr`) : plus de `landmark-unique` axe entre panneaux. Donner un `label` à chaque groupe quand plusieurs se trouvent sur une même page.
28
+ - `OrigamCode` gagne `hideHeader`, `flat` et `scrollerAriaLabel`, utilisables seuls.
29
+ - Aucun nouveau token : le groupe lit `--origam-code---*`, donc un thème qui restyle `OrigamCode` restyle aussi le groupe.
30
+
31
+ ## [2.35.1] - 2026-10-19
32
+
33
+ ### Fixed — `OrigamCode` : un 2e bloc monté pendant un import de `shiki` en échec restait vide (#1189)
34
+
35
+ Quand `shiki` n'est pas résolvable, deux `<origam-code>` montés dans le même tick : le premier s'affichait en texte brut, le second restait **vide** (zone défilante de hauteur 0) avec un rejet de promesse non capturé. `loadHighlighter()` ne renvoyait la promesse munie de son repli qu'au premier appelant ; un appelant concurrent recevait la promesse brute, qui rejetait, et `rebuild()` n'avait qu'un `try/finally`.
36
+
37
+ - `loadHighlighter()` renvoie désormais la même promesse, déjà munie de son repli (`null` → code brut), à tous les appelants.
38
+ - `rebuild()` capture en plus un éventuel rejet et peint le code en clair : aucun bloc ne reste vide.
39
+ - Prouvé par `packages/tests/TU/components/Code/OrigamCode-concurrent-load-failure.spec.ts` (rouge sur le parent, vert après).
40
+
21
41
  ## [2.35.0] - 2026-10-19
22
42
 
23
43
  ### Added — `OrigamCode` : `lang` ouvert, `createOrigam({ code: { langs } })` (#1180)
@@ -175,6 +175,11 @@
175
175
  "scroller_aria_label_filename": "{filename}, code block, scrollable region",
176
176
  "scroller_aria_label_lang": "{lang} code block, scrollable region"
177
177
  },
178
+ "code_group": {
179
+ "tabs_aria_label": "Code variants",
180
+ "scroller_aria_label": "{label}, code block {position} of {total}, scrollable region",
181
+ "scroller_aria_label_group": "{group}, {label}, code block {position} of {total}, scrollable region"
182
+ },
178
183
  "qr_code": {
179
184
  "aria_label": "QR code for {value}"
180
185
  },
@@ -175,6 +175,11 @@
175
175
  "scroller_aria_label_filename": "{filename}, bloc de code, zone défilante",
176
176
  "scroller_aria_label_lang": "Bloc de code {lang}, zone défilante"
177
177
  },
178
+ "code_group": {
179
+ "tabs_aria_label": "Variantes du code",
180
+ "scroller_aria_label": "{label}, bloc de code {position} sur {total}, zone défilante",
181
+ "scroller_aria_label_group": "{group}, {label}, bloc de code {position} sur {total}, zone défilante"
182
+ },
178
183
  "qr_code": {
179
184
  "aria_label": "QR code pour {value}"
180
185
  },
@@ -124,6 +124,9 @@ const props = defineProps({
124
124
  filename: { type: String, required: false, default: void 0 },
125
125
  compact: { type: Boolean, required: false, default: false },
126
126
  prompt: { type: String, required: false, default: void 0 },
127
+ hideHeader: { type: Boolean, required: false, default: false },
128
+ flat: { type: Boolean, required: false, default: false },
129
+ scrollerAriaLabel: { type: String, required: false, default: void 0 },
127
130
  id: { type: String, required: false },
128
131
  class: { type: [String, Array, Object], required: false },
129
132
  style: { type: [String, Array, Object, Boolean, null], required: false, skipCheck: true },
@@ -207,6 +210,7 @@ const { typographyStyles } = useTypography(props, "code");
207
210
  const { highlight } = useCode();
208
211
  const { t } = useLocale();
209
212
  const scrollerLabel = computed(() => {
213
+ if (props.scrollerAriaLabel) return props.scrollerAriaLabel;
210
214
  if (props.filename) return t("origam.code.scroller_aria_label_filename", { filename: props.filename });
211
215
  if (props.lang && props.lang !== CODE_LANG.PLAINTEXT) return t("origam.code.scroller_aria_label_lang", { lang: props.lang });
212
216
  return t("origam.code.scroller_aria_label");
@@ -266,6 +270,13 @@ async function rebuild() {
266
270
  const html = await highlight(formattedCode.value, props.lang);
267
271
  if (token !== _renderToken) return;
268
272
  paintIntoDom(html);
273
+ } catch (err) {
274
+ console.warn("[origam] OrigamCode: highlighting failed \u2014 rendering plain code.", err);
275
+ if (token === _renderToken) {
276
+ const plain = document.createElement("div");
277
+ plain.textContent = formattedCode.value;
278
+ paintIntoDom(plain.innerHTML);
279
+ }
269
280
  } finally {
270
281
  if (token === _renderToken) isHighlighting.value = false;
271
282
  }
@@ -316,7 +327,7 @@ const copyAriaLabel = computed(
316
327
  const copyBtnStyle = {
317
328
  padding: "var(--origam-code__copy---padding-block) var(--origam-code__copy---padding-inline)"
318
329
  };
319
- const showHeader = computed(() => !props.compact && (!!props.filename || !!slots.header || props.copyable));
330
+ const showHeader = computed(() => !props.compact && !props.hideHeader && (!!props.filename || !!slots.header || props.copyable));
320
331
  const compactCopyIcon = computed(() => copied.value ? "mdi-check" : "mdi-content-copy");
321
332
  const headerTag = computed(() => props.tag === "figure" ? "figcaption" : "div");
322
333
  const codeClasses = computed(() => [
@@ -328,21 +339,22 @@ const codeClasses = computed(() => [
328
339
  "origam-code--wrap": props.wrap,
329
340
  "origam-code--has-header": showHeader.value,
330
341
  "origam-code--copyable": props.copyable,
331
- "origam-code--max-height": props.maxHeight != null
342
+ "origam-code--max-height": props.maxHeight != null,
343
+ "origam-code--flat": props.flat
332
344
  },
333
- borderClasses.value,
334
- roundedClasses.value,
335
- elevationClasses.value,
345
+ props.flat ? [] : borderClasses.value,
346
+ props.flat ? [] : roundedClasses.value,
347
+ props.flat ? [] : elevationClasses.value,
336
348
  paddingClasses.value,
337
- marginClasses.value,
349
+ props.flat ? [] : marginClasses.value,
338
350
  colorClasses.value,
339
351
  props.class
340
352
  ]);
341
353
  const codeStyles = computed(() => [
342
- borderStyles.value,
343
- roundedStyles.value,
354
+ props.flat ? {} : borderStyles.value,
355
+ props.flat ? {} : roundedStyles.value,
344
356
  paddingStyles.value,
345
- marginStyles.value,
357
+ props.flat ? {} : marginStyles.value,
346
358
  colorStyles.value,
347
359
  dimensionStyles.value,
348
360
  typographyStyles.value,
@@ -413,6 +425,13 @@ defineExpose({ rebuild, copied, codeRef });
413
425
  white-space: nowrap;
414
426
  }
415
427
 
428
+ .origam-code--flat {
429
+ border: 0;
430
+ border-radius: 0;
431
+ box-shadow: none;
432
+ margin: 0;
433
+ }
434
+
416
435
  .origam-code__prompt {
417
436
  flex: none;
418
437
  color: var(--origam-code__prompt---color);
@@ -0,0 +1,215 @@
1
+ <template>
2
+ <component
3
+ :is="tag"
4
+ :id="id"
5
+ :class="groupClasses"
6
+ :style="groupStyles"
7
+ >
8
+ <origam-tabs
9
+ v-model="model"
10
+ class="origam-code-group__tabs"
11
+ variant="underline"
12
+ :aria-label="tabsLabel"
13
+ data-cy="origam-code-group-tabs"
14
+ >
15
+ <origam-tab
16
+ v-for="item in getItems()"
17
+ :key="item.value"
18
+ :value="item.value"
19
+ :text="item.label"
20
+ />
21
+ </origam-tabs>
22
+
23
+ <slot
24
+ v-if="copyable"
25
+ name="copy"
26
+ :copy="handleCopy"
27
+ :copied="copied"
28
+ >
29
+ <origam-btn
30
+ variant="text"
31
+ class="origam-code__copy origam-code-group__copy"
32
+ :text="copyButtonLabel"
33
+ :aria-label="copyAriaLabel"
34
+ :style="copyBtnStyle"
35
+ aria-live="polite"
36
+ data-cy="origam-code-group-copy"
37
+ @click="handleCopy"
38
+ />
39
+ </slot>
40
+
41
+ <origam-tab-panels
42
+ v-model="model"
43
+ class="origam-code-group__panels"
44
+ :transition="false"
45
+ >
46
+ <origam-tab-panel
47
+ v-for="item in getItems()"
48
+ :key="item.value"
49
+ :value="item.value"
50
+ >
51
+ <component :is="item.vnode"/>
52
+ </origam-tab-panel>
53
+ </origam-tab-panels>
54
+ </component>
55
+ </template>
56
+
57
+ <script lang="ts" setup>
58
+ import { computed, useSlots } from "vue";
59
+ import OrigamBtn from "../Btn/OrigamBtn.vue";
60
+ import OrigamTab from "../Tabs/OrigamTab.vue";
61
+ import OrigamTabPanel from "../Tabs/OrigamTabPanel.vue";
62
+ import OrigamTabPanels from "../Tabs/OrigamTabPanels.vue";
63
+ import OrigamTabs from "../Tabs/OrigamTabs.vue";
64
+ import { useBorder } from "../../composables/Commons/border.composable";
65
+ import { useClipboard } from "../../composables/Clipboard/clipboard.composable";
66
+ import { useDimension } from "../../composables/Commons/dimension.composable";
67
+ import { useElevation } from "../../composables/Commons/elevation.composable";
68
+ import { useLocale } from "../../composables/Commons/locale.composable";
69
+ import { useMargin } from "../../composables/Commons/margin.composable";
70
+ import { useRounded } from "../../composables/Commons/rounded.composable";
71
+ import { useVModel } from "../../composables/Commons/vModel.composable";
72
+ import { CODE_DEFAULTS } from "../../consts/Code/code.const";
73
+ import { findCodeGroupItem, resolveCodeGroupItems } from "../../utils/CodeGroup/code-group.util";
74
+ const props = defineProps({
75
+ items: { type: Array, required: false, default: () => [] },
76
+ modelValue: { type: String, required: false, default: void 0 },
77
+ label: { type: String, required: false, default: void 0 },
78
+ copyable: { type: Boolean, required: false, default: true },
79
+ lineNumbers: { type: Boolean, required: false, default: false },
80
+ wrap: { type: Boolean, required: false, default: false },
81
+ id: { type: String, required: false },
82
+ class: { type: [String, Array, Object], required: false },
83
+ style: { type: [String, Array, Object, Boolean, null], required: false, skipCheck: true },
84
+ tag: { type: String, required: false, default: "figure" },
85
+ border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true },
86
+ borderTop: { type: [Boolean, Number, String], required: false },
87
+ borderLeft: { type: [Boolean, Number, String], required: false },
88
+ borderBottom: { type: [Boolean, Number, String], required: false },
89
+ borderRight: { type: [Boolean, Number, String], required: false },
90
+ borderBlock: { type: [Boolean, Number, String], required: false },
91
+ borderInline: { type: [Boolean, Number, String], required: false },
92
+ borderInlineStart: { type: [Boolean, Number, String], required: false },
93
+ borderInlineEnd: { type: [Boolean, Number, String], required: false },
94
+ borderBlockStart: { type: [Boolean, Number, String], required: false },
95
+ borderBlockEnd: { type: [Boolean, Number, String], required: false },
96
+ borderColor: { type: String, required: false },
97
+ borderStyle: { type: String, required: false },
98
+ borderTopColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
99
+ borderRightColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
100
+ borderBottomColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
101
+ borderLeftColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
102
+ borderInlineStartColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
103
+ borderInlineEndColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
104
+ borderBlockStartColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
105
+ borderBlockEndColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
106
+ rounded: { type: [Boolean, Number, String, null], required: false, skipCheck: true },
107
+ roundedTopRight: { type: [Boolean, Number, String], required: false },
108
+ roundedTopLeft: { type: [Boolean, Number, String], required: false },
109
+ roundedBottomLeft: { type: [Boolean, Number, String], required: false },
110
+ roundedBottomRight: { type: [Boolean, Number, String], required: false },
111
+ roundedStartStart: { type: [Boolean, Number, String], required: false },
112
+ roundedStartEnd: { type: [Boolean, Number, String], required: false },
113
+ roundedEndStart: { type: [Boolean, Number, String], required: false },
114
+ roundedEndEnd: { type: [Boolean, Number, String], required: false },
115
+ elevation: { type: [Number, String], required: false },
116
+ margin: { type: [Boolean, Number, String], required: false },
117
+ marginTop: { type: [Boolean, Number, String], required: false },
118
+ marginLeft: { type: [Boolean, Number, String], required: false },
119
+ marginBottom: { type: [Boolean, Number, String], required: false },
120
+ marginRight: { type: [Boolean, Number, String], required: false },
121
+ marginBlock: { type: [Boolean, Number, String], required: false },
122
+ marginInline: { type: [Boolean, Number, String], required: false },
123
+ marginInlineStart: { type: [Boolean, Number, String], required: false },
124
+ marginInlineEnd: { type: [Boolean, Number, String], required: false },
125
+ marginBlockStart: { type: [Boolean, Number, String], required: false },
126
+ marginBlockEnd: { type: [Boolean, Number, String], required: false },
127
+ height: { type: [Number, String], required: false },
128
+ maxHeight: { type: [Number, String], required: false },
129
+ maxWidth: { type: [Number, String], required: false },
130
+ minHeight: { type: [Number, String], required: false },
131
+ minWidth: { type: [Number, String], required: false },
132
+ width: { type: [Number, String], required: false }
133
+ });
134
+ const emit = defineEmits(["update:modelValue", "copy"]);
135
+ defineSlots();
136
+ const slots = useSlots();
137
+ const { t } = useLocale();
138
+ function getItems() {
139
+ return resolveCodeGroupItems(props.items, slots.default?.(), {
140
+ label: props.label,
141
+ lineNumbers: props.lineNumbers,
142
+ wrap: props.wrap,
143
+ t
144
+ });
145
+ }
146
+ const model = useVModel(props, "modelValue", () => getItems()[0]?.value);
147
+ const tabsLabel = computed(() => props.label ?? t("origam.code_group.tabs_aria_label"));
148
+ const { copy, copied } = useClipboard({ feedbackDuration: CODE_DEFAULTS.copyFeedbackDurationMs });
149
+ async function handleCopy() {
150
+ const code = findCodeGroupItem(getItems(), model.value)?.code ?? "";
151
+ if (await copy(code)) emit("copy", code);
152
+ }
153
+ const copyButtonLabel = computed(() => copied.value ? t("origam.code.copied") : t("origam.code.copy"));
154
+ const copyAriaLabel = computed(() => copied.value ? t("origam.code.copied_aria_label") : t("origam.code.copy_aria_label"));
155
+ const copyBtnStyle = {
156
+ padding: "var(--origam-code__copy---padding-block) var(--origam-code__copy---padding-inline)"
157
+ };
158
+ const { borderClasses, borderStyles } = useBorder(props);
159
+ const { roundedClasses, roundedStyles } = useRounded(props);
160
+ const { elevationClasses } = useElevation(props);
161
+ const { marginClasses, marginStyles } = useMargin(props);
162
+ const { dimensionStyles } = useDimension(props);
163
+ const groupClasses = computed(() => [
164
+ "origam-code-group",
165
+ { "origam-code-group--copyable": props.copyable },
166
+ borderClasses.value,
167
+ roundedClasses.value,
168
+ elevationClasses.value,
169
+ marginClasses.value,
170
+ props.class
171
+ ]);
172
+ const groupStyles = computed(() => [
173
+ borderStyles.value,
174
+ roundedStyles.value,
175
+ marginStyles.value,
176
+ dimensionStyles.value,
177
+ props.style
178
+ ]);
179
+ defineExpose({ copied, model });
180
+ </script>
181
+
182
+ <style lang="scss">
183
+ .origam-code-group {
184
+ display: grid;
185
+ grid-template-columns: minmax(0, 1fr) auto;
186
+ grid-template-areas:
187
+ "tabs copy"
188
+ "panels panels";
189
+ align-items: center;
190
+ margin: 0;
191
+ overflow: hidden;
192
+ background-color: var(--origam-code__header---background-color);
193
+ color: var(--origam-code---color);
194
+ border: var(--origam-code---border-width) solid var(--origam-code---border-color);
195
+ border-radius: var(--origam-code---border-radius);
196
+ }
197
+
198
+ .origam-code-group__tabs {
199
+ grid-area: tabs;
200
+ min-inline-size: 0;
201
+ overflow-x: auto;
202
+ }
203
+
204
+ .origam-code-group__copy {
205
+ grid-area: copy;
206
+ margin-inline-end: var(--origam-code__header---padding-inline);
207
+ }
208
+
209
+ .origam-code-group__panels {
210
+ grid-area: panels;
211
+ min-inline-size: 0;
212
+ background-color: var(--origam-code---background-color);
213
+ border-top: var(--origam-code---border-width) solid var(--origam-code---border-color);
214
+ }
215
+ </style>
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "OrigamCodeGroup", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _OrigamCodeGroup.default;
10
+ }
11
+ });
12
+ var _OrigamCodeGroup = _interopRequireDefault(require("./OrigamCodeGroup.vue"));
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -0,0 +1 @@
1
+ export { default as OrigamCodeGroup } from './OrigamCodeGroup.vue';
@@ -0,0 +1 @@
1
+ export { default as OrigamCodeGroup } from "./OrigamCodeGroup.vue";
@@ -201,6 +201,17 @@ Object.keys(_Code).forEach(function (key) {
201
201
  }
202
202
  });
203
203
  });
204
+ var _CodeGroup = require("./CodeGroup/index.cjs");
205
+ Object.keys(_CodeGroup).forEach(function (key) {
206
+ if (key === "default" || key === "__esModule") return;
207
+ if (key in exports && exports[key] === _CodeGroup[key]) return;
208
+ Object.defineProperty(exports, key, {
209
+ enumerable: true,
210
+ get: function () {
211
+ return _CodeGroup[key];
212
+ }
213
+ });
214
+ });
204
215
  var _ColorPicker = require("./ColorPicker/index.cjs");
205
216
  Object.keys(_ColorPicker).forEach(function (key) {
206
217
  if (key === "default" || key === "__esModule") return;
@@ -16,6 +16,7 @@ export * from './Chip';
16
16
  export * from './ClientOnly';
17
17
  export * from './Clipboard';
18
18
  export * from './Code';
19
+ export * from './CodeGroup';
19
20
  export * from './ColorPicker';
20
21
  export * from './ColorPickerField';
21
22
  export * from './CommandPalette';
@@ -16,6 +16,7 @@ export * from "./Chip/index.js";
16
16
  export * from "./ClientOnly/index.js";
17
17
  export * from "./Clipboard/index.js";
18
18
  export * from "./Code/index.js";
19
+ export * from "./CodeGroup/index.js";
19
20
  export * from "./ColorPicker/index.js";
20
21
  export * from "./ColorPickerField/index.js";
21
22
  export * from "./CommandPalette/index.js";
@@ -37,7 +37,7 @@ function lruSet(key, value) {
37
37
  async function loadHighlighter(loader, langs) {
38
38
  if (_highlighterUnavailable) return null;
39
39
  if (_highlighterPromise) return _highlighterPromise;
40
- _highlighterPromise = (async () => {
40
+ const raw = (async () => {
41
41
  const shiki = loader ? await loader() : await Promise.resolve().then(() => require("shiki"));
42
42
  const highlighter = await shiki.createHighlighter({
43
43
  themes: [_code.CODE_LIGHT_THEME, _code.CODE_DARK_THEME],
@@ -46,7 +46,7 @@ async function loadHighlighter(loader, langs) {
46
46
  _highlighterReady = true;
47
47
  return highlighter;
48
48
  })();
49
- return _highlighterPromise.catch(err => {
49
+ _highlighterPromise = raw.catch(err => {
50
50
  _highlighterUnavailable = true;
51
51
  _highlighterPromise = null;
52
52
  if (!_unavailableWarned) {
@@ -55,6 +55,7 @@ async function loadHighlighter(loader, langs) {
55
55
  }
56
56
  return null;
57
57
  });
58
+ return _highlighterPromise;
58
59
  }
59
60
  function resolveLang(lang, hasCustomHighlighter, extraLangs) {
60
61
  if (hasCustomHighlighter) return lang;
@@ -30,7 +30,7 @@ function lruSet(key, value) {
30
30
  async function loadHighlighter(loader, langs) {
31
31
  if (_highlighterUnavailable) return null;
32
32
  if (_highlighterPromise) return _highlighterPromise;
33
- _highlighterPromise = (async () => {
33
+ const raw = (async () => {
34
34
  const shiki = loader ? await loader() : await import(
35
35
  /* @vite-ignore */
36
36
  "shiki"
@@ -42,7 +42,7 @@ async function loadHighlighter(loader, langs) {
42
42
  _highlighterReady = true;
43
43
  return highlighter;
44
44
  })();
45
- return _highlighterPromise.catch((err) => {
45
+ _highlighterPromise = raw.catch((err) => {
46
46
  _highlighterUnavailable = true;
47
47
  _highlighterPromise = null;
48
48
  if (!_unavailableWarned) {
@@ -54,6 +54,7 @@ async function loadHighlighter(loader, langs) {
54
54
  }
55
55
  return null;
56
56
  });
57
+ return _highlighterPromise;
57
58
  }
58
59
  function resolveLang(lang, hasCustomHighlighter, extraLangs) {
59
60
  if (hasCustomHighlighter) return lang;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.CODE_GROUP_EMBED_PROPS = exports.CODE_GROUP_DEFAULTS = void 0;
7
+ const CODE_GROUP_EMBED_PROPS = exports.CODE_GROUP_EMBED_PROPS = {
8
+ hideHeader: true,
9
+ flat: true,
10
+ copyable: false
11
+ };
12
+ const CODE_GROUP_DEFAULTS = exports.CODE_GROUP_DEFAULTS = {
13
+ tag: "figure",
14
+ copyable: true,
15
+ lineNumbers: false,
16
+ wrap: false
17
+ };
@@ -0,0 +1,16 @@
1
+ import type { ICodeProps } from '../../interfaces/Code/code.interface';
2
+ /*********************************************************
3
+ * CODE_GROUP_EMBED_PROPS
4
+ *
5
+ * @description
6
+ * What `<OrigamCodeGroup>` forces on every `<OrigamCode>` it hosts: the tab
7
+ * already shows the label, the group already owns the one surface and the
8
+ * one copy button.
9
+ ********************************************************/
10
+ export declare const CODE_GROUP_EMBED_PROPS: Pick<ICodeProps, 'hideHeader' | 'flat' | 'copyable'>;
11
+ export declare const CODE_GROUP_DEFAULTS: {
12
+ readonly tag: "figure";
13
+ readonly copyable: true;
14
+ readonly lineNumbers: false;
15
+ readonly wrap: false;
16
+ };
@@ -0,0 +1,11 @@
1
+ export const CODE_GROUP_EMBED_PROPS = {
2
+ hideHeader: true,
3
+ flat: true,
4
+ copyable: false
5
+ };
6
+ export const CODE_GROUP_DEFAULTS = {
7
+ tag: "figure",
8
+ copyable: true,
9
+ lineNumbers: false,
10
+ wrap: false
11
+ };
@@ -366,6 +366,17 @@ Object.keys(_code).forEach(function (key) {
366
366
  }
367
367
  });
368
368
  });
369
+ var _codeGroup = require("./CodeGroup/code-group.const.cjs");
370
+ Object.keys(_codeGroup).forEach(function (key) {
371
+ if (key === "default" || key === "__esModule") return;
372
+ if (key in exports && exports[key] === _codeGroup[key]) return;
373
+ Object.defineProperty(exports, key, {
374
+ enumerable: true,
375
+ get: function () {
376
+ return _codeGroup[key];
377
+ }
378
+ });
379
+ });
369
380
  var _selectionControl = require("./SelectionControl/selection-control.const.cjs");
370
381
  Object.keys(_selectionControl).forEach(function (key) {
371
382
  if (key === "default" || key === "__esModule") return;
@@ -31,6 +31,7 @@ export * from './Commons/vmodel.const';
31
31
  export * from './Commons/forwardRefs.const';
32
32
  export * from './ColorPicker/color-picker.const';
33
33
  export * from './Code/code.const';
34
+ export * from './CodeGroup/code-group.const';
34
35
  export * from './SelectionControl/selection-control.const';
35
36
  export * from './Snackbar/snackbar-group.const';
36
37
  export * from './Snackbar/snackbar.const';
@@ -31,6 +31,7 @@ export * from "./Commons/vmodel.const.js";
31
31
  export * from "./Commons/forwardRefs.const.js";
32
32
  export * from "./ColorPicker/color-picker.const.js";
33
33
  export * from "./Code/code.const.js";
34
+ export * from "./CodeGroup/code-group.const.js";
34
35
  export * from "./SelectionControl/selection-control.const.js";
35
36
  export * from "./Snackbar/snackbar-group.const.js";
36
37
  export * from "./Snackbar/snackbar.const.js";
@@ -88,7 +88,27 @@ export interface ICodeProps extends ICommonsComponentProps, ITagProps, IBorderPr
88
88
  * Most useful paired with `compact` for an install-command pill.
89
89
  */
90
90
  prompt?: string;
91
+ hideHeader?: boolean;
92
+ flat?: boolean;
93
+ scrollerAriaLabel?: string;
91
94
  }
95
+ /*********************************************************
96
+ * Embedding props (`hideHeader`, `flat`, `scrollerAriaLabel`)
97
+ *
98
+ * @description
99
+ * `hideHeader` removes the header bar (filename / language badge / copy
100
+ * button) whatever `filename`, `copyable` or the `header` slot say.
101
+ * @description
102
+ * `flat` flattens the block into its host: no border, no radius, no
103
+ * elevation, no outer margin, so the host owns the one visible surface.
104
+ * @description
105
+ * `scrollerAriaLabel` is the accessible name of the scrollable region. Left
106
+ * out, it is derived from `filename`, then `lang`; set it when several blocks
107
+ * of the same language share a page.
108
+ * @description
109
+ * The three exist so a block can sit inside `<OrigamCodeGroup>`, a tab already
110
+ * showing the label and the group owning the surface and the copy button.
111
+ ********************************************************/
92
112
  /*********************************************************
93
113
  * ICodeOptions
94
114
  *
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,102 @@
1
+ import type { VNode } from 'vue';
2
+ import type { IBorderProps } from '../Commons/border.interface';
3
+ import type { ICommonsComponentEmits, ICommonsComponentProps, ITagProps } from '../Commons/commons.interface';
4
+ import type { IDimensionProps } from '../Commons/dimension.interface';
5
+ import type { IElevationProps } from '../Commons/elevation.interface';
6
+ import type { IMarginProps } from '../Commons/margin.interface';
7
+ import type { IRoundedProps } from '../Commons/rounded.interface';
8
+ import type { TCodeLangOpen } from '../../types/Code/code.type';
9
+ /*********************************************************
10
+ * ICodeGroupItem
11
+ *
12
+ * @description
13
+ * One tab of an `<OrigamCodeGroup>` in its `items` form: the label shown on
14
+ * the tab and the code shown in its panel.
15
+ ********************************************************/
16
+ export interface ICodeGroupItem {
17
+ label: string;
18
+ code: string;
19
+ lang?: TCodeLangOpen;
20
+ filename?: string;
21
+ value?: string;
22
+ }
23
+ /*********************************************************
24
+ * ICodeGroupResolvedItem
25
+ *
26
+ * @description
27
+ * An `ICodeGroupItem` once the group has settled its `value` and, in the
28
+ * slot form, kept the child `<OrigamCode>` vnode to render in the panel.
29
+ ********************************************************/
30
+ export interface ICodeGroupResolvedItem extends Required<Pick<ICodeGroupItem, 'label' | 'code' | 'value'>>, Pick<ICodeGroupItem, 'lang' | 'filename'> {
31
+ vnode?: VNode;
32
+ }
33
+ /*********************************************************
34
+ * ICodeGroupRenderedItem
35
+ *
36
+ * @description
37
+ * A resolved item whose `vnode` is the `<OrigamCode>` to render in the panel,
38
+ * already flattened, header-less and named. Built by `resolveCodeGroupItems`.
39
+ ********************************************************/
40
+ export interface ICodeGroupRenderedItem extends Omit<ICodeGroupResolvedItem, 'vnode'> {
41
+ vnode: VNode;
42
+ }
43
+ /*********************************************************
44
+ * ICodeGroupResolveOptions
45
+ *
46
+ * @description
47
+ * What `resolveCodeGroupItems` needs from the group: its `label` and `t` to
48
+ * name each scroller, and `lineNumbers` / `wrap` to forward to every block.
49
+ ********************************************************/
50
+ export interface ICodeGroupResolveOptions {
51
+ label?: string;
52
+ lineNumbers: boolean;
53
+ wrap: boolean;
54
+ t: (key: string, ...params: unknown[]) => string;
55
+ }
56
+ /*********************************************************
57
+ * ICodeGroupProps
58
+ *
59
+ * @description
60
+ * Props for `<OrigamCodeGroup>` — tabbed code blocks (npm / pnpm / yarn)
61
+ * drawn as ONE surface with one shared copy button. Fed either by `items`
62
+ * or by `<origam-code>` children in the default slot (the tab label comes
63
+ * from the child's `label`, else its `filename`).
64
+ * @description
65
+ * `modelValue` is the `value` of the active tab (default: the first tab).
66
+ * `label` is the accessible name of the tab list (default: a localised
67
+ * generic name). `copyable`, `lineNumbers` and `wrap` apply to the whole
68
+ * group. `items` is ignored when the default slot holds code blocks.
69
+ ********************************************************/
70
+ export interface ICodeGroupProps extends ICommonsComponentProps, ITagProps, IBorderProps, IRoundedProps, IElevationProps, IMarginProps, IDimensionProps {
71
+ items?: ICodeGroupItem[];
72
+ modelValue?: string;
73
+ label?: string;
74
+ copyable?: boolean;
75
+ lineNumbers?: boolean;
76
+ wrap?: boolean;
77
+ }
78
+ /*********************************************************
79
+ * ICodeGroupEmits
80
+ *
81
+ * @description
82
+ * `update:modelValue` carries the new active tab `value`; `copy` carries the
83
+ * code of the tab that was copied.
84
+ ********************************************************/
85
+ export interface ICodeGroupEmits extends ICommonsComponentEmits {
86
+ (e: 'update:modelValue', value: string): void;
87
+ (e: 'copy', code: string): void;
88
+ }
89
+ /*********************************************************
90
+ * ICodeGroupSlots
91
+ *
92
+ * @description
93
+ * `default` takes the `<origam-code>` children, one per tab, when `items` is
94
+ * not used. `copy` replaces the shared copy button.
95
+ ********************************************************/
96
+ export interface ICodeGroupSlots {
97
+ default?: () => any;
98
+ copy?: (data: {
99
+ copy: () => Promise<void>;
100
+ copied: boolean;
101
+ }) => any;
102
+ }
@@ -399,6 +399,17 @@ Object.keys(_code).forEach(function (key) {
399
399
  }
400
400
  });
401
401
  });
402
+ var _codeGroup = require("./CodeGroup/code-group.interface.cjs");
403
+ Object.keys(_codeGroup).forEach(function (key) {
404
+ if (key === "default" || key === "__esModule") return;
405
+ if (key in exports && exports[key] === _codeGroup[key]) return;
406
+ Object.defineProperty(exports, key, {
407
+ enumerable: true,
408
+ get: function () {
409
+ return _codeGroup[key];
410
+ }
411
+ });
412
+ });
402
413
  var _colorPicker = require("./ColorPicker/color-picker.interface.cjs");
403
414
  Object.keys(_colorPicker).forEach(function (key) {
404
415
  if (key === "default" || key === "__esModule") return;
@@ -34,6 +34,7 @@ export * from './Chip/chip-group.interface';
34
34
  export * from './ClientOnly/client-only.interface';
35
35
  export * from './Clipboard/clipboard.interface';
36
36
  export * from './Code/code.interface';
37
+ export * from './CodeGroup/code-group.interface';
37
38
  export * from './ColorPicker/color-picker.interface';
38
39
  export * from './ColorPicker/color-picker-canvas.interface';
39
40
  export * from './ConfirmWrapper/confirm-wrapper.interface';
@@ -34,6 +34,7 @@ export * from "./Chip/chip-group.interface.js";
34
34
  export * from "./ClientOnly/client-only.interface.js";
35
35
  export * from "./Clipboard/clipboard.interface.js";
36
36
  export * from "./Code/code.interface.js";
37
+ export * from "./CodeGroup/code-group.interface.js";
37
38
  export * from "./ColorPicker/color-picker.interface.js";
38
39
  export * from "./ColorPicker/color-picker-canvas.interface.js";
39
40
  export * from "./ConfirmWrapper/confirm-wrapper.interface.js";
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,2 @@
1
+ import OrigamCodeGroup from '../../components/CodeGroup/OrigamCodeGroup.vue';
2
+ export type TOrigamCodeGroup = InstanceType<typeof OrigamCodeGroup>;
File without changes
@@ -333,6 +333,17 @@ Object.keys(_code).forEach(function (key) {
333
333
  }
334
334
  });
335
335
  });
336
+ var _codeGroup = require("./CodeGroup/code-group.type.cjs");
337
+ Object.keys(_codeGroup).forEach(function (key) {
338
+ if (key === "default" || key === "__esModule") return;
339
+ if (key in exports && exports[key] === _codeGroup[key]) return;
340
+ Object.defineProperty(exports, key, {
341
+ enumerable: true,
342
+ get: function () {
343
+ return _codeGroup[key];
344
+ }
345
+ });
346
+ });
336
347
  var _colorPicker = require("./ColorPicker/color-picker.type.cjs");
337
348
  Object.keys(_colorPicker).forEach(function (key) {
338
349
  if (key === "default" || key === "__esModule") return;
@@ -28,6 +28,7 @@ export * from './Chip/chip-group.type';
28
28
  export * from './ClientOnly/client-only.type';
29
29
  export * from './Clipboard/clipboard.type';
30
30
  export * from './Code/code.type';
31
+ export * from './CodeGroup/code-group.type';
31
32
  export * from './ColorPicker/color-picker.type';
32
33
  export * from './ColorPicker/color-picker-canvas.type';
33
34
  export * from './ColorPicker/color-picker-preview.type';
@@ -28,6 +28,7 @@ export * from "./Chip/chip-group.type.js";
28
28
  export * from "./ClientOnly/client-only.type.js";
29
29
  export * from "./Clipboard/clipboard.type.js";
30
30
  export * from "./Code/code.type.js";
31
+ export * from "./CodeGroup/code-group.type.js";
31
32
  export * from "./ColorPicker/color-picker.type.js";
32
33
  export * from "./ColorPicker/color-picker-canvas.type.js";
33
34
  export * from "./ColorPicker/color-picker-preview.type.js";
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.extractCodeGroupText = extractCodeGroupText;
7
+ exports.findCodeGroupItem = findCodeGroupItem;
8
+ exports.flattenCodeGroupVNodes = flattenCodeGroupVNodes;
9
+ exports.resolveCodeGroupItems = resolveCodeGroupItems;
10
+ exports.resolveCodeGroupSlotItems = resolveCodeGroupSlotItems;
11
+ var _vue = require("vue");
12
+ var _OrigamCode = _interopRequireDefault(require("../../components/Code/OrigamCode.vue"));
13
+ var _codeGroup = require("../../consts/CodeGroup/code-group.const.cjs");
14
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
+ function flattenCodeGroupVNodes(nodes) {
16
+ const out = [];
17
+ for (const node of nodes ?? []) {
18
+ if (node.type === _vue.Fragment && Array.isArray(node.children)) {
19
+ out.push(...flattenCodeGroupVNodes(node.children));
20
+ } else if (node.type !== _vue.Comment && node.type !== _vue.Text) {
21
+ out.push(node);
22
+ }
23
+ }
24
+ return out;
25
+ }
26
+ function extractCodeGroupText(node) {
27
+ const children = node.children;
28
+ const raw = typeof children === "object" && children !== null && !Array.isArray(children) ? children.default?.() : children;
29
+ const parts = [];
30
+ const visit = value => {
31
+ if (value == null || typeof value === "boolean") return;
32
+ if (typeof value === "string" || typeof value === "number") {
33
+ parts.push(String(value));
34
+ return;
35
+ }
36
+ if (Array.isArray(value)) {
37
+ value.forEach(visit);
38
+ return;
39
+ }
40
+ visit(value.children);
41
+ };
42
+ visit(raw);
43
+ return parts.join("").replace(/^\n+/, "").replace(/\n+$/, "");
44
+ }
45
+ function resolveCodeGroupSlotItems(nodes) {
46
+ return flattenCodeGroupVNodes(nodes).map((vnode, index) => {
47
+ const attrs = vnode.props ?? {};
48
+ const label = String(attrs.label ?? attrs.filename ?? index + 1);
49
+ return {
50
+ label,
51
+ value: String(attrs.value ?? label),
52
+ code: typeof attrs.code === "string" ? attrs.code : extractCodeGroupText(vnode),
53
+ lang: attrs.lang,
54
+ filename: attrs.filename,
55
+ vnode
56
+ };
57
+ });
58
+ }
59
+ function resolveCodeGroupItems(items, nodes, options) {
60
+ const fromSlot = resolveCodeGroupSlotItems(nodes);
61
+ const source = fromSlot.length > 0 ? fromSlot : items.map(item => ({
62
+ ...item,
63
+ value: item.value ?? item.label
64
+ }));
65
+ return source.map((item, index) => {
66
+ const params = {
67
+ label: item.label,
68
+ position: index + 1,
69
+ total: source.length
70
+ };
71
+ const scrollerAriaLabel = options.label ? options.t("origam.code_group.scroller_aria_label_group", {
72
+ ...params,
73
+ group: options.label
74
+ }) : options.t("origam.code_group.scroller_aria_label", params);
75
+ const embed = {
76
+ ..._codeGroup.CODE_GROUP_EMBED_PROPS,
77
+ lineNumbers: options.lineNumbers || void 0,
78
+ wrap: options.wrap || void 0,
79
+ scrollerAriaLabel
80
+ };
81
+ const vnode = item.vnode ? (0, _vue.cloneVNode)(item.vnode, {
82
+ ...embed,
83
+ label: void 0,
84
+ value: void 0
85
+ }) : (0, _vue.h)(_OrigamCode.default, {
86
+ code: item.code,
87
+ lang: item.lang,
88
+ filename: item.filename,
89
+ ...embed
90
+ });
91
+ return {
92
+ ...item,
93
+ vnode
94
+ };
95
+ });
96
+ }
97
+ function findCodeGroupItem(items, value) {
98
+ return items.find(item => item.value === value) ?? items[0];
99
+ }
@@ -0,0 +1,51 @@
1
+ import type { VNode } from 'vue';
2
+ import type { ICodeGroupRenderedItem, ICodeGroupResolvedItem, ICodeGroupResolveOptions } from '../../interfaces/CodeGroup/code-group.interface';
3
+ /*********************************************************
4
+ * flattenCodeGroupVNodes
5
+ *
6
+ * @description
7
+ * Walks a default-slot vnode list, going through fragments (`v-for`), and
8
+ * returns the component vnodes only: comments and whitespace text are the
9
+ * template's noise, not tabs.
10
+ ********************************************************/
11
+ export declare function flattenCodeGroupVNodes(nodes: VNode[] | undefined): VNode[];
12
+ /*********************************************************
13
+ * extractCodeGroupText
14
+ *
15
+ * @description
16
+ * Text content of a child's default slot, used when the block gives its code
17
+ * in the slot rather than in the `code` prop (same rule as `<OrigamCode>`:
18
+ * leading and trailing blank lines dropped).
19
+ ********************************************************/
20
+ export declare function extractCodeGroupText(node: VNode): string;
21
+ /*********************************************************
22
+ * resolveCodeGroupSlotItems
23
+ *
24
+ * @description
25
+ * Builds the tabs of the slot form. The label is the child's `label`, else its
26
+ * `filename`, else its position, so a block is never left without a tab.
27
+ ********************************************************/
28
+ export declare function resolveCodeGroupSlotItems(nodes: VNode[] | undefined): ICodeGroupResolvedItem[];
29
+ /*********************************************************
30
+ * resolveCodeGroupItems
31
+ *
32
+ * @description
33
+ * One list for both forms of `<OrigamCodeGroup>`: the code blocks of the
34
+ * default slot win, `items` is the fallback. Every item comes back with the
35
+ * `<OrigamCode>` vnode to render, already flattened, header-less and named
36
+ * after the group `label`, its tab and its position — so the component does
37
+ * no per-item work in its template.
38
+ * @description
39
+ * `items` is typed `readonly unknown[]` on purpose: the compiled `.vue` that
40
+ * `nuxt typecheck` reads (`packages/ds/dist`) has its types stripped, so the
41
+ * prop reaches this call as `unknown[]` and an `ICodeGroupItem[]` parameter
42
+ * would add one error to the marketing type-check ratchet.
43
+ ********************************************************/
44
+ export declare function resolveCodeGroupItems(items: readonly unknown[], nodes: VNode[] | undefined, options: ICodeGroupResolveOptions): ICodeGroupRenderedItem[];
45
+ /*********************************************************
46
+ * findCodeGroupItem
47
+ *
48
+ * @description
49
+ * The item whose `value` is the active one, the first item when none matches.
50
+ ********************************************************/
51
+ export declare function findCodeGroupItem(items: ICodeGroupRenderedItem[], value: unknown): ICodeGroupRenderedItem | undefined;
@@ -0,0 +1,66 @@
1
+ import { cloneVNode, Comment, Fragment, h, Text } from "vue";
2
+ import OrigamCode from "../../components/Code/OrigamCode.vue";
3
+ import { CODE_GROUP_EMBED_PROPS } from "../../consts/CodeGroup/code-group.const.js";
4
+ export function flattenCodeGroupVNodes(nodes) {
5
+ const out = [];
6
+ for (const node of nodes ?? []) {
7
+ if (node.type === Fragment && Array.isArray(node.children)) {
8
+ out.push(...flattenCodeGroupVNodes(node.children));
9
+ } else if (node.type !== Comment && node.type !== Text) {
10
+ out.push(node);
11
+ }
12
+ }
13
+ return out;
14
+ }
15
+ export function extractCodeGroupText(node) {
16
+ const children = node.children;
17
+ const raw = typeof children === "object" && children !== null && !Array.isArray(children) ? children.default?.() : children;
18
+ const parts = [];
19
+ const visit = (value) => {
20
+ if (value == null || typeof value === "boolean") return;
21
+ if (typeof value === "string" || typeof value === "number") {
22
+ parts.push(String(value));
23
+ return;
24
+ }
25
+ if (Array.isArray(value)) {
26
+ value.forEach(visit);
27
+ return;
28
+ }
29
+ visit(value.children);
30
+ };
31
+ visit(raw);
32
+ return parts.join("").replace(/^\n+/, "").replace(/\n+$/, "");
33
+ }
34
+ export function resolveCodeGroupSlotItems(nodes) {
35
+ return flattenCodeGroupVNodes(nodes).map((vnode, index) => {
36
+ const attrs = vnode.props ?? {};
37
+ const label = String(attrs.label ?? attrs.filename ?? index + 1);
38
+ return {
39
+ label,
40
+ value: String(attrs.value ?? label),
41
+ code: typeof attrs.code === "string" ? attrs.code : extractCodeGroupText(vnode),
42
+ lang: attrs.lang,
43
+ filename: attrs.filename,
44
+ vnode
45
+ };
46
+ });
47
+ }
48
+ export function resolveCodeGroupItems(items, nodes, options) {
49
+ const fromSlot = resolveCodeGroupSlotItems(nodes);
50
+ const source = fromSlot.length > 0 ? fromSlot : items.map((item) => ({ ...item, value: item.value ?? item.label }));
51
+ return source.map((item, index) => {
52
+ const params = { label: item.label, position: index + 1, total: source.length };
53
+ const scrollerAriaLabel = options.label ? options.t("origam.code_group.scroller_aria_label_group", { ...params, group: options.label }) : options.t("origam.code_group.scroller_aria_label", params);
54
+ const embed = {
55
+ ...CODE_GROUP_EMBED_PROPS,
56
+ lineNumbers: options.lineNumbers || void 0,
57
+ wrap: options.wrap || void 0,
58
+ scrollerAriaLabel
59
+ };
60
+ const vnode = item.vnode ? cloneVNode(item.vnode, { ...embed, label: void 0, value: void 0 }) : h(OrigamCode, { code: item.code, lang: item.lang, filename: item.filename, ...embed });
61
+ return { ...item, vnode };
62
+ });
63
+ }
64
+ export function findCodeGroupItem(items, value) {
65
+ return items.find((item) => item.value === value) ?? items[0];
66
+ }
@@ -696,6 +696,17 @@ Object.keys(_parseHighlightLines).forEach(function (key) {
696
696
  }
697
697
  });
698
698
  });
699
+ var _codeGroup = require("./CodeGroup/code-group.util.cjs");
700
+ Object.keys(_codeGroup).forEach(function (key) {
701
+ if (key === "default" || key === "__esModule") return;
702
+ if (key in exports && exports[key] === _codeGroup[key]) return;
703
+ Object.defineProperty(exports, key, {
704
+ enumerable: true,
705
+ get: function () {
706
+ return _codeGroup[key];
707
+ }
708
+ });
709
+ });
699
710
  var _sanitizeHtml = require("./TextareaField/sanitize-html.util.cjs");
700
711
  Object.keys(_sanitizeHtml).forEach(function (key) {
701
712
  if (key === "default" || key === "__esModule") return;
@@ -61,6 +61,7 @@ export * from './DataTable/slot-name.util';
61
61
  export * from './DataTable/skeleton-cell.util';
62
62
  export * from './CommandPalette/fuzzy-match.util';
63
63
  export * from './Code/parse-highlight-lines.util';
64
+ export * from './CodeGroup/code-group.util';
64
65
  export * from './TextareaField/sanitize-html.util';
65
66
  export * from './TextareaField/html-to-markdown.util';
66
67
  export * from './Commons/apply-mask.util';
@@ -61,6 +61,7 @@ export * from "./DataTable/slot-name.util.js";
61
61
  export * from "./DataTable/skeleton-cell.util.js";
62
62
  export * from "./CommandPalette/fuzzy-match.util.js";
63
63
  export * from "./Code/parse-highlight-lines.util.js";
64
+ export * from "./CodeGroup/code-group.util.js";
64
65
  export * from "./TextareaField/sanitize-html.util.js";
65
66
  export * from "./TextareaField/html-to-markdown.util.js";
66
67
  export * from "./Commons/apply-mask.util.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "origam",
3
- "version": "2.35.0",
3
+ "version": "2.36.0",
4
4
  "type": "module",
5
5
  "description": "origam — a Vue 3 design system with multi-theme design tokens, CSS-first components and TypeScript types.",
6
6
  "keywords": [