@iris-ui-kit/vue 0.1.0 → 0.2.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.
@@ -1,13 +1,14 @@
1
1
  import { useFloating, useDismiss } from './chunk-3FJUCHCC.js';
2
2
  import { useMachine } from './chunk-TQB5LVOH.js';
3
3
  import { findFirstElement, mergeSlotProps } from './chunk-F77KIPOH.js';
4
- import { IrisSidebarLayout, IrisHeaderLayout } from './chunk-I6D5VXQK.js';
4
+ import { IrisHeaderLayout, IrisSidebarLayout } from './chunk-I6D5VXQK.js';
5
5
  import { IrisThemeKey } from './chunk-72PZMU6R.js';
6
+ import { IrisSortable } from './chunk-W3B6E5GN.js';
6
7
  import { useStore } from './chunk-75GSYEJS.js';
7
8
  import { useI18n } from './chunk-TCAXRWT6.js';
8
- import { defineComponent, inject, h, computed, shallowRef, onBeforeUnmount, watch, ref, provide, useId, nextTick, Teleport, Fragment, watchEffect, toValue } from 'vue';
9
+ import { defineComponent, inject, h, computed, shallowRef, onBeforeUnmount, watch, ref, provide, useId, nextTick, Teleport, Fragment, watchEffect, toValue, onMounted } from 'vue';
9
10
  import { visibleNav, findNavPath, createExpansion, branchTrail, createFloatingMachine, findNavNode, isBranch, firstLeaf, matchTypeahead, nextEnabledIndex, isClosable, createAdminShell } from '@iris-ui-kit/core';
10
- export { createTabsNav, findNavNode, findNavPath, firstLeaf, flattenNav, isBranch, isClosable, visibleNav } from '@iris-ui-kit/core';
11
+ export { createAdminPreferences, createTabsNav, filterNavByAccess, findNavNode, findNavPath, firstLeaf, flattenNav, isBranch, isClosable, localStorageAdminPreferencesStorage, nodeAllowsRoles, visibleNav } from '@iris-ui-kit/core';
11
12
  import { defaultIconRegistry, resolveThemedIcon } from '@iris-ui-kit/icons';
12
13
 
