@aleph-alpha/settings-kit 0.0.0-stage → 1.0.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 (174) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +489 -2
  3. package/dist/SkLayout.vue_vue_type_script_setup_true_lang-ZjV2AMdR.js +51 -0
  4. package/dist/SkLayoutPage-DGbCpQFm.js +2545 -0
  5. package/dist/UseFileConvertor-DN6cCXNi.js +50 -0
  6. package/dist/components/SkField/SkField.vue.d.ts +28 -0
  7. package/dist/components/SkField/SkField.vue.d.ts.map +1 -0
  8. package/dist/components/SkField/index.d.ts +2 -0
  9. package/dist/components/SkField/index.d.ts.map +1 -0
  10. package/dist/components/SkGroup/SkGroup.vue.d.ts +29 -0
  11. package/dist/components/SkGroup/SkGroup.vue.d.ts.map +1 -0
  12. package/dist/components/SkGroup/index.d.ts +2 -0
  13. package/dist/components/SkGroup/index.d.ts.map +1 -0
  14. package/dist/components/SkItem/SkItem.vue.d.ts +22 -0
  15. package/dist/components/SkItem/SkItem.vue.d.ts.map +1 -0
  16. package/dist/components/SkItem/index.d.ts +2 -0
  17. package/dist/components/SkItem/index.d.ts.map +1 -0
  18. package/dist/components/SkLayout/SkLayout.vue.d.ts +53 -0
  19. package/dist/components/SkLayout/SkLayout.vue.d.ts.map +1 -0
  20. package/dist/components/SkLayout/SkLayoutPage.d.ts +23 -0
  21. package/dist/components/SkLayout/SkLayoutPage.d.ts.map +1 -0
  22. package/dist/components/SkLayout/context.d.ts +61 -0
  23. package/dist/components/SkLayout/context.d.ts.map +1 -0
  24. package/dist/components/SkLayout/index.d.ts +5 -0
  25. package/dist/components/SkLayout/index.d.ts.map +1 -0
  26. package/dist/components/SkPage/SkPage.vue.d.ts +35 -0
  27. package/dist/components/SkPage/SkPage.vue.d.ts.map +1 -0
  28. package/dist/components/SkPage/index.d.ts +2 -0
  29. package/dist/components/SkPage/index.d.ts.map +1 -0
  30. package/dist/components/SkSection/SkSection.vue.d.ts +29 -0
  31. package/dist/components/SkSection/SkSection.vue.d.ts.map +1 -0
  32. package/dist/components/SkSection/index.d.ts +2 -0
  33. package/dist/components/SkSection/index.d.ts.map +1 -0
  34. package/dist/components/controls/SkActionsControl/SkActionsControl.vue.d.ts +37 -0
  35. package/dist/components/controls/SkActionsControl/SkActionsControl.vue.d.ts.map +1 -0
  36. package/dist/components/controls/SkActionsControl/index.d.ts +2 -0
  37. package/dist/components/controls/SkActionsControl/index.d.ts.map +1 -0
  38. package/dist/components/controls/SkCheckboxControl/SkCheckboxControl.vue.d.ts +35 -0
  39. package/dist/components/controls/SkCheckboxControl/SkCheckboxControl.vue.d.ts.map +1 -0
  40. package/dist/components/controls/SkCheckboxControl/index.d.ts +2 -0
  41. package/dist/components/controls/SkCheckboxControl/index.d.ts.map +1 -0
  42. package/dist/components/controls/SkColorControl/SkColorControl.vue.d.ts +35 -0
  43. package/dist/components/controls/SkColorControl/SkColorControl.vue.d.ts.map +1 -0
  44. package/dist/components/controls/SkColorControl/index.d.ts +2 -0
  45. package/dist/components/controls/SkColorControl/index.d.ts.map +1 -0
  46. package/dist/components/controls/SkFileUpload/SkFilePlaceholder.vue.d.ts +11 -0
  47. package/dist/components/controls/SkFileUpload/SkFilePlaceholder.vue.d.ts.map +1 -0
  48. package/dist/components/controls/SkFileUpload/SkFileUpload.vue.d.ts +46 -0
  49. package/dist/components/controls/SkFileUpload/SkFileUpload.vue.d.ts.map +1 -0
  50. package/dist/components/controls/SkFileUpload/index.d.ts +2 -0
  51. package/dist/components/controls/SkFileUpload/index.d.ts.map +1 -0
  52. package/dist/components/controls/SkPeriodControl/SkPeriodControl.vue.d.ts +35 -0
  53. package/dist/components/controls/SkPeriodControl/SkPeriodControl.vue.d.ts.map +1 -0
  54. package/dist/components/controls/SkPeriodControl/index.d.ts +2 -0
  55. package/dist/components/controls/SkPeriodControl/index.d.ts.map +1 -0
  56. package/dist/components/controls/SkSelectControl/SkSelectControl.vue.d.ts +40 -0
  57. package/dist/components/controls/SkSelectControl/SkSelectControl.vue.d.ts.map +1 -0
  58. package/dist/components/controls/SkSelectControl/index.d.ts +2 -0
  59. package/dist/components/controls/SkSelectControl/index.d.ts.map +1 -0
  60. package/dist/components/controls/SkTelControl/SKTelPrefixControl.vue.d.ts +16 -0
  61. package/dist/components/controls/SkTelControl/SKTelPrefixControl.vue.d.ts.map +1 -0
  62. package/dist/components/controls/SkTelControl/SkTelControl.vue.d.ts +35 -0
  63. package/dist/components/controls/SkTelControl/SkTelControl.vue.d.ts.map +1 -0
  64. package/dist/components/controls/SkTelControl/index.d.ts +4 -0
  65. package/dist/components/controls/SkTelControl/index.d.ts.map +1 -0
  66. package/dist/components/controls/SkTelControl/prefixes.d.ts +26 -0
  67. package/dist/components/controls/SkTelControl/prefixes.d.ts.map +1 -0
  68. package/dist/components/controls/SkTextControl/SkTextControl.vue.d.ts +45 -0
  69. package/dist/components/controls/SkTextControl/SkTextControl.vue.d.ts.map +1 -0
  70. package/dist/components/controls/SkTextControl/index.d.ts +2 -0
  71. package/dist/components/controls/SkTextControl/index.d.ts.map +1 -0
  72. package/dist/components/controls/SkUnsupportedControl/SkUnsupportedControl.vue.d.ts +8 -0
  73. package/dist/components/controls/SkUnsupportedControl/SkUnsupportedControl.vue.d.ts.map +1 -0
  74. package/dist/components/controls/storyEventLog.d.ts +33 -0
  75. package/dist/components/controls/storyEventLog.d.ts.map +1 -0
  76. package/dist/components/index.d.ts +8 -0
  77. package/dist/components/index.d.ts.map +1 -0
  78. package/dist/components/index.js +14 -0
  79. package/dist/composables/UseFileConvertor/UseFileConvertor.d.ts +7 -0
  80. package/dist/composables/UseFileConvertor/UseFileConvertor.d.ts.map +1 -0
  81. package/dist/composables/index.d.ts +14 -0
  82. package/dist/composables/index.d.ts.map +1 -0
  83. package/dist/composables/useFieldInheritance/useFieldInheritance.d.ts +24 -0
  84. package/dist/composables/useFieldInheritance/useFieldInheritance.d.ts.map +1 -0
  85. package/dist/composables/useFieldValidator/useFieldValidator.d.ts +50 -0
  86. package/dist/composables/useFieldValidator/useFieldValidator.d.ts.map +1 -0
  87. package/dist/composables/useSettingField/useSettingField.d.ts +24 -0
  88. package/dist/composables/useSettingField/useSettingField.d.ts.map +1 -0
  89. package/dist/composables/useSettingsForm/useSettingsForm.d.ts +12 -0
  90. package/dist/composables/useSettingsForm/useSettingsForm.d.ts.map +1 -0
  91. package/dist/composables/useSettingsLayout/useSettingsLayout.d.ts +71 -0
  92. package/dist/composables/useSettingsLayout/useSettingsLayout.d.ts.map +1 -0
  93. package/dist/composables/useSettingsLocale/useSettingsLocale.d.ts +38 -0
  94. package/dist/composables/useSettingsLocale/useSettingsLocale.d.ts.map +1 -0
  95. package/dist/composables/useStateManager/useStateManager.d.ts +10 -0
  96. package/dist/composables/useStateManager/useStateManager.d.ts.map +1 -0
  97. package/dist/core/controls/controlDefinitions.d.ts +33 -0
  98. package/dist/core/controls/controlDefinitions.d.ts.map +1 -0
  99. package/dist/core/controls/index.d.ts +26 -0
  100. package/dist/core/controls/index.d.ts.map +1 -0
  101. package/dist/core/index.d.ts +18 -0
  102. package/dist/core/index.d.ts.map +1 -0
  103. package/dist/core/layout/index.d.ts +8 -0
  104. package/dist/core/layout/index.d.ts.map +1 -0
  105. package/dist/core/layout/navigation.d.ts +33 -0
  106. package/dist/core/layout/navigation.d.ts.map +1 -0
  107. package/dist/core/layout/resolve.d.ts +41 -0
  108. package/dist/core/layout/resolve.d.ts.map +1 -0
  109. package/dist/core/layout/types.d.ts +160 -0
  110. package/dist/core/layout/types.d.ts.map +1 -0
  111. package/dist/core/layout/validate.d.ts +26 -0
  112. package/dist/core/layout/validate.d.ts.map +1 -0
  113. package/dist/core/types.d.ts +541 -0
  114. package/dist/core/types.d.ts.map +1 -0
  115. package/dist/core/useControlModel.d.ts +13 -0
  116. package/dist/core/useControlModel.d.ts.map +1 -0
  117. package/dist/core/utils/a11y.d.ts +25 -0
  118. package/dist/core/utils/a11y.d.ts.map +1 -0
  119. package/dist/core/utils/cast.d.ts +8 -0
  120. package/dist/core/utils/cast.d.ts.map +1 -0
  121. package/dist/core/utils/consts.d.ts +978 -0
  122. package/dist/core/utils/consts.d.ts.map +1 -0
  123. package/dist/core/utils/kitMessages.d.ts +165 -0
  124. package/dist/core/utils/kitMessages.d.ts.map +1 -0
  125. package/dist/core/utils/localizedText.d.ts +10 -0
  126. package/dist/core/utils/localizedText.d.ts.map +1 -0
  127. package/dist/core/utils/useName.d.ts +7 -0
  128. package/dist/core/utils/useName.d.ts.map +1 -0
  129. package/dist/core/validate/constraints.d.ts +20 -0
  130. package/dist/core/validate/constraints.d.ts.map +1 -0
  131. package/dist/core/validate/rules.d.ts +29 -0
  132. package/dist/core/validate/rules.d.ts.map +1 -0
  133. package/dist/favicon.ico +0 -0
  134. package/dist/generators/defineSettingUnit.d.ts +12 -0
  135. package/dist/generators/defineSettingUnit.d.ts.map +1 -0
  136. package/dist/generators/index.d.ts +2 -0
  137. package/dist/generators/index.d.ts.map +1 -0
  138. package/dist/generators/index.js +13 -0
  139. package/dist/index-BQ6z6MK4.js +214 -0
  140. package/dist/index-BXs-0JdT.js +168 -0
  141. package/dist/index-BynIH0EE.js +92 -0
  142. package/dist/index-C-WLhRod.js +100 -0
  143. package/dist/index-CFMv8jSO.js +4 -0
  144. package/dist/index-CGYERet5.js +373 -0
  145. package/dist/index-KAbhkO1J.js +81 -0
  146. package/dist/index.d.ts +11 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/index.js +52 -0
  149. package/dist/service/index.d.ts +2 -0
  150. package/dist/service/index.d.ts.map +1 -0
  151. package/dist/shell/SkShell.vue.d.ts +80 -0
  152. package/dist/shell/SkShell.vue.d.ts.map +1 -0
  153. package/dist/shell/SkShellFrame.vue.d.ts +46 -0
  154. package/dist/shell/SkShellFrame.vue.d.ts.map +1 -0
  155. package/dist/shell/SkShellNav.vue.d.ts +19 -0
  156. package/dist/shell/SkShellNav.vue.d.ts.map +1 -0
  157. package/dist/shell/history.d.ts +9 -0
  158. package/dist/shell/history.d.ts.map +1 -0
  159. package/dist/shell/index.d.ts +12 -0
  160. package/dist/shell/index.d.ts.map +1 -0
  161. package/dist/shell/index.js +848 -0
  162. package/dist/shell/labels.d.ts +25 -0
  163. package/dist/shell/labels.d.ts.map +1 -0
  164. package/dist/shell/location.d.ts +18 -0
  165. package/dist/shell/location.d.ts.map +1 -0
  166. package/dist/shell/routes.d.ts +19 -0
  167. package/dist/shell/routes.d.ts.map +1 -0
  168. package/dist/shell/useMediaQuery.d.ts +4 -0
  169. package/dist/shell/useMediaQuery.d.ts.map +1 -0
  170. package/dist/shell/useShellLocation.d.ts +37 -0
  171. package/dist/shell/useShellLocation.d.ts.map +1 -0
  172. package/dist/types.d.ts +17 -0
  173. package/dist/types.d.ts.map +1 -0
  174. package/package.json +110 -3