13
14
  var IrisIcon = defineComponent({
@@ -82,6 +83,10 @@ var IrisNavMenu = defineComponent({
82
83
  defaultExpandedKeys: { type: Array, default: void 0 },
83
84
  /** Icon-only rail (top-level items only). */
84
85
  collapsed: { type: Boolean, default: false },
86
+ orientation: {
87
+ type: String,
88
+ default: "vertical"
89
+ },
85
90
  ariaLabel: { type: String, default: void 0 }
86
91
  },
87
92
  emits: {
@@ -137,7 +142,7 @@ var IrisNavMenu = defineComponent({
137
142
  display: "flex",
138
143
  alignItems: "center",
139
144
  gap: "10px",
140
- width: "100%",
145
+ width: props.orientation === "horizontal" && opts.depth === 0 ? "auto" : "100%",
141
146
  boxSizing: "border-box",
142
147
  border: "none",
143
148
  borderRadius: "var(--iris-radius-md, 6px)",
@@ -149,7 +154,8 @@ var IrisNavMenu = defineComponent({
149
154
  textAlign: "start",
150
155
  cursor: opts.disabled ? "not-allowed" : "pointer",
151
156
  opacity: opts.disabled ? "0.5" : "1",
152
- padding: props.collapsed ? "10px" : `8px 10px 8px ${12 + opts.depth * 16}px`,
157
+ padding: props.collapsed ? "10px" : "8px 10px",
158
+ paddingInlineStart: props.collapsed ? "10px" : `${12 + opts.depth * 16}px`,
153
159
  justifyContent: props.collapsed ? "center" : "flex-start"
154
160
  };
155
161
  };
@@ -243,16 +249,40 @@ var IrisNavMenu = defineComponent({
243
249
  }) : null
244
250
  ]
245
251
  );
252
+ const groupStyle = props.orientation === "horizontal" && depth === 0 ? { position: "relative" } : void 0;
246
253
  if (!branch || !open)
247
- return h("div", { key: node.key, "data-iris-nav-group": branch ? "" : void 0 }, [row]);
248
- return h("div", { key: node.key, "data-iris-nav-group": "", "data-open": "true" }, [
249
- row,
250
- h(
254
+ return h(
251
255
  "div",
252
- { "data-iris-nav-children": "", role: "group" },
253
- (node.children ?? []).map((child) => renderItem(child, depth + 1))
254
- )
255
- ]);
256
+ { key: node.key, "data-iris-nav-group": branch ? "" : void 0, style: groupStyle },
257
+ [row]
258
+ );
259
+ return h(
260
+ "div",
261
+ { key: node.key, "data-iris-nav-group": "", "data-open": "true", style: groupStyle },
262
+ [
263
+ row,
264
+ h(
265
+ "div",
266
+ {
267
+ "data-iris-nav-children": "",
268
+ role: "group",
269
+ style: props.orientation === "horizontal" && depth === 0 ? {
270
+ position: "absolute",
271
+ insetBlockStart: "calc(100% + 4px)",
272
+ insetInlineStart: "0",
273
+ zIndex: "60",
274
+ minWidth: "220px",
275
+ padding: "6px",
276
+ border: "1px solid var(--iris-border)",
277
+ borderRadius: "var(--iris-radius-md, 6px)",
278
+ background: "var(--iris-surface)",
279
+ boxShadow: "var(--iris-shadow-md)"
280
+ } : void 0
281
+ },
282
+ (node.children ?? []).map((child) => renderItem(child, depth + 1))
283
+ )
284
+ ]
285
+ );
256
286
  };
257
287
  const onKeydown = (e) => {
258
288
  const root = e.currentTarget;
@@ -305,11 +335,13 @@ var IrisNavMenu = defineComponent({
305
335
  ...attrs,
306
336
  "data-iris-nav-menu": "",
307
337
  "data-collapsed": props.collapsed ? "true" : void 0,
338
+ "data-orientation": props.orientation,
308
339
  "aria-label": props.ariaLabel ?? t("admin.nav"),
309
340
  onKeydown,
310
341
  style: {
311
342
  display: "flex",
312
- flexDirection: "column",
343
+ flexDirection: props.orientation === "horizontal" ? "row" : "column",
344
+ alignItems: props.orientation === "horizontal" ? "center" : void 0,
313
345
  gap: "2px",
314
346
  ...attrs.style ?? {}
315
347
  }
@@ -499,6 +531,7 @@ function useTabsNav(nav) {
499
531
  closeRight: nav.closeRight,
500
532
  refresh: nav.refresh,
501
533
  setPinned: nav.setPinned,
534
+ move: nav.move,
502
535
  cacheKey: nav.cacheKey
503
536
  };
504
537
  }
@@ -825,12 +858,14 @@ var IrisAdminTabs = defineComponent({
825
858
  inheritAttrs: false,
826
859
  props: {
827
860
  /** Shared tabs store (from `createTabsNav`). */
828
- nav: { type: Object, required: true }
861
+ nav: { type: Object, required: true },
862
+ reorderable: { type: Boolean, default: true }
829
863
  },
830
864
  emits: {
831
865
  change: (_key) => true,
832
866
  close: (_key) => true,
833
- refresh: (_key) => true
867
+ refresh: (_key) => true,
868
+ reorder: (_tabs) => true
834
869
  },
835
870
  setup(props, { emit, attrs }) {
836
871
  const { t: tr } = useI18n();
@@ -847,6 +882,10 @@ var IrisAdminTabs = defineComponent({
847
882
  props.nav.refresh(key);
848
883
  emit("refresh", key);
849
884
  };
885
+ const reorder = (tabs) => {
886
+ tabs.forEach((tab, index) => props.nav.move(tab.key, index));
887
+ emit("reorder", tabs);
888
+ };
850
889
  const focusTab = (root, key) => {
851
890
  if (!root || !key) return;
852
891
  const labels = root.querySelectorAll("[data-iris-tab-label]");
@@ -998,6 +1037,8 @@ var IrisAdminTabs = defineComponent({
998
1037
  action(tr("admin.refresh"), () => refresh(key)),
999
1038
  action(tr("admin.close"), () => close(key)),
1000
1039
  h(IrisDropdownSeparator),
1040
+ action(tr("admin.closeLeft"), () => props.nav.closeLeft(key)),
1041
+ action(tr("admin.closeRight"), () => props.nav.closeRight(key)),
1001
1042
  action(tr("admin.closeOthers"), () => props.nav.closeOthers(key)),
1002
1043
  action(tr("admin.closeAll"), () => props.nav.closeAll())
1003
1044
  ];
@@ -1029,14 +1070,28 @@ var IrisAdminTabs = defineComponent({
1029
1070
  "aria-label": tr("admin.openPages"),
1030
1071
  onKeydown: onTablistKeydown,
1031
1072
  style: {
1032
- display: "flex",
1033
- alignItems: "center",
1034
- gap: "6px",
1035
1073
  overflowX: "auto",
1036
1074
  flex: "1"
1037
1075
  }
1038
1076
  },
1039
- t.tabs.value.map((tab) => chip(tab))
1077
+ [
1078
+ h(
1079
+ IrisSortable,
1080
+ {
1081
+ items: t.tabs.value,
1082
+ getKey: (item) => item.key,
1083
+ onReorder: (items) => reorder(items),
1084
+ disabled: !props.reorderable,
1085
+ orientation: "horizontal",
1086
+ style: {
1087
+ alignItems: "center",
1088
+ gap: "6px",
1089
+ width: "max-content"
1090
+ }
1091
+ },
1092
+ { default: () => t.tabs.value.map((tab) => chip(tab)) }
1093
+ )
1094
+ ]
1040
1095
  ),
1041
1096
  actionsMenu()
1042
1097
  ]
@@ -1085,6 +1140,8 @@ var IrisAdminLayout = defineComponent({
1085
1140
  menus: { type: Array, required: true },
1086
1141
  /** Active page key (v-model:activeKey). */
1087
1142
  activeKey: { type: String, default: void 0 },
1143
+ /** Initial active page key when `activeKey` is uncontrolled. */
1144
+ defaultActiveKey: { type: String, default: void 0 },
1088
1145
  /** Sidebar collapsed (v-model:collapsed); undefined = uncontrolled. */
1089
1146
  collapsed: { type: Boolean, default: void 0 },
1090
1147
  defaultCollapsed: { type: Boolean, default: false },
@@ -1093,7 +1150,16 @@ var IrisAdminLayout = defineComponent({
1093
1150
  appTitle: { type: String, default: "Iris Admin" },
1094
1151
  /** Optional shared tabs store; when present the tab bar is rendered. */
1095
1152
  tabs: { type: Object, default: void 0 },
1153
+ showTabs: { type: Boolean, default: true },
1096
1154
  showBreadcrumb: { type: Boolean, default: true },
1155
+ stickyHeader: { type: Boolean, default: true },
1156
+ stickyTabs: { type: Boolean, default: true },
1157
+ menuAlign: { type: String, default: "start" },
1158
+ contentWidth: { type: String, default: "fluid" },
1159
+ contentHeight: {
1160
+ type: String,
1161
+ default: "viewport"
1162
+ },
1097
1163
  sidebarWidth: { type: [Number, String], default: 240 },
1098
1164
  collapsedWidth: { type: [Number, String], default: 64 }
1099
1165
  },
@@ -1112,6 +1178,7 @@ var IrisAdminLayout = defineComponent({
1112
1178
  } = useAdminShell({
1113
1179
  menus: () => props.menus,
1114
1180
  activeKey: () => props.activeKey,
1181
+ defaultActiveKey: props.defaultActiveKey,
1115
1182
  tabs: props.tabs,
1116
1183
  onActiveKeyChange: (key) => emit("update:activeKey", key),
1117
1184
  onSelect: (key, node) => emit("select", key, node)
@@ -1230,11 +1297,37 @@ var IrisAdminLayout = defineComponent({
1230
1297
  ) : null
1231
1298
  ]
1232
1299
  );
1233
- const renderContent = () => h(
1300
+ const renderContent = (horizontal = false) => h(
1234
1301
  "div",
1235
- { "data-iris-admin-content": "", style: { padding: "16px" } },
1236
- slots.default?.({ activeKey: activeKey.value }) ?? []
1302
+ {
1303
+ "data-iris-admin-content": "",
1304
+ "data-width": props.contentWidth,
1305
+ style: {
1306
+ boxSizing: "border-box",
1307
+ width: "100%",
1308
+ maxWidth: props.contentWidth === "centered" ? "72rem" : void 0,
1309
+ marginInline: props.contentWidth === "centered" ? "auto" : void 0,
1310
+ padding: "16px"
1311
+ }
1312
+ },
1313
+ [
1314
+ horizontal && props.showBreadcrumb ? h(IrisAdminBreadcrumb, { trail: trail.value, hideSingle: false, onSelect }) : null,
1315
+ ...slots.default?.({ activeKey: activeKey.value }) ?? []
1316
+ ]
1237
1317
  );
1318
+ const renderTabs = () => props.tabs && props.showTabs ? h(
1319
+ "div",
1320
+ {
1321
+ "data-iris-admin-tabs-region": "",
1322
+ "data-sticky": props.stickyTabs ? "true" : void 0,
1323
+ style: {
1324
+ position: props.stickyTabs && !props.stickyHeader ? "sticky" : "relative",
1325
+ top: "0",
1326
+ zIndex: "49"
1327
+ }
1328
+ },
1329
+ [h(IrisAdminTabs, { nav: props.tabs })]
1330
+ ) : null;
1238
1331
  return () => {
1239
1332
  if (props.mode === "full-content") {
1240
1333
  return h(
@@ -1251,6 +1344,80 @@ var IrisAdminLayout = defineComponent({
1251
1344
  slots.default?.({ activeKey: activeKey.value }) ?? []
1252
1345
  );
1253
1346
  }
1347
+ if (props.mode === "horizontal") {
1348
+ const justifyContent = props.menuAlign === "center" ? "center" : props.menuAlign === "end" ? "flex-end" : "flex-start";
1349
+ return h(
1350
+ "div",
1351
+ {
1352
+ ...attrs,
1353
+ "data-iris-admin-layout": "",
1354
+ "data-mode": "horizontal",
1355
+ style: {
1356
+ height: props.contentHeight === "viewport" ? "100vh" : "auto",
1357
+ minHeight: "100vh",
1358
+ ...attrs.style ?? {}
1359
+ }
1360
+ },
1361
+ [
1362
+ h(
1363
+ IrisHeaderLayout,
1364
+ { sticky: props.stickyHeader },
1365
+ {
1366
+ header: () => h("div", { "data-iris-admin-header": "" }, [
1367
+ h(
1368
+ "div",
1369
+ {
1370
+ "data-iris-admin-headerbar": "",
1371
+ style: {
1372
+ display: "flex",
1373
+ alignItems: "center",
1374
+ gap: "12px",
1375
+ minHeight: "52px",
1376
+ padding: "0 16px",
1377
+ background: "var(--iris-background)"
1378
+ }
1379
+ },
1380
+ [
1381
+ renderLogo({ collapsed: false }),
1382
+ h(
1383
+ "div",
1384
+ {
1385
+ "data-iris-admin-topnav": "",
1386
+ style: {
1387
+ display: "flex",
1388
+ flex: "1",
1389
+ minWidth: "0",
1390
+ justifyContent
1391
+ }
1392
+ },
1393
+ [
1394
+ h(IrisNavMenu, {
1395
+ items: props.menus,
1396
+ activeKey: activeKey.value,
1397
+ orientation: "horizontal",
1398
+ onSelect
1399
+ })
1400
+ ]
1401
+ ),
1402
+ slots.toolbar ? h(
1403
+ "div",
1404
+ {
1405
+ "data-iris-admin-toolbar": "",
1406
+ style: { display: "flex", alignItems: "center", gap: "8px" }
1407
+ },
1408
+ slots.toolbar()
1409
+ ) : null
1410
+ ]
1411
+ ),
1412
+ renderTabs()
1413
+ ]),
1414
+ default: () => renderContent(true),
1415
+ ...slots.footer ? { footer: () => slots.footer() } : {}
1416
+ }
1417
+ )
1418
+ ]
1419
+ );
1420
+ }
1254
1421
  return h(
1255
1422
  IrisSidebarLayout,
1256
1423
  {
@@ -1297,12 +1464,9 @@ var IrisAdminLayout = defineComponent({
1297
1464
  ),
1298
1465
  default: () => h(
1299
1466
  IrisHeaderLayout,
1300
- { sticky: true },
1467
+ { sticky: props.stickyHeader },
1301
1468
  {
1302
- header: () => h("div", { "data-iris-admin-header": "" }, [
1303
- renderHeaderBar(),
1304
- props.tabs ? h(IrisAdminTabs, { nav: props.tabs }) : null
1305
- ]),
1469
+ header: () => h("div", { "data-iris-admin-header": "" }, [renderHeaderBar(), renderTabs()]),
1306
1470
  default: () => renderContent(),
1307
1471
  ...slots.footer ? { footer: () => slots.footer() } : {}
1308
1472
  }
@@ -1312,7 +1476,25 @@ var IrisAdminLayout = defineComponent({
1312
1476
  };
1313
1477
  }
1314
1478
  });
1479
+ function useAdminPreferences(preferences, hydrate = true) {
1480
+ const state = ref(preferences.getState());
1481
+ const unsubscribe = preferences.subscribe((next) => {
1482
+ state.value = next;
1483
+ });
1484
+ onMounted(() => {
1485
+ if (hydrate) void preferences.hydrate();
1486
+ });
1487
+ onBeforeUnmount(unsubscribe);
1488
+ return {
1489
+ state: computed(() => state.value),
1490
+ set: preferences.set,
1491
+ patch: preferences.patch,
1492
+ reset: preferences.reset,
1493
+ hydrate: preferences.hydrate,
1494
+ flush: preferences.flush
1495
+ };
1496
+ }
1315
1497
 
1316
- export { DropdownContextKey, IrisAdminBreadcrumb, IrisAdminLayout, IrisAdminTabs, IrisBreadcrumb, IrisBreadcrumbItem, IrisDropdown, IrisDropdownItem, IrisDropdownMenu, IrisDropdownSeparator, IrisDropdownTrigger, IrisIcon, IrisNavMenu, useAdminShell, useTabsNav };
1317
- //# sourceMappingURL=chunk-FJBYAIL4.js.map
1318
- //# sourceMappingURL=chunk-FJBYAIL4.js.map
1498
+ export { DropdownContextKey, IrisAdminBreadcrumb, IrisAdminLayout, IrisAdminTabs, IrisBreadcrumb, IrisBreadcrumbItem, IrisDropdown, IrisDropdownItem, IrisDropdownMenu, IrisDropdownSeparator, IrisDropdownTrigger, IrisIcon, IrisNavMenu, useAdminPreferences, useAdminShell, useTabsNav };
1499
+ //# sourceMappingURL=chunk-4V4CT3Z4.js.map
1500
+ //# sourceMappingURL=chunk-4V4CT3Z4.js.map