@@ -0,0 +1,848 @@
1
+ import { defineComponent, openBlock, createBlock, unref, withCtx, createElementBlock, Fragment, renderList, createVNode, createSlots, createTextVNode, toDisplayString, createCommentVNode, createElementVNode, ref, onBeforeUnmount, getCurrentInstance, computed, useSlots, watch, nextTick, onMounted, onBeforeUpdate, normalizeStyle, renderSlot, toValue, inject, onDeactivated, onActivated, onUnmounted, useModel, mergeProps, toHandlers, mergeModels } from "vue";
2
+ import { H as useSettingsLayout, r as provideSkLayoutContext, I as useSettingsLocale, S as SkLayoutPage, V as resolveKitMessage } from "../SkLayoutPage-DGbCpQFm.js";
3
+ import { UiSidebarMenu, UiSidebarMenuItem, UiSidebarMenuButton, UiTopBar, UiSidebarTrigger, UiTooltip, UiButton, UiIcon, UiFloatActionItems, UiSidebar, UiSidebarContent, UiSidebarGroup, UiSidebarGroupLabel, UiSidebarGroupContent, UiLayoutContent } from "@aleph-alpha/ui-library";
4
+ import { ArrowLeftIcon, ScanIcon, PanelRightIcon } from "@aleph-alpha/ui-library/icons";
5
+ import { routerKey, routeLocationKey, matchedRouteKey, createWebHistory, isNavigationFailure } from "vue-router";
6
+ function createShellRoutes(layout) {
7
+ return layout.pages.map(({ id, path }) => ({ id, path }));
8
+ }
9
+ function findShellRoute(routes, path) {
10
+ const wanted = normalizeRoutePath(path);
11
+ const exact = routes.find(
12
+ (route) => normalizeRoutePath(route.path) === wanted
13
+ );
14
+ if (exact) return exact;
15
+ const folded = wanted.toLowerCase();
16
+ return routes.find(
17
+ (route) => normalizeRoutePath(route.path).toLowerCase() === folded
18
+ );
19
+ }
20
+ function normalizeRoutePath(path) {
21
+ const segments = path.split("/").filter((segment) => segment !== "").map((segment) => encodeURIComponent(safeDecode(segment)));
22
+ return `/${segments.join("/")}`;
23
+ }
24
+ function safeDecode(segment) {
25
+ try {
26
+ return decodeURIComponent(segment);
27
+ } catch {
28
+ return segment;
29
+ }
30
+ }
31
+ const _hoisted_1$1 = {
32
+ key: 0,
33
+ class: "sr-only"
34
+ };
35
+ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
36
+ ...{
37
+ name: "SkShellNav"
38
+ },
39
+ __name: "SkShellNav",
40
+ props: {
41
+ nodes: {},
42
+ activeId: {},
43
+ hrefOf: { type: Function },
44
+ pageHasErrors: {}
45
+ },
46
+ emits: ["navigate"],
47
+ setup(__props, { emit: __emit }) {
48
+ const emit = __emit;
49
+ function open(event, id) {
50
+ const modified = event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
51
+ if (modified || event.defaultPrevented) return;
52
+ event.preventDefault();
53
+ emit("navigate", id);
54
+ }
55
+ return (_ctx, _cache) => {
56
+ return openBlock(), createBlock(unref(UiSidebarMenu), null, {
57
+ default: withCtx(() => [
58
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.nodes, (node) => {
59
+ return openBlock(), createBlock(unref(UiSidebarMenuItem), {
60
+ key: node.id
61
+ }, {
62
+ default: withCtx(() => [
63
+ createVNode(unref(UiSidebarMenuButton), {
64
+ as: "a",
65
+ href: __props.hrefOf(node.id),
66
+ tooltip: node.label,
67
+ "is-active": __props.activeId === node.id,
68
+ "aria-current": __props.activeId === node.id ? "page" : void 0,
69
+ onClick: ($event) => open($event, node.id)
70
+ }, createSlots({
71
+ default: withCtx(() => [
72
+ createTextVNode(toDisplayString(node.label) + " ", 1),
73
+ node.invalid ? (openBlock(), createElementBlock("span", _hoisted_1$1, "(" + toDisplayString(__props.pageHasErrors) + ")", 1)) : createCommentVNode("", true)
74
+ ]),
75
+ _: 2
76
+ }, [
77
+ node.invalid ? {
78
+ name: "end-icon",
79
+ fn: withCtx(() => [
80
+ _cache[0] || (_cache[0] = createElementVNode("span", {
81
+ "aria-hidden": "true",
82
+ class: "size-2 rounded-full bg-background-status-error"
83
+ }, null, -1))
84
+ ]),
85
+ key: "0"
86
+ } : void 0
87
+ ]), 1032, ["href", "tooltip", "is-active", "aria-current", "onClick"])
88
+ ]),
89
+ _: 2
90
+ }, 1024);
91
+ }), 128))
92
+ ]),
93
+ _: 1
94
+ });
95
+ };
96
+ }
97
+ });
98
+ function useMediaQuery(query) {
99
+ const matches = ref(false);
100
+ if (typeof window === "undefined" || !window.matchMedia) return matches;
101
+ const list = window.matchMedia(query);
102
+ matches.value = list.matches;
103
+ const update = (event) => {
104
+ matches.value = event.matches;
105
+ };
106
+ list.addEventListener("change", update);
107
+ onBeforeUnmount(() => list.removeEventListener("change", update));
108
+ return matches;
109
+ }
110
+ const _hoisted_1 = { class: "flex min-w-0 items-center gap-2" };
111
+ const _hoisted_2 = { class: "flex min-w-0 items-center gap-1" };
112
+ const _hoisted_3 = ["href", "aria-label"];
113
+ const _hoisted_4 = {
114
+ key: 1,
115
+ class: "body-s-medium truncate"
116
+ };
117
+ const _hoisted_5 = { class: "flex min-h-0 w-full flex-1" };
118
+ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
119
+ ...{
120
+ name: "SkShellFrame"
121
+ },
122
+ __name: "SkShellFrame",
123
+ props: {
124
+ navigation: {},
125
+ activeId: { default: void 0 },
126
+ hrefOf: {},
127
+ sidebarMode: { default: "default" },
128
+ backHref: { default: void 0 },
129
+ labels: {}
130
+ },
131
+ emits: ["navigate", "back"],
132
+ setup(__props, { emit: __emit }) {
133
+ const props = __props;
134
+ const emit = __emit;
135
+ const instance = getCurrentInstance();
136
+ const hasBack = computed(
137
+ () => Boolean(props.backHref) || Boolean(instance?.vnode.props?.onBack)
138
+ );
139
+ const slots = useSlots();
140
+ const layout = ref("sidebar");
141
+ const isMobile = useMediaQuery("(max-width: 768px)");
142
+ const desktopOpen = ref(true);
143
+ const mobileOpen = ref(false);
144
+ watch(isMobile, () => {
145
+ mobileOpen.value = false;
146
+ });
147
+ const root = ref();
148
+ const topBar = ref();
149
+ const barToggle = ref();
150
+ const railToggle = ref();
151
+ const mobileToggle = ref();
152
+ function focusToggle(wrapper) {
153
+ wrapper?.querySelector('[data-sidebar="trigger"]')?.focus();
154
+ }
155
+ const sidebarOpen = computed({
156
+ get: () => isMobile.value ? mobileOpen.value : desktopOpen.value,
157
+ set: (open) => {
158
+ if (isMobile.value) {
159
+ mobileOpen.value = open;
160
+ return;
161
+ }
162
+ const focused = document.activeElement;
163
+ const refocus = focused instanceof HTMLElement && Boolean(root.value?.contains(focused)) && focused.closest('[data-sidebar="trigger"]') !== null;
164
+ desktopOpen.value = open;
165
+ if (refocus) {
166
+ nextTick(() => focusToggle(open ? barToggle.value : railToggle.value));
167
+ }
168
+ }
169
+ });
170
+ function closeDrawer() {
171
+ if (!isMobile.value || !mobileOpen.value) return;
172
+ mobileOpen.value = false;
173
+ nextTick(() => focusToggle(mobileToggle.value));
174
+ }
175
+ function onKeydown(event) {
176
+ if (event.key !== "Escape" || event.defaultPrevented) return;
177
+ const target = event.target;
178
+ if (!target?.closest('[data-mobile="true"]')) return;
179
+ closeDrawer();
180
+ }
181
+ function onNavigate(id) {
182
+ emit("navigate", id);
183
+ closeDrawer();
184
+ }
185
+ const drawerOffset = ref(0);
186
+ let observer;
187
+ onMounted(() => {
188
+ const bar = topBar.value;
189
+ if (!bar) return;
190
+ const measure = () => {
191
+ drawerOffset.value = bar.getBoundingClientRect().bottom;
192
+ };
193
+ measure();
194
+ observer = new ResizeObserver(measure);
195
+ observer.observe(bar);
196
+ });
197
+ onBeforeUnmount(() => observer?.disconnect());
198
+ const hasSidebar = ref(Boolean(slots.sidebar));
199
+ onBeforeUpdate(() => {
200
+ const present = Boolean(slots.sidebar);
201
+ if (present && !hasSidebar.value) layout.value = "sidebar";
202
+ hasSidebar.value = present;
203
+ });
204
+ return (_ctx, _cache) => {
205
+ return openBlock(), createElementBlock("div", {
206
+ ref_key: "root",
207
+ ref: root,
208
+ class: "flex h-svh w-full flex-col overflow-hidden bg-background-surface-primary text-content-on-surface-primary",
209
+ style: normalizeStyle({ "--sidebar-offset-top": `${drawerOffset.value}px` }),
210
+ onKeydown
211
+ }, [
212
+ createElementVNode("div", {
213
+ ref_key: "topBar",
214
+ ref: topBar,
215
+ class: "shrink-0"
216
+ }, [
217
+ createVNode(unref(UiTopBar), {
218
+ "aria-label": __props.labels.title,
219
+ "leading-width": "calc(var(--sidebar-width, 16rem) - 1rem)"
220
+ }, createSlots({
221
+ logo: withCtx(() => [
222
+ createElementVNode("span", _hoisted_1, [
223
+ renderSlot(_ctx.$slots, "logo"),
224
+ createElementVNode("span", _hoisted_2, [
225
+ hasBack.value ? (openBlock(), createBlock(unref(UiTooltip), {
226
+ key: 0,
227
+ content: __props.labels.back,
228
+ side: "bottom"
229
+ }, {
230
+ default: withCtx(() => [
231
+ __props.backHref ? (openBlock(), createBlock(unref(UiButton), {
232
+ key: 0,
233
+ "as-child": "",
234
+ variant: "ghost",
235
+ size: "icon-sm"
236
+ }, {
237
+ default: withCtx(() => [
238
+ createElementVNode("a", {
239
+ href: __props.backHref,
240
+ "aria-label": __props.labels.back
241
+ }, [
242
+ createVNode(unref(UiIcon), {
243
+ name: unref(ArrowLeftIcon),
244
+ size: "s"
245
+ }, null, 8, ["name"])
246
+ ], 8, _hoisted_3)
247
+ ]),
248
+ _: 1
249
+ })) : (openBlock(), createBlock(unref(UiButton), {
250
+ key: 1,
251
+ variant: "ghost",
252
+ size: "icon-sm",
253
+ "aria-label": __props.labels.back,
254
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("back"))
255
+ }, {
256
+ default: withCtx(() => [
257
+ createVNode(unref(UiIcon), {
258
+ name: unref(ArrowLeftIcon),
259
+ size: "s"
260
+ }, null, 8, ["name"])
261
+ ]),
262
+ _: 1
263
+ }, 8, ["aria-label"]))
264
+ ]),
265
+ _: 1
266
+ }, 8, ["content"])) : createCommentVNode("", true),
267
+ __props.labels.title ? (openBlock(), createElementBlock("span", _hoisted_4, toDisplayString(__props.labels.title), 1)) : createCommentVNode("", true)
268
+ ])
269
+ ])
270
+ ]),
271
+ "mobile-sidebar-toggle": withCtx(() => [
272
+ createElementVNode("span", {
273
+ ref_key: "mobileToggle",
274
+ ref: mobileToggle,
275
+ class: "contents",
276
+ "data-sk-toggle": "mobile"
277
+ }, [
278
+ createVNode(unref(UiSidebarTrigger), {
279
+ open: sidebarOpen.value,
280
+ "onUpdate:open": _cache[2] || (_cache[2] = ($event) => sidebarOpen.value = $event),
281
+ tooltip: __props.labels.toggleSidebar,
282
+ "aria-label": __props.labels.toggleSidebar
283
+ }, null, 8, ["open", "tooltip", "aria-label"])
284
+ ], 512)
285
+ ]),
286
+ _: 2
287
+ }, [
288
+ desktopOpen.value ? {
289
+ name: "sidebar-toggle",
290
+ fn: withCtx(() => [
291
+ createElementVNode("span", {
292
+ ref_key: "barToggle",
293
+ ref: barToggle,
294
+ class: "contents",
295
+ "data-sk-toggle": "bar"
296
+ }, [
297
+ createVNode(unref(UiSidebarTrigger), {
298
+ open: sidebarOpen.value,
299
+ "onUpdate:open": _cache[1] || (_cache[1] = ($event) => sidebarOpen.value = $event),
300
+ tooltip: __props.labels.toggleSidebar,
301
+ "aria-label": __props.labels.toggleSidebar
302
+ }, null, 8, ["open", "tooltip", "aria-label"])
303
+ ], 512)
304
+ ]),
305
+ key: "0"
306
+ } : void 0,
307
+ hasSidebar.value ? {
308
+ name: "layout-actions",
309
+ fn: withCtx(() => [
310
+ createVNode(unref(UiFloatActionItems), {
311
+ modelValue: layout.value,
312
+ "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => layout.value = $event),
313
+ "aria-label": __props.labels.layout
314
+ }, {
315
+ default: withCtx(() => [
316
+ createVNode(unref(UiTooltip), {
317
+ content: __props.labels.focusLayout,
318
+ side: "bottom"
319
+ }, {
320
+ default: withCtx(() => [
321
+ createVNode(unref(UiFloatActionItems), {
322
+ type: "button",
323
+ value: "focus",
324
+ "aria-label": __props.labels.focusLayout
325
+ }, {
326
+ default: withCtx(() => [
327
+ createVNode(unref(UiIcon), {
328
+ name: unref(ScanIcon),
329
+ size: "s"
330
+ }, null, 8, ["name"])
331
+ ]),
332
+ _: 1
333
+ }, 8, ["aria-label"])
334
+ ]),
335
+ _: 1
336
+ }, 8, ["content"]),
337
+ createVNode(unref(UiTooltip), {
338
+ content: __props.labels.sidebarLayout,
339
+ side: "bottom"
340
+ }, {
341
+ default: withCtx(() => [
342
+ createVNode(unref(UiFloatActionItems), {
343
+ type: "button",
344
+ value: "sidebar",
345
+ "aria-label": __props.labels.sidebarLayout
346
+ }, {
347
+ default: withCtx(() => [
348
+ createVNode(unref(UiIcon), {
349
+ name: unref(PanelRightIcon),
350
+ size: "s"
351
+ }, null, 8, ["name"])
352
+ ]),
353
+ _: 1
354
+ }, 8, ["aria-label"])
355
+ ]),
356
+ _: 1
357
+ }, 8, ["content"])
358
+ ]),
359
+ _: 1
360
+ }, 8, ["modelValue", "aria-label"])
361
+ ]),
362
+ key: "1"
363
+ } : void 0,
364
+ _ctx.$slots.profile ? {
365
+ name: "profile",
366
+ fn: withCtx(() => [
367
+ renderSlot(_ctx.$slots, "profile")
368
+ ]),
369
+ key: "2"
370
+ } : void 0
371
+ ]), 1032, ["aria-label"])
372
+ ], 512),
373
+ createElementVNode("div", _hoisted_5, [
374
+ createVNode(unref(UiSidebar), {
375
+ open: sidebarOpen.value,
376
+ "onUpdate:open": _cache[4] || (_cache[4] = ($event) => sidebarOpen.value = $event),
377
+ collapsible: "icon",
378
+ class: "isolate",
379
+ role: "navigation",
380
+ "aria-label": __props.labels.navigation
381
+ }, {
382
+ "start-action": withCtx(() => [
383
+ createVNode(unref(UiSidebarMenu), null, {
384
+ default: withCtx(() => [
385
+ createVNode(unref(UiSidebarMenuItem), null, {
386
+ default: withCtx(() => [
387
+ createElementVNode("span", {
388
+ ref_key: "railToggle",
389
+ ref: railToggle,
390
+ class: "contents",
391
+ "data-sk-toggle": "rail"
392
+ }, [
393
+ createVNode(unref(UiSidebarTrigger), {
394
+ tooltip: __props.labels.toggleSidebar,
395
+ "aria-label": __props.labels.toggleSidebar
396
+ }, null, 8, ["tooltip", "aria-label"])
397
+ ], 512)
398
+ ]),
399
+ _: 1
400
+ })
401
+ ]),
402
+ _: 1
403
+ })
404
+ ]),
405
+ default: withCtx(() => [
406
+ createVNode(unref(UiSidebarContent), null, {
407
+ default: withCtx(() => [
408
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.navigation, (group) => {
409
+ return openBlock(), createBlock(unref(UiSidebarGroup), {
410
+ key: group.id,
411
+ "default-open": true
412
+ }, {
413
+ default: withCtx(() => [
414
+ createVNode(unref(UiSidebarGroupLabel), {
415
+ size: "xs",
416
+ "show-action": false
417
+ }, {
418
+ default: withCtx(() => [
419
+ createTextVNode(toDisplayString(group.label), 1)
420
+ ]),
421
+ _: 2
422
+ }, 1024),
423
+ createVNode(unref(UiSidebarGroupContent), null, {
424
+ default: withCtx(() => [
425
+ createVNode(_sfc_main$2, {
426
+ nodes: group.children,
427
+ "active-id": __props.activeId,
428
+ "href-of": __props.hrefOf,
429
+ "page-has-errors": __props.labels.pageHasErrors,
430
+ onNavigate
431
+ }, null, 8, ["nodes", "active-id", "href-of", "page-has-errors"])
432
+ ]),
433
+ _: 2
434
+ }, 1024)
435
+ ]),
436
+ _: 2
437
+ }, 1024);
438
+ }), 128))
439
+ ]),
440
+ _: 1
441
+ })
442
+ ]),
443
+ _: 1
444
+ }, 8, ["open", "aria-label"]),
445
+ createVNode(unref(UiLayoutContent), {
446
+ class: "min-h-0 min-w-0 flex-1 overflow-auto mb-4",
447
+ "sidebar-mode": __props.sidebarMode
448
+ }, createSlots({
449
+ default: withCtx(() => [
450
+ renderSlot(_ctx.$slots, "default")
451
+ ]),
452
+ _: 2
453
+ }, [
454
+ hasSidebar.value && layout.value === "sidebar" ? {
455
+ name: "sidebar",
456
+ fn: withCtx(() => [
457
+ renderSlot(_ctx.$slots, "sidebar")
458
+ ]),
459
+ key: "0"
460
+ } : void 0
461
+ ]), 1032, ["sidebar-mode"])
462
+ ])
463
+ ], 36);
464
+ };
465
+ }
466
+ });
467
+ const skShellHistoryKey = /* @__PURE__ */ Symbol("sk-shell-history");
468
+ function normalizeShellBase(base) {
469
+ if (!base || base === "/") return "";
470
+ const prefixed = base.startsWith("/") ? base : `/${base}`;
471
+ let end = prefixed.length;
472
+ while (end > 0 && prefixed[end - 1] === "/") end -= 1;
473
+ return prefixed.slice(0, end);
474
+ }
475
+ function shellPath(base, pagePath2) {
476
+ const normalized = normalizeShellBase(base);
477
+ if (!normalized) return pagePath2 || "/";
478
+ if (!pagePath2 || pagePath2 === "/") return normalized;
479
+ const path = pagePath2.startsWith("/") ? pagePath2 : `/${pagePath2}`;
480
+ return `${normalized}${path}`;
481
+ }
482
+ function pagePath(base, fullPath) {
483
+ const pathname = splitLocation(fullPath).path;
484
+ const normalized = normalizeShellBase(base);
485
+ if (!normalized) return pathname;
486
+ const folded = pathname.toLowerCase();
487
+ const prefix = normalized.toLowerCase();
488
+ if (folded === prefix || folded === `${prefix}/`) return "/";
489
+ if (folded.startsWith(`${prefix}/`)) return pathname.slice(normalized.length);
490
+ return void 0;
491
+ }
492
+ function splitLocation(location) {
493
+ const index = location.search(/[?#]/);
494
+ const pathname = index === -1 ? location : location.slice(0, index);
495
+ const suffix = index === -1 ? "" : location.slice(index);
496
+ return {
497
+ path: pathname.startsWith("/") ? pathname : `/${pathname}`,
498
+ suffix
499
+ };
500
+ }
501
+ function useShellLocation(options) {
502
+ const routes = computed(() => toValue(options.routes));
503
+ const base = computed(() => normalizeShellBase(toValue(options.base)));
504
+ const injected = inject(skShellHistoryKey, void 0);
505
+ const hostRouter = injected ? void 0 : inject(routerKey, void 0);
506
+ const hostRoute = hostRouter ? inject(routeLocationKey, void 0) : void 0;
507
+ const anchor = (hostRouter && inject(matchedRouteKey, void 0)?.value) ?? hostRoute?.matched.at(-1);
508
+ const canUseDom = typeof window !== "undefined";
509
+ let owned;
510
+ let stopListen;
511
+ let active = true;
512
+ const selected = ref();
513
+ let committed;
514
+ function history() {
515
+ return injected ?? owned;
516
+ }
517
+ function createOwned() {
518
+ if (injected || hostRouter || !canUseDom) return;
519
+ owned = createWebHistory(base.value || void 0);
520
+ if (insideBase() && !hasHistoryCurrent(owned)) {
521
+ owned.replace(owned.location);
522
+ }
523
+ }
524
+ function destroyOwned() {
525
+ stopListen?.();
526
+ stopListen = void 0;
527
+ owned?.destroy();
528
+ owned = void 0;
529
+ }
530
+ function listen() {
531
+ stopListen?.();
532
+ stopListen = history()?.listen(() => apply());
533
+ }
534
+ function insideBase() {
535
+ if (!owned || !base.value) return true;
536
+ return pagePath(base.value, window.location.pathname) !== void 0;
537
+ }
538
+ function hostShowsShell() {
539
+ if (!hostRoute || !anchor) return false;
540
+ return hostRoute.matched.some((record) => sameRouteRecord(record, anchor));
541
+ }
542
+ function readLocation() {
543
+ const current = history();
544
+ if (current) {
545
+ if (current === owned && !insideBase()) return void 0;
546
+ return splitLocation(current.location);
547
+ }
548
+ if (hostRoute) {
549
+ const path = pagePath(base.value, hostRoute.path);
550
+ if (path === void 0) return void 0;
551
+ return { path, suffix: "" };
552
+ }
553
+ return void 0;
554
+ }
555
+ function ownsUnknownPaths() {
556
+ if (history()) return history() !== owned || insideBase();
557
+ return base.value !== "" && hostShowsShell();
558
+ }
559
+ function fallbackId(preferred = selected.value) {
560
+ const ids = routes.value.map((route) => route.id);
561
+ return preferred && ids.includes(preferred) ? preferred : ids[0];
562
+ }
563
+ function apply() {
564
+ if (!active) return;
565
+ show();
566
+ committed = selected.value;
567
+ }
568
+ function show() {
569
+ const location = readLocation();
570
+ if (!location) {
571
+ selected.value = fallbackId();
572
+ return;
573
+ }
574
+ const match = findShellRoute(routes.value, location.path);
575
+ if (match) {
576
+ selected.value = match.id;
577
+ const current = history();
578
+ if (current && location.path !== match.path) {
579
+ current.replace(match.path + location.suffix);
580
+ }
581
+ return;
582
+ }
583
+ const first = routes.value[0];
584
+ if (!first) {
585
+ selected.value = void 0;
586
+ return;
587
+ }
588
+ if (!ownsUnknownPaths()) {
589
+ selected.value = fallbackId();
590
+ return;
591
+ }
592
+ navigate(first, "replace", location.suffix);
593
+ }
594
+ function navigate(route, mode, suffix = "") {
595
+ selected.value = route.id;
596
+ const current = history();
597
+ if (current) {
598
+ committed = route.id;
599
+ if (current === owned && !insideBase() && mode === "push") {
600
+ return;
601
+ }
602
+ current[mode](route.path + suffix);
603
+ return;
604
+ }
605
+ const local = () => {
606
+ committed = route.id;
607
+ };
608
+ if (!hostRouter || !hostRoute || !anchor || !hostShowsShell()) {
609
+ return local();
610
+ }
611
+ const target = hostRouter.resolve(shellPath(base.value, route.path));
612
+ if (samePath(target.path, hostRoute.path)) return local();
613
+ if (!target.matched.some((record) => sameRouteRecord(record, anchor))) {
614
+ return local();
615
+ }
616
+ const location = mode === "replace" ? { path: target.path, query: hostRoute.query, hash: hostRoute.hash } : { path: target.path };
617
+ const resync = () => {
618
+ if (selected.value !== route.id) return;
619
+ const match = findShellRoute(
620
+ routes.value,
621
+ pagePath(base.value, hostRoute.path) ?? ""
622
+ );
623
+ selected.value = match?.id ?? fallbackId(committed);
624
+ committed = selected.value;
625
+ };
626
+ hostRouter[mode](location).then((failure) => {
627
+ if (isNavigationFailure(failure)) resync();
628
+ }, resync);
629
+ }
630
+ function openPage(id) {
631
+ if (!id || id === selected.value) return;
632
+ const route = routes.value.find((entry) => entry.id === id);
633
+ if (route) navigate(route, "push");
634
+ }
635
+ function hrefOf(id) {
636
+ const route = routes.value.find((entry) => entry.id === id);
637
+ if (!route) return "#";
638
+ const current = history();
639
+ if (current) return current.createHref(route.path);
640
+ if (hostRouter) {
641
+ return hostRouter.resolve(shellPath(base.value, route.path)).href;
642
+ }
643
+ return shellPath(base.value, route.path);
644
+ }
645
+ createOwned();
646
+ listen();
647
+ if (hostRoute) {
648
+ watch(
649
+ () => hostRoute.path,
650
+ () => {
651
+ if (hostShowsShell()) apply();
652
+ }
653
+ );
654
+ }
655
+ watch(
656
+ () => routes.value.map((route) => `${route.id}
657
+ ${route.path}`).join("\n"),
658
+ apply,
659
+ { immediate: true, flush: "sync" }
660
+ );
661
+ watch(base, (_next, previous) => {
662
+ if (owned) {
663
+ const page = pagePath(previous, window.location.pathname);
664
+ destroyOwned();
665
+ createOwned();
666
+ listen();
667
+ if (page !== void 0 && owned) {
668
+ owned.replace(page + window.location.search + window.location.hash);
669
+ }
670
+ }
671
+ apply();
672
+ });
673
+ onDeactivated(() => {
674
+ active = false;
675
+ });
676
+ onActivated(() => {
677
+ active = true;
678
+ apply();
679
+ });
680
+ onUnmounted(() => {
681
+ stopListen?.();
682
+ owned?.destroy();
683
+ });
684
+ return {
685
+ activeId: computed(() => selected.value),
686
+ openPage,
687
+ hrefOf
688
+ };
689
+ }
690
+ function hasHistoryCurrent(history) {
691
+ const current = history.state?.current;
692
+ return typeof current === "string";
693
+ }
694
+ function samePath(left, right) {
695
+ return normalizeRoutePath(left).toLowerCase() === normalizeRoutePath(right).toLowerCase();
696
+ }
697
+ function sameRouteRecord(record, anchor) {
698
+ if (anchor.name != null && record.name === anchor.name) return true;
699
+ return record.path === anchor.path;
700
+ }
701
+ const _sfc_main = /* @__PURE__ */ defineComponent({
702
+ ...{
703
+ name: "SkShell"
704
+ },
705
+ __name: "SkShell",
706
+ props: /* @__PURE__ */ mergeModels({
707
+ layout: {},
708
+ session: { default: void 0 },
709
+ fields: { default: void 0 },
710
+ base: { default: "" },
711
+ backHref: { default: void 0 },
712
+ labels: { default: void 0 },
713
+ validators: { default: void 0 },
714
+ blocks: { default: void 0 },
715
+ headingLevel: { default: 1 }
716
+ }, {
717
+ "page": {},
718
+ "pageModifiers": {}
719
+ }),
720
+ emits: /* @__PURE__ */ mergeModels(["action", "error", "back"], ["update:page"]),
721
+ setup(__props, { expose: __expose, emit: __emit }) {
722
+ const props = __props;
723
+ const page = useModel(__props, "page");
724
+ const emit = __emit;
725
+ const model = useSettingsLayout({
726
+ layout: () => props.layout,
727
+ session: props.session,
728
+ fields: () => props.fields,
729
+ validators: props.validators
730
+ });
731
+ provideSkLayoutContext(model, {
732
+ blocks: () => props.blocks,
733
+ headingLevel: () => props.headingLevel,
734
+ onAction: (event) => emit("action", event),
735
+ onError: (error) => emit("error", error)
736
+ });
737
+ const { message } = useSettingsLocale();
738
+ const labels = computed(() => ({
739
+ title: message("shell.title"),
740
+ back: message("shell.back"),
741
+ toggleSidebar: message("shell.toggleSidebar"),
742
+ navigation: message("shell.navigation"),
743
+ layout: message("shell.layout"),
744
+ focusLayout: message("shell.focusLayout"),
745
+ sidebarLayout: message("shell.sidebarLayout"),
746
+ pageHasErrors: message("shell.pageHasErrors"),
747
+ ...props.labels
748
+ }));
749
+ const routes = computed(() => createShellRoutes(model.resolved.value));
750
+ const { activeId, openPage, hrefOf } = useShellLocation({
751
+ routes,
752
+ base: () => props.base
753
+ });
754
+ const active = computed(() => model.page(activeId.value));
755
+ const activeCategory = computed(
756
+ () => model.resolved.value.categories.find(
757
+ (category) => category.uid === active.value?.categoryId
758
+ )
759
+ );
760
+ watch(
761
+ activeId,
762
+ (id) => {
763
+ if (id !== void 0 && id !== page.value) page.value = id;
764
+ },
765
+ { immediate: true }
766
+ );
767
+ watch(page, (id) => openPage(id));
768
+ const instance = getCurrentInstance();
769
+ const backListeners = computed(
770
+ () => instance?.vnode.props?.onBack ? { back: () => emit("back") } : {}
771
+ );
772
+ __expose({
773
+ /** The layout model: session, resolved tree, navigation, validator. */
774
+ model,
775
+ /** Opens a page by id, updating the URL where the shell may. */
776
+ openPage
777
+ });
778
+ return (_ctx, _cache) => {
779
+ return openBlock(), createBlock(_sfc_main$1, mergeProps({
780
+ navigation: unref(model).navigation.value,
781
+ "active-id": unref(activeId),
782
+ "href-of": unref(hrefOf),
783
+ "sidebar-mode": active.value?.sidebarMode,
784
+ "back-href": __props.backHref,
785
+ labels: labels.value
786
+ }, toHandlers(backListeners.value), { onNavigate: unref(openPage) }), createSlots({
787
+ default: withCtx(() => [
788
+ active.value ? (openBlock(), createBlock(unref(SkLayoutPage), {
789
+ key: active.value.id,
790
+ page: active.value
791
+ }, null, 8, ["page"])) : renderSlot(_ctx.$slots, "empty", { key: 1 })
792
+ ]),
793
+ _: 2
794
+ }, [
795
+ _ctx.$slots.logo ? {
796
+ name: "logo",
797
+ fn: withCtx(() => [
798
+ renderSlot(_ctx.$slots, "logo")
799
+ ]),
800
+ key: "0"
801
+ } : void 0,
802
+ _ctx.$slots.profile ? {
803
+ name: "profile",
804
+ fn: withCtx(() => [
805
+ renderSlot(_ctx.$slots, "profile")
806
+ ]),
807
+ key: "1"
808
+ } : void 0,
809
+ active.value?.sidebar && activeCategory.value && _ctx.$slots.sidebar ? {
810
+ name: "sidebar",
811
+ fn: withCtx(() => [
812
+ renderSlot(_ctx.$slots, "sidebar", {
813
+ page: active.value,
814
+ category: activeCategory.value
815
+ })
816
+ ]),
817
+ key: "2"
818
+ } : void 0
819
+ ]), 1040, ["navigation", "active-id", "href-of", "sidebar-mode", "back-href", "labels", "onNavigate"]);
820
+ };
821
+ }
822
+ });
823
+ const english = (key) => resolveKitMessage(key, "en");
824
+ const defaultShellLabels = {
825
+ title: english("shell.title"),
826
+ back: english("shell.back"),
827
+ toggleSidebar: english("shell.toggleSidebar"),
828
+ navigation: english("shell.navigation"),
829
+ layout: english("shell.layout"),
830
+ focusLayout: english("shell.focusLayout"),
831
+ sidebarLayout: english("shell.sidebarLayout"),
832
+ pageHasErrors: english("shell.pageHasErrors")
833
+ };
834
+ export {
835
+ _sfc_main as SkShell,
836
+ _sfc_main$1 as SkShellFrame,
837
+ _sfc_main$2 as SkShellNav,
838
+ createShellRoutes,
839
+ defaultShellLabels,
840
+ findShellRoute,
841
+ normalizeRoutePath,
842
+ normalizeShellBase,
843
+ pagePath,
844
+ shellPath,
845
+ skShellHistoryKey,
846
+ splitLocation,
847
+ useShellLocation
848
+ };