@iris-ui-kit/vue 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  var vue = require('vue');
4
+ var core = require('@iris-ui-kit/core');
4
5
  var theme = require('@iris-ui-kit/theme');
5
6
  var skins = require('@iris-ui-kit/skins');
6
- var core = require('@iris-ui-kit/core');
7
7
  var icons = require('@iris-ui-kit/icons');
8
8
  var dom = require('@floating-ui/dom');
9
9
  var undo = require('@iris-ui-kit/core/undo');
@@ -20,6 +20,41 @@ function useStoreSelector(store2, selector, equals) {
20
20
  vue.onScopeDispose(store2.subscribeWith(selector, (v) => slice.value = v, equals));
21
21
  return slice;
22
22
  }
23
+ function useReconnectingSource(connect, handlers, options) {
24
+ const status = vue.ref("idle");
25
+ const handlersRef = { current: handlers };
26
+ handlersRef.current = handlers;
27
+ const source = core.createReconnectingSource(
28
+ connect,
29
+ {
30
+ onMessage: (data) => handlersRef.current.onMessage?.(data),
31
+ onOpen: () => handlersRef.current.onOpen?.(),
32
+ onError: (err) => handlersRef.current.onError?.(err),
33
+ onClose: () => handlersRef.current.onClose?.(),
34
+ onStatus: (s) => {
35
+ status.value = s;
36
+ }
37
+ },
38
+ options
39
+ );
40
+ source.open();
41
+ vue.onUnmounted(() => source.close());
42
+ return status;
43
+ }
44
+ function useResilientFetcher(options) {
45
+ const rf = core.createResilientFetcher(options);
46
+ vue.onUnmounted(() => {
47
+ rf.cache.clear();
48
+ });
49
+ return rf;
50
+ }
51
+ function useDisposableScope() {
52
+ const scope = vue.ref(core.createDisposableScope());
53
+ vue.onUnmounted(() => {
54
+ scope.value.destroy();
55
+ });
56
+ return scope;
57
+ }
23
58
  var IrisThemeKey = /* @__PURE__ */ Symbol("IrisTheme");
24
59
  var ThemeProvider = vue.defineComponent({
25
60
  name: "IrisThemeProvider",
@@ -812,6 +847,10 @@ var IrisNavMenu = vue.defineComponent({
812
847
  defaultExpandedKeys: { type: Array, default: void 0 },
813
848
  /** Icon-only rail (top-level items only). */
814
849
  collapsed: { type: Boolean, default: false },
850
+ orientation: {
851
+ type: String,
852
+ default: "vertical"
853
+ },
815
854
  ariaLabel: { type: String, default: void 0 }
816
855
  },
817
856
  emits: {
@@ -867,7 +906,7 @@ var IrisNavMenu = vue.defineComponent({
867
906
  display: "flex",
868
907
  alignItems: "center",
869
908
  gap: "10px",
870
- width: "100%",
909
+ width: props.orientation === "horizontal" && opts.depth === 0 ? "auto" : "100%",
871
910
  boxSizing: "border-box",
872
911
  border: "none",
873
912
  borderRadius: "var(--iris-radius-md, 6px)",
@@ -879,7 +918,8 @@ var IrisNavMenu = vue.defineComponent({
879
918
  textAlign: "start",
880
919
  cursor: opts.disabled ? "not-allowed" : "pointer",
881
920
  opacity: opts.disabled ? "0.5" : "1",
882
- padding: props.collapsed ? "10px" : `8px 10px 8px ${12 + opts.depth * 16}px`,
921
+ padding: props.collapsed ? "10px" : "8px 10px",
922
+ paddingInlineStart: props.collapsed ? "10px" : `${12 + opts.depth * 16}px`,
883
923
  justifyContent: props.collapsed ? "center" : "flex-start"
884
924
  };
885
925
  };
@@ -973,16 +1013,40 @@ var IrisNavMenu = vue.defineComponent({
973
1013
  }) : null
974
1014
  ]
975
1015
  );
1016
+ const groupStyle = props.orientation === "horizontal" && depth === 0 ? { position: "relative" } : void 0;
976
1017
  if (!branch || !open)
977
- return vue.h("div", { key: node.key, "data-iris-nav-group": branch ? "" : void 0 }, [row]);
978
- return vue.h("div", { key: node.key, "data-iris-nav-group": "", "data-open": "true" }, [
979
- row,
980
- vue.h(
1018
+ return vue.h(
981
1019
  "div",
982
- { "data-iris-nav-children": "", role: "group" },
983
- (node.children ?? []).map((child) => renderItem(child, depth + 1))
984
- )
985
- ]);
1020
+ { key: node.key, "data-iris-nav-group": branch ? "" : void 0, style: groupStyle },
1021
+ [row]
1022
+ );
1023
+ return vue.h(
1024
+ "div",
1025
+ { key: node.key, "data-iris-nav-group": "", "data-open": "true", style: groupStyle },
1026
+ [
1027
+ row,
1028
+ vue.h(
1029
+ "div",
1030
+ {
1031
+ "data-iris-nav-children": "",
1032
+ role: "group",
1033
+ style: props.orientation === "horizontal" && depth === 0 ? {
1034
+ position: "absolute",
1035
+ insetBlockStart: "calc(100% + 4px)",
1036
+ insetInlineStart: "0",
1037
+ zIndex: "60",
1038
+ minWidth: "220px",
1039
+ padding: "6px",
1040
+ border: "1px solid var(--iris-border)",
1041
+ borderRadius: "var(--iris-radius-md, 6px)",
1042
+ background: "var(--iris-surface)",
1043
+ boxShadow: "var(--iris-shadow-md)"
1044
+ } : void 0
1045
+ },
1046
+ (node.children ?? []).map((child) => renderItem(child, depth + 1))
1047
+ )
1048
+ ]
1049
+ );
986
1050
  };
987
1051
  const onKeydown = (e) => {
988
1052
  const root = e.currentTarget;
@@ -1035,11 +1099,13 @@ var IrisNavMenu = vue.defineComponent({
1035
1099
  ...attrs,
1036
1100
  "data-iris-nav-menu": "",
1037
1101
  "data-collapsed": props.collapsed ? "true" : void 0,
1102
+ "data-orientation": props.orientation,
1038
1103
  "aria-label": props.ariaLabel ?? t("admin.nav"),
1039
1104
  onKeydown,
1040
1105
  style: {
1041
1106
  display: "flex",
1042
- flexDirection: "column",
1107
+ flexDirection: props.orientation === "horizontal" ? "row" : "column",
1108
+ alignItems: props.orientation === "horizontal" ? "center" : void 0,
1043
1109
  gap: "2px",
1044
1110
  ...attrs.style ?? {}
1045
1111
  }
@@ -1229,6 +1295,7 @@ function useTabsNav(nav) {
1229
1295
  closeRight: nav.closeRight,
1230
1296
  refresh: nav.refresh,
1231
1297
  setPinned: nav.setPinned,
1298
+ move: nav.move,
1232
1299
  cacheKey: nav.cacheKey
1233
1300
  };
1234
1301
  }
@@ -1785,6 +1852,168 @@ var IrisDropdownSeparator = vue.defineComponent({
1785
1852
  });
1786
1853
  }
1787
1854
  });
1855
+ var SORTABLE_ITEM_ATTR = "data-iris-sortable-item";
1856
+ var IrisSortable = vue.defineComponent({
1857
+ name: "IrisSortable",
1858
+ inheritAttrs: false,
1859
+ props: {
1860
+ /** The ordered items. Used to detect which item is at which position. */
1861
+ items: {
1862
+ type: Array,
1863
+ required: true
1864
+ },
1865
+ /** Called when the user drops an item in a new position. */
1866
+ onReorder: {
1867
+ type: Function,
1868
+ default: void 0
1869
+ },
1870
+ /** Optional item key getter. Defaults to `String(index)`. */
1871
+ getKey: {
1872
+ type: Function,
1873
+ default: void 0
1874
+ },
1875
+ disabled: {
1876
+ type: Boolean,
1877
+ default: false
1878
+ },
1879
+ orientation: {
1880
+ type: String,
1881
+ default: "vertical"
1882
+ },
1883
+ class: {
1884
+ type: String,
1885
+ default: void 0
1886
+ },
1887
+ style: {
1888
+ type: Object,
1889
+ default: void 0
1890
+ }
1891
+ },
1892
+ emits: {
1893
+ reorder: (_next) => true
1894
+ },
1895
+ setup(props, { slots, attrs, emit }) {
1896
+ const containerRef = vue.ref(null);
1897
+ const sortable = core.createSortable();
1898
+ const activeKey = vue.ref(null);
1899
+ const unsub = sortable.subscribe((state) => {
1900
+ activeKey.value = state.activeId;
1901
+ });
1902
+ vue.onBeforeUnmount(unsub);
1903
+ const indexOf = (key) => {
1904
+ const container = containerRef.value;
1905
+ if (!container) return -1;
1906
+ return Array.from(
1907
+ container.querySelectorAll(`[${SORTABLE_ITEM_ATTR}]`)
1908
+ ).findIndex((el) => el.getAttribute(SORTABLE_ITEM_ATTR) === key);
1909
+ };
1910
+ const onPointerDown = (e) => {
1911
+ if (props.disabled) return;
1912
+ const target = e.target.closest(`[${SORTABLE_ITEM_ATTR}]`);
1913
+ if (!target) return;
1914
+ const container = containerRef.value;
1915
+ if (!container) return;
1916
+ const key = target.getAttribute(SORTABLE_ITEM_ATTR) ?? "";
1917
+ const index = indexOf(key);
1918
+ if (index < 0) return;
1919
+ sortable.press(key, e.clientX, e.clientY);
1920
+ };
1921
+ const onPointerMove = (e) => {
1922
+ if (!sortable.isPending() && sortable.getState().activeId === null) return;
1923
+ const items = containerRef.value?.querySelectorAll(`[${SORTABLE_ITEM_ATTR}]`);
1924
+ const rects = Array.from(items ?? []).map((el) => {
1925
+ const rect = el.getBoundingClientRect();
1926
+ return {
1927
+ id: el.getAttribute(SORTABLE_ITEM_ATTR) ?? "",
1928
+ left: rect.left,
1929
+ top: rect.top,
1930
+ width: rect.width,
1931
+ height: rect.height
1932
+ };
1933
+ });
1934
+ sortable.tryStart(e.clientX, e.clientY);
1935
+ if (sortable.getState().activeId !== null) {
1936
+ sortable.moveOver({ x: e.clientX, y: e.clientY }, rects);
1937
+ }
1938
+ };
1939
+ const onPointerUp = () => {
1940
+ const state = sortable.getState();
1941
+ if (state.activeId === null) {
1942
+ sortable.cancel();
1943
+ return;
1944
+ }
1945
+ const result = sortable.end();
1946
+ if (result.activeId && result.overId && result.activeId !== result.overId) {
1947
+ const from = indexOf(result.activeId);
1948
+ const to = indexOf(result.overId);
1949
+ if (from >= 0 && to >= 0) {
1950
+ const next = [...props.items];
1951
+ const [moved] = next.splice(from, 1);
1952
+ next.splice(to, 0, moved);
1953
+ if (props.onReorder) {
1954
+ props.onReorder(next);
1955
+ }
1956
+ emit("reorder", next);
1957
+ }
1958
+ }
1959
+ };
1960
+ const resolveKey = (item, index) => props.getKey ? props.getKey(item, index) : String(index);
1961
+ return () => {
1962
+ const children = [];
1963
+ const defaultSlots = slots.default?.();
1964
+ if (defaultSlots) {
1965
+ const itemsArray = props.items;
1966
+ defaultSlots.forEach((child, index) => {
1967
+ const item = itemsArray[index];
1968
+ const key = resolveKey(item, index);
1969
+ const isDragging = key === activeKey.value;
1970
+ children.push(
1971
+ vue.h(
1972
+ "div",
1973
+ {
1974
+ key,
1975
+ [SORTABLE_ITEM_ATTR]: key,
1976
+ "data-iris-sortable-dragging": isDragging ? "" : void 0,
1977
+ style: {
1978
+ transition: isDragging ? "none" : "transform 150ms ease",
1979
+ opacity: isDragging ? 0.4 : 1,
1980
+ position: "relative",
1981
+ zIndex: isDragging ? 100 : void 0
1982
+ }
1983
+ },
1984
+ [child]
1985
+ )
1986
+ );
1987
+ });
1988
+ }
1989
+ return vue.h(
1990
+ "div",
1991
+ {
1992
+ ...attrs,
1993
+ ref: (el) => {
1994
+ containerRef.value = el ?? null;
1995
+ },
1996
+ "data-iris-sortable": "",
1997
+ "data-state": activeKey.value ? "dragging" : "idle",
1998
+ class: props.class,
1999
+ style: {
2000
+ display: "flex",
2001
+ flexDirection: props.orientation === "horizontal" ? "row" : "column",
2002
+ gap: "var(--iris-gap-sm, 4px)",
2003
+ opacity: props.disabled ? 0.6 : 1,
2004
+ userSelect: activeKey.value ? "none" : void 0,
2005
+ ...props.style ?? {}
2006
+ },
2007
+ onPointerdown: onPointerDown,
2008
+ onPointermove: onPointerMove,
2009
+ onPointerup: onPointerUp,
2010
+ onPointerleave: onPointerUp
2011
+ },
2012
+ children
2013
+ );
2014
+ };
2015
+ }
2016
+ });
1788
2017
 
1789
2018
  // src/admin/AdminTabs.ts
1790
2019
  var IrisAdminTabs = vue.defineComponent({
@@ -1792,12 +2021,14 @@ var IrisAdminTabs = vue.defineComponent({
1792
2021
  inheritAttrs: false,
1793
2022
  props: {
1794
2023
  /** Shared tabs store (from `createTabsNav`). */
1795
- nav: { type: Object, required: true }
2024
+ nav: { type: Object, required: true },
2025
+ reorderable: { type: Boolean, default: true }
1796
2026
  },
1797
2027
  emits: {
1798
2028
  change: (_key) => true,
1799
2029
  close: (_key) => true,
1800
- refresh: (_key) => true
2030
+ refresh: (_key) => true,
2031
+ reorder: (_tabs) => true
1801
2032
  },
1802
2033
  setup(props, { emit, attrs }) {
1803
2034
  const { t: tr } = useI18n();
@@ -1814,6 +2045,10 @@ var IrisAdminTabs = vue.defineComponent({
1814
2045
  props.nav.refresh(key);
1815
2046
  emit("refresh", key);
1816
2047
  };
2048
+ const reorder = (tabs) => {
2049
+ tabs.forEach((tab, index) => props.nav.move(tab.key, index));
2050
+ emit("reorder", tabs);
2051
+ };
1817
2052
  const focusTab = (root, key) => {
1818
2053
  if (!root || !key) return;
1819
2054
  const labels = root.querySelectorAll("[data-iris-tab-label]");
@@ -1965,6 +2200,8 @@ var IrisAdminTabs = vue.defineComponent({
1965
2200
  action(tr("admin.refresh"), () => refresh(key)),
1966
2201
  action(tr("admin.close"), () => close(key)),
1967
2202
  vue.h(IrisDropdownSeparator),
2203
+ action(tr("admin.closeLeft"), () => props.nav.closeLeft(key)),
2204
+ action(tr("admin.closeRight"), () => props.nav.closeRight(key)),
1968
2205
  action(tr("admin.closeOthers"), () => props.nav.closeOthers(key)),
1969
2206
  action(tr("admin.closeAll"), () => props.nav.closeAll())
1970
2207
  ];
@@ -1996,14 +2233,28 @@ var IrisAdminTabs = vue.defineComponent({
1996
2233
  "aria-label": tr("admin.openPages"),
1997
2234
  onKeydown: onTablistKeydown,
1998
2235
  style: {
1999
- display: "flex",
2000
- alignItems: "center",
2001
- gap: "6px",
2002
2236
  overflowX: "auto",
2003
2237
  flex: "1"
2004
2238
  }
2005
2239
  },
2006
- t.tabs.value.map((tab) => chip(tab))
2240
+ [
2241
+ vue.h(
2242
+ IrisSortable,
2243
+ {
2244
+ items: t.tabs.value,
2245
+ getKey: (item) => item.key,
2246
+ onReorder: (items) => reorder(items),
2247
+ disabled: !props.reorderable,
2248
+ orientation: "horizontal",
2249
+ style: {
2250
+ alignItems: "center",
2251
+ gap: "6px",
2252
+ width: "max-content"
2253
+ }
2254
+ },
2255
+ { default: () => t.tabs.value.map((tab) => chip(tab)) }
2256
+ )
2257
+ ]
2007
2258
  ),
2008
2259
  actionsMenu()
2009
2260
  ]
@@ -2052,6 +2303,8 @@ var IrisAdminLayout = vue.defineComponent({
2052
2303
  menus: { type: Array, required: true },
2053
2304
  /** Active page key (v-model:activeKey). */
2054
2305
  activeKey: { type: String, default: void 0 },
2306
+ /** Initial active page key when `activeKey` is uncontrolled. */
2307
+ defaultActiveKey: { type: String, default: void 0 },
2055
2308
  /** Sidebar collapsed (v-model:collapsed); undefined = uncontrolled. */
2056
2309
  collapsed: { type: Boolean, default: void 0 },
2057
2310
  defaultCollapsed: { type: Boolean, default: false },
@@ -2060,7 +2313,16 @@ var IrisAdminLayout = vue.defineComponent({
2060
2313
  appTitle: { type: String, default: "Iris Admin" },
2061
2314
  /** Optional shared tabs store; when present the tab bar is rendered. */
2062
2315
  tabs: { type: Object, default: void 0 },
2316
+ showTabs: { type: Boolean, default: true },
2063
2317
  showBreadcrumb: { type: Boolean, default: true },
2318
+ stickyHeader: { type: Boolean, default: true },
2319
+ stickyTabs: { type: Boolean, default: true },
2320
+ menuAlign: { type: String, default: "start" },
2321
+ contentWidth: { type: String, default: "fluid" },
2322
+ contentHeight: {
2323
+ type: String,
2324
+ default: "viewport"
2325
+ },
2064
2326
  sidebarWidth: { type: [Number, String], default: 240 },
2065
2327
  collapsedWidth: { type: [Number, String], default: 64 }
2066
2328
  },
@@ -2079,6 +2341,7 @@ var IrisAdminLayout = vue.defineComponent({
2079
2341
  } = useAdminShell({
2080
2342
  menus: () => props.menus,
2081
2343
  activeKey: () => props.activeKey,
2344
+ defaultActiveKey: props.defaultActiveKey,
2082
2345
  tabs: props.tabs,
2083
2346
  onActiveKeyChange: (key) => emit("update:activeKey", key),
2084
2347
  onSelect: (key, node) => emit("select", key, node)
@@ -2197,11 +2460,37 @@ var IrisAdminLayout = vue.defineComponent({
2197
2460
  ) : null
2198
2461
  ]
2199
2462
  );
2200
- const renderContent = () => vue.h(
2463
+ const renderContent = (horizontal = false) => vue.h(
2201
2464
  "div",
2202
- { "data-iris-admin-content": "", style: { padding: "16px" } },
2203
- slots.default?.({ activeKey: activeKey.value }) ?? []
2465
+ {
2466
+ "data-iris-admin-content": "",
2467
+ "data-width": props.contentWidth,
2468
+ style: {
2469
+ boxSizing: "border-box",
2470
+ width: "100%",
2471
+ maxWidth: props.contentWidth === "centered" ? "72rem" : void 0,
2472
+ marginInline: props.contentWidth === "centered" ? "auto" : void 0,
2473
+ padding: "16px"
2474
+ }
2475
+ },
2476
+ [
2477
+ horizontal && props.showBreadcrumb ? vue.h(IrisAdminBreadcrumb, { trail: trail.value, hideSingle: false, onSelect }) : null,
2478
+ ...slots.default?.({ activeKey: activeKey.value }) ?? []
2479
+ ]
2204
2480
  );
2481
+ const renderTabs = () => props.tabs && props.showTabs ? vue.h(
2482
+ "div",
2483
+ {
2484
+ "data-iris-admin-tabs-region": "",
2485
+ "data-sticky": props.stickyTabs ? "true" : void 0,
2486
+ style: {
2487
+ position: props.stickyTabs && !props.stickyHeader ? "sticky" : "relative",
2488
+ top: "0",
2489
+ zIndex: "49"
2490
+ }
2491
+ },
2492
+ [vue.h(IrisAdminTabs, { nav: props.tabs })]
2493
+ ) : null;
2205
2494
  return () => {
2206
2495
  if (props.mode === "full-content") {
2207
2496
  return vue.h(
@@ -2218,32 +2507,106 @@ var IrisAdminLayout = vue.defineComponent({
2218
2507
  slots.default?.({ activeKey: activeKey.value }) ?? []
2219
2508
  );
2220
2509
  }
2221
- return vue.h(
2222
- IrisSidebarLayout,
2223
- {
2224
- ...attrs,
2225
- collapsed: collapsed.value,
2226
- width: props.sidebarWidth,
2227
- collapsedWidth: props.collapsedWidth,
2228
- "onUpdate:collapsed": setCollapsed,
2229
- "data-iris-admin-layout": "",
2230
- "data-mode": "sidebar",
2231
- style: {
2232
- height: "100vh",
2233
- ...attrs.style ?? {}
2234
- }
2235
- },
2236
- {
2237
- sidebar: (state) => vue.h(
2238
- "div",
2239
- {
2240
- "data-iris-admin-sidebar": "",
2241
- style: {
2242
- display: "flex",
2243
- flexDirection: "column",
2244
- height: "100%",
2245
- borderInlineEnd: "1px solid var(--iris-border)",
2246
- background: "var(--iris-surface)"
2510
+ if (props.mode === "horizontal") {
2511
+ const justifyContent = props.menuAlign === "center" ? "center" : props.menuAlign === "end" ? "flex-end" : "flex-start";
2512
+ return vue.h(
2513
+ "div",
2514
+ {
2515
+ ...attrs,
2516
+ "data-iris-admin-layout": "",
2517
+ "data-mode": "horizontal",
2518
+ style: {
2519
+ height: props.contentHeight === "viewport" ? "100vh" : "auto",
2520
+ minHeight: "100vh",
2521
+ ...attrs.style ?? {}
2522
+ }
2523
+ },
2524
+ [
2525
+ vue.h(
2526
+ IrisHeaderLayout,
2527
+ { sticky: props.stickyHeader },
2528
+ {
2529
+ header: () => vue.h("div", { "data-iris-admin-header": "" }, [
2530
+ vue.h(
2531
+ "div",
2532
+ {
2533
+ "data-iris-admin-headerbar": "",
2534
+ style: {
2535
+ display: "flex",
2536
+ alignItems: "center",
2537
+ gap: "12px",
2538
+ minHeight: "52px",
2539
+ padding: "0 16px",
2540
+ background: "var(--iris-background)"
2541
+ }
2542
+ },
2543
+ [
2544
+ renderLogo({ collapsed: false }),
2545
+ vue.h(
2546
+ "div",
2547
+ {
2548
+ "data-iris-admin-topnav": "",
2549
+ style: {
2550
+ display: "flex",
2551
+ flex: "1",
2552
+ minWidth: "0",
2553
+ justifyContent
2554
+ }
2555
+ },
2556
+ [
2557
+ vue.h(IrisNavMenu, {
2558
+ items: props.menus,
2559
+ activeKey: activeKey.value,
2560
+ orientation: "horizontal",
2561
+ onSelect
2562
+ })
2563
+ ]
2564
+ ),
2565
+ slots.toolbar ? vue.h(
2566
+ "div",
2567
+ {
2568
+ "data-iris-admin-toolbar": "",
2569
+ style: { display: "flex", alignItems: "center", gap: "8px" }
2570
+ },
2571
+ slots.toolbar()
2572
+ ) : null
2573
+ ]
2574
+ ),
2575
+ renderTabs()
2576
+ ]),
2577
+ default: () => renderContent(true),
2578
+ ...slots.footer ? { footer: () => slots.footer() } : {}
2579
+ }
2580
+ )
2581
+ ]
2582
+ );
2583
+ }
2584
+ return vue.h(
2585
+ IrisSidebarLayout,
2586
+ {
2587
+ ...attrs,
2588
+ collapsed: collapsed.value,
2589
+ width: props.sidebarWidth,
2590
+ collapsedWidth: props.collapsedWidth,
2591
+ "onUpdate:collapsed": setCollapsed,
2592
+ "data-iris-admin-layout": "",
2593
+ "data-mode": "sidebar",
2594
+ style: {
2595
+ height: "100vh",
2596
+ ...attrs.style ?? {}
2597
+ }
2598
+ },
2599
+ {
2600
+ sidebar: (state) => vue.h(
2601
+ "div",
2602
+ {
2603
+ "data-iris-admin-sidebar": "",
2604
+ style: {
2605
+ display: "flex",
2606
+ flexDirection: "column",
2607
+ height: "100%",
2608
+ borderInlineEnd: "1px solid var(--iris-border)",
2609
+ background: "var(--iris-surface)"
2247
2610
  }
2248
2611
  },
2249
2612
  [
@@ -2264,12 +2627,9 @@ var IrisAdminLayout = vue.defineComponent({
2264
2627
  ),
2265
2628
  default: () => vue.h(
2266
2629
  IrisHeaderLayout,
2267
- { sticky: true },
2630
+ { sticky: props.stickyHeader },
2268
2631
  {
2269
- header: () => vue.h("div", { "data-iris-admin-header": "" }, [
2270
- renderHeaderBar(),
2271
- props.tabs ? vue.h(IrisAdminTabs, { nav: props.tabs }) : null
2272
- ]),
2632
+ header: () => vue.h("div", { "data-iris-admin-header": "" }, [renderHeaderBar(), renderTabs()]),
2273
2633
  default: () => renderContent(),
2274
2634
  ...slots.footer ? { footer: () => slots.footer() } : {}
2275
2635
  }
@@ -2279,6 +2639,24 @@ var IrisAdminLayout = vue.defineComponent({
2279
2639
  };
2280
2640
  }
2281
2641
  });
2642
+ function useAdminPreferences(preferences, hydrate = true) {
2643
+ const state = vue.ref(preferences.getState());
2644
+ const unsubscribe = preferences.subscribe((next) => {
2645
+ state.value = next;
2646
+ });
2647
+ vue.onMounted(() => {
2648
+ if (hydrate) void preferences.hydrate();
2649
+ });
2650
+ vue.onBeforeUnmount(unsubscribe);
2651
+ return {
2652
+ state: vue.computed(() => state.value),
2653
+ set: preferences.set,
2654
+ patch: preferences.patch,
2655
+ reset: preferences.reset,
2656
+ hydrate: preferences.hydrate,
2657
+ flush: preferences.flush
2658
+ };
2659
+ }
2282
2660
  function useUndoStack(options) {
2283
2661
  const stack = undo.createUndoStack(options);
2284
2662
  const state = vue.shallowRef({
@@ -2840,39 +3218,37 @@ var IrisPopoverContent = vue.defineComponent({
2840
3218
  target?.focus();
2841
3219
  }
2842
3220
  });
2843
- const contentVNode = vue.computed(
2844
- () => vue.h(
2845
- "div",
2846
- {
2847
- ...attrs,
2848
- ref: (el) => {
2849
- innerRef.value = el ?? null;
2850
- },
2851
- id: ctx.contentId,
2852
- role: "dialog",
2853
- tabindex: -1,
2854
- "data-state": ctx.open.value ? "open" : "closed",
2855
- "data-placement": ctx.placement,
2856
- style: {
2857
- ...floatingStyles.value,
2858
- background: "var(--iris-surface)",
2859
- color: "var(--iris-foreground)",
2860
- border: "1px solid var(--iris-border)",
2861
- borderRadius: "var(--iris-radius-md)",
2862
- padding: "var(--iris-padding-md)",
2863
- boxShadow: "0 8px 24px -8px rgba(0, 0, 0, 0.16), 0 4px 8px -2px rgba(0, 0, 0, 0.08)",
2864
- fontSize: "14px",
2865
- zIndex: "1000",
2866
- outline: "none",
2867
- ...attrs.style ?? {}
2868
- }
3221
+ const renderContent = () => vue.h(
3222
+ "div",
3223
+ {
3224
+ ...attrs,
3225
+ ref: (el) => {
3226
+ innerRef.value = el ?? null;
2869
3227
  },
2870
- slots.default?.()
2871
- )
3228
+ id: ctx.contentId,
3229
+ role: "dialog",
3230
+ tabindex: -1,
3231
+ "data-state": ctx.open.value ? "open" : "closed",
3232
+ "data-placement": ctx.placement,
3233
+ style: {
3234
+ ...floatingStyles.value,
3235
+ background: "var(--iris-surface)",
3236
+ color: "var(--iris-foreground)",
3237
+ border: "1px solid var(--iris-border)",
3238
+ borderRadius: "var(--iris-radius-md)",
3239
+ padding: "var(--iris-padding-md)",
3240
+ boxShadow: "0 8px 24px -8px rgba(0, 0, 0, 0.16), 0 4px 8px -2px rgba(0, 0, 0, 0.08)",
3241
+ fontSize: "14px",
3242
+ zIndex: "1000",
3243
+ outline: "none",
3244
+ ...attrs.style ?? {}
3245
+ }
3246
+ },
3247
+ slots.default?.()
2872
3248
  );
2873
3249
  return () => {
2874
3250
  if (!ctx.open.value) return null;
2875
- const node = contentVNode.value;
3251
+ const node = renderContent();
2876
3252
  if (props.teleport === false) return node;
2877
3253
  return vue.h(vue.Teleport, { to: props.teleport }, [node]);
2878
3254
  };
@@ -5663,6 +6039,7 @@ var IrisSelect = vue.defineComponent({
5663
6039
  props: {
5664
6040
  items: { type: Array, required: true },
5665
6041
  modelValue: { type: null },
6042
+ defaultValue: { type: null, default: void 0 },
5666
6043
  placeholder: { type: String, default: void 0 },
5667
6044
  size: { type: String, default: "md" },
5668
6045
  disabled: { type: Boolean, default: false },
@@ -5679,13 +6056,17 @@ var IrisSelect = vue.defineComponent({
5679
6056
  }
5680
6057
  },
5681
6058
  emits: {
5682
- "update:modelValue": (_value) => true
6059
+ "update:modelValue": (_value) => true,
6060
+ valueChange: (_value) => true
5683
6061
  },
5684
6062
  setup(props, { slots, attrs, emit }) {
5685
6063
  const { t } = useI18n();
5686
6064
  const open = vue.ref(false);
6065
+ const internalValue = vue.ref(props.defaultValue);
6066
+ const controlled = vue.computed(() => props.modelValue !== void 0);
6067
+ const currentValue = vue.computed(() => controlled.value ? props.modelValue : internalValue.value);
5687
6068
  const selectedItem = vue.computed(
5688
- () => props.items.find((item) => item.value === props.modelValue) ?? null
6069
+ () => props.items.find((item) => item.value === currentValue.value) ?? null
5689
6070
  );
5690
6071
  const triggerLabel = vue.computed(() => {
5691
6072
  const item = selectedItem.value;
@@ -5693,7 +6074,9 @@ var IrisSelect = vue.defineComponent({
5693
6074
  return item.label ?? String(item.value);
5694
6075
  });
5695
6076
  const onSelect = (item) => {
6077
+ if (!controlled.value) internalValue.value = item.value;
5696
6078
  emit("update:modelValue", item.value);
6079
+ emit("valueChange", item.value);
5697
6080
  open.value = false;
5698
6081
  };
5699
6082
  const sizeStyles = vue.computed(() => {
@@ -5759,7 +6142,7 @@ var IrisSelect = vue.defineComponent({
5759
6142
  default: () => [
5760
6143
  vue.h(IrisPopoverTrigger, { asChild: true }, () => [
5761
6144
  slots.trigger ? slots.trigger({
5762
- value: props.modelValue,
6145
+ value: currentValue.value,
5763
6146
  label: triggerLabel.value,
5764
6147
  open: open.value
5765
6148
  }) : vue.h(
@@ -5796,8 +6179,7 @@ var IrisSelect = vue.defineComponent({
5796
6179
  },
5797
6180
  () => vue.h(IrisList, {
5798
6181
  items: props.items,
5799
- modelValue: props.modelValue,
5800
- "onUpdate:modelValue": (v) => emit("update:modelValue", v),
6182
+ modelValue: currentValue.value,
5801
6183
  onSelect,
5802
6184
  ariaLabel: t("select.options")
5803
6185
  })
@@ -6257,8 +6639,8 @@ var IrisSkeleton = vue.defineComponent({
6257
6639
  vue.onMounted(installSkeletonStyles);
6258
6640
  const style = vue.computed(() => {
6259
6641
  const w = props.width !== void 0 ? toCss(props.width) : defaultWidth(props.shape);
6260
- const h122 = props.height !== void 0 ? toCss(props.height) : defaultHeight(props.shape, props.width);
6261
- return { width: w, height: h122 };
6642
+ const h123 = props.height !== void 0 ? toCss(props.height) : defaultHeight(props.shape, props.width);
6643
+ return { width: w, height: h123 };
6262
6644
  });
6263
6645
  return () => vue.h("div", {
6264
6646
  ...attrs,
@@ -8722,10 +9104,91 @@ var IrisVirtualScroll = vue.defineComponent({
8722
9104
  };
8723
9105
  }
8724
9106
  });
9107
+
9108
+ // src/primitives/table/controlProps.ts
9109
+ var tableControlProps = {
9110
+ selectable: {
9111
+ type: String,
9112
+ default: "none"
9113
+ },
9114
+ selection: {
9115
+ type: Array,
9116
+ default: void 0
9117
+ },
9118
+ defaultSelection: {
9119
+ type: Array,
9120
+ default: void 0
9121
+ },
9122
+ sort: {
9123
+ type: Object,
9124
+ default: void 0
9125
+ },
9126
+ defaultSort: {
9127
+ type: Object,
9128
+ default: void 0
9129
+ }
9130
+ };
8725
9131
  function getCellValue(row, column) {
8726
9132
  const key = column.dataIndex ?? column.key;
8727
9133
  return row[key];
8728
9134
  }
9135
+
9136
+ // src/primitives/table/useTableSort.ts
9137
+ function useTableSort(data, options) {
9138
+ const sortProp = vue.computed(() => options.sort === void 0 ? void 0 : vue.toValue(options.sort));
9139
+ const internalSortValue = vue.ref(options.defaultSort ?? null);
9140
+ const sortState = vue.computed({
9141
+ get: () => sortProp.value === void 0 ? internalSortValue.value : sortProp.value ?? null,
9142
+ set: (val) => {
9143
+ if (sortProp.value === void 0) internalSortValue.value = val;
9144
+ options.onSortChange?.(val);
9145
+ }
9146
+ });
9147
+ const sortComparator = vue.computed(() => {
9148
+ const s = sortState.value;
9149
+ if (!s) return null;
9150
+ const col = vue.toValue(options.leafColumns).find((c) => c.key === s.key);
9151
+ if (!col) return null;
9152
+ const dir = s.direction === "asc" ? 1 : -1;
9153
+ const sorter = col.sorter ?? ((a, b) => core.compareValues(getCellValue(a, col), getCellValue(b, col)));
9154
+ return (a, b) => sorter(a, b) * dir;
9155
+ });
9156
+ const sortedData = vue.computed(() => {
9157
+ const compare = sortComparator.value;
9158
+ if (!compare) return data.value;
9159
+ return [...data.value].sort(compare);
9160
+ });
9161
+ function setSort(next) {
9162
+ if (sortProp.value === void 0) internalSortValue.value = next;
9163
+ options.onSortChange?.(next);
9164
+ }
9165
+ function cycleSort(col) {
9166
+ if (!col.sortable) return;
9167
+ const s = sortState.value;
9168
+ if (!s || s.key !== col.key) {
9169
+ setSort({ key: col.key, direction: "asc" });
9170
+ return;
9171
+ }
9172
+ if (s.direction === "asc") {
9173
+ setSort({ key: col.key, direction: "desc" });
9174
+ return;
9175
+ }
9176
+ setSort(null);
9177
+ }
9178
+ return {
9179
+ sortState,
9180
+ cycleSort,
9181
+ setSort,
9182
+ sortComparator,
9183
+ sortedData
9184
+ };
9185
+ }
9186
+
9187
+ // src/primitives/table/Table.ts
9188
+ function getCellValue2(row, column) {
9189
+ const key = column.dataIndex ?? column.key;
9190
+ return row[key];
9191
+ }
8729
9192
  var SELECTION_COL_WIDTH = 40;
8730
9193
  var EXPAND_COL_WIDTH = 40;
8731
9194
  var DEFAULT_COL_WIDTH = 140;
@@ -8752,18 +9215,7 @@ var IrisTable = vue.defineComponent({
8752
9215
  required: true
8753
9216
  },
8754
9217
  rowKey: { type: String, default: "id" },
8755
- selectable: {
8756
- type: String,
8757
- default: "none"
8758
- },
8759
- selection: {
8760
- type: Array,
8761
- default: void 0
8762
- },
8763
- sort: {
8764
- type: Object,
8765
- default: void 0
8766
- },
9218
+ ...tableControlProps,
8767
9219
  striped: { type: Boolean, default: false },
8768
9220
  bordered: { type: Boolean, default: true },
8769
9221
  /** Enable per-column resize handles. Combine with `v-model:columnWidths` for persistence. */
@@ -8847,31 +9299,23 @@ var IrisTable = vue.defineComponent({
8847
9299
  () => grouped.value ? core.flattenLeafColumns(props.columns) : props.columns
8848
9300
  );
8849
9301
  const headerMatrix = vue.computed(() => grouped.value ? core.buildHeaderMatrix(props.columns) : null);
8850
- const internalSortValue = vue.ref(null);
8851
- const internalSort = vue.computed({
8852
- get: () => props.sort === void 0 ? internalSortValue.value : props.sort,
8853
- set: (value) => {
8854
- if (props.sort === void 0) internalSortValue.value = value;
8855
- emit("update:sort", value);
9302
+ const {
9303
+ sortState: internalSort,
9304
+ cycleSort,
9305
+ sortComparator,
9306
+ sortedData: sortedRows
9307
+ } = useTableSort(
9308
+ vue.computed(() => props.data ?? []),
9309
+ {
9310
+ leafColumns,
9311
+ sort: vue.computed(() => props.sort),
9312
+ defaultSort: props.defaultSort,
9313
+ onSortChange: (next) => emit("update:sort", next)
8856
9314
  }
8857
- });
8858
- const sortComparator = vue.computed(() => {
8859
- const state = internalSort.value;
8860
- if (!state) return null;
8861
- const column = leafColumns.value.find((c) => c.key === state.key);
8862
- if (!column) return null;
8863
- const dir = state.direction === "asc" ? 1 : -1;
8864
- const sorter = column.sorter ?? ((a, b) => core.compareValues(getCellValue(a, column), getCellValue(b, column)));
8865
- return (a, b) => sorter(a, b) * dir;
8866
- });
8867
- const sortedRows = vue.computed(() => {
8868
- const compare = sortComparator.value;
8869
- if (!compare) return props.data ?? [];
8870
- return [...props.data ?? []].sort(compare);
8871
- });
9315
+ );
8872
9316
  const selControlled = vue.computed(() => props.selection !== void 0);
8873
9317
  const selectionModel = core.createSelectionModel({
8874
- defaultSelected: props.selection ?? [],
9318
+ defaultSelected: props.selection ?? props.defaultSelection ?? [],
8875
9319
  onChange: (keys) => emit("update:selection", keys)
8876
9320
  });
8877
9321
  const selectedKeys = vue.shallowRef(selectionModel.get());
@@ -8953,14 +9397,14 @@ var IrisTable = vue.defineComponent({
8953
9397
  const beginEdit = (row, column, rowIdent) => {
8954
9398
  if (!column.editable) return;
8955
9399
  editingCellId.value = cellId(rowIdent, column.key);
8956
- const current = getCellValue(row, column);
9400
+ const current = getCellValue2(row, column);
8957
9401
  editingDraft.value = current == null ? "" : String(current);
8958
9402
  editError.value = null;
8959
9403
  void vue.nextTick(() => editorInputRef.value?.focus());
8960
9404
  };
8961
9405
  const commitEdit = (row, column, rowIndex) => {
8962
9406
  if (editingCellId.value === null) return;
8963
- const oldValue = getCellValue(row, column);
9407
+ const oldValue = getCellValue2(row, column);
8964
9408
  const draft = editingDraft.value;
8965
9409
  const newValue = column.editor === "number" ? draft === "" || Number.isNaN(Number(draft)) ? oldValue : Number(draft) : draft;
8966
9410
  if (column.validate) {
@@ -9001,17 +9445,7 @@ var IrisTable = vue.defineComponent({
9001
9445
  emit("update:columnWidths", next);
9002
9446
  };
9003
9447
  const onHeaderClick = (column) => {
9004
- if (!column.sortable) return;
9005
- const current = internalSort.value;
9006
- let next;
9007
- if (!current || current.key !== column.key) {
9008
- next = { key: column.key, direction: "asc" };
9009
- } else if (current.direction === "asc") {
9010
- next = { key: column.key, direction: "desc" };
9011
- } else {
9012
- next = null;
9013
- }
9014
- internalSort.value = next;
9448
+ cycleSort(column);
9015
9449
  };
9016
9450
  const sortIndicator = (col) => {
9017
9451
  if (!col.sortable) return null;
@@ -9585,7 +10019,7 @@ var IrisTable = vue.defineComponent({
9585
10019
  )
9586
10020
  ] : input;
9587
10021
  } else {
9588
- content = cellSlot?.({ row, index, value: getCellValue(row, col) }) ?? String(getCellValue(row, col) ?? "");
10022
+ content = cellSlot?.({ row, index, value: getCellValue2(row, col) }) ?? String(getCellValue2(row, col) ?? "");
9589
10023
  }
9590
10024
  const treeIndent = treeMeta && ci === 0 ? vue.h(
9591
10025
  "span",
@@ -9831,7 +10265,7 @@ var IrisTable = vue.defineComponent({
9831
10265
  if (visibleColSet.value && !visibleColSet.value.has(ci)) continue;
9832
10266
  const align = col.align ?? "left";
9833
10267
  const op = col.summary;
9834
- const value = op ? core.aggregate(bodyData.value, (r) => getCellValue(r, col), op) : null;
10268
+ const value = op ? core.aggregate(bodyData.value, (r) => getCellValue2(r, col), op) : null;
9835
10269
  const summaryContent = op != null && value != null ? col.renderSummary ? col.renderSummary(value, bodyData.value) : String(value) : "";
9836
10270
  summaryCells.push(
9837
10271
  vue.h(
@@ -9910,45 +10344,23 @@ var IrisTable = vue.defineComponent({
9910
10344
  };
9911
10345
  }
9912
10346
  });
9913
- var FORMULA_LEAD = /^[=+\-@\t\r]/;
9914
- function neutralizeFormula(text) {
9915
- return FORMULA_LEAD.test(text) ? `'${text}` : text;
9916
- }
9917
- function csvCell(value) {
9918
- if (value == null) return "";
9919
- const isNumber = typeof value === "number" && Number.isFinite(value);
9920
- const s = isNumber ? String(value) : neutralizeFormula(String(value));
9921
- if (/[",\r\n]/.test(s)) {
9922
- return `"${s.replace(/"/g, '""')}"`;
9923
- }
9924
- return s;
9925
- }
9926
10347
  function exportCsv(rows, columns) {
9927
- const header = columns.map((c) => csvCell(c.title)).join(",");
9928
- const body = rows.map(
9929
- (row) => columns.map((col) => {
9930
- const key = col.dataIndex ?? col.key;
9931
- return csvCell(row[key]);
9932
- }).join(",")
9933
- ).join("\n");
9934
- return body.length > 0 ? `${header}
9935
- ${body}` : header;
10348
+ return core.toCsv(
10349
+ rows,
10350
+ columns.map((column) => ({
10351
+ key: column.key,
10352
+ title: column.title,
10353
+ dataIndex: typeof column.dataIndex === "string" ? column.dataIndex : void 0
10354
+ }))
10355
+ );
9936
10356
  }
9937
10357
  async function downloadCsv(filename, csv) {
9938
10358
  const BOM = String.fromCharCode(65279);
9939
- const content = BOM + csv;
9940
- if (await core.saveFile({ filename, content, mimeType: "text/csv;charset=utf-8;" })) return;
9941
- if (typeof document === "undefined") return;
9942
- const blob = new Blob([content], { type: "text/csv;charset=utf-8;" });
9943
- const url = URL.createObjectURL(blob);
9944
- const anchor = document.createElement("a");
9945
- anchor.href = url;
9946
- anchor.download = filename;
9947
- anchor.style.display = "none";
9948
- document.body.appendChild(anchor);
9949
- anchor.click();
9950
- document.body.removeChild(anchor);
9951
- setTimeout(() => URL.revokeObjectURL(url), 0);
10359
+ await core.downloadFile({
10360
+ filename,
10361
+ content: BOM + csv,
10362
+ mimeType: "text/csv;charset=utf-8;"
10363
+ });
9952
10364
  }
9953
10365
  function exportExcel(rows, columns, options) {
9954
10366
  return core.toSpreadsheetXml(
@@ -9962,20 +10374,11 @@ function exportExcel(rows, columns, options) {
9962
10374
  );
9963
10375
  }
9964
10376
  async function downloadExcel(filename, xml) {
9965
- if (await core.saveFile({ filename, content: xml, mimeType: "application/vnd.ms-excel" })) {
9966
- return;
9967
- }
9968
- if (typeof document === "undefined") return;
9969
- const blob = new Blob([xml], { type: "application/vnd.ms-excel" });
9970
- const url = URL.createObjectURL(blob);
9971
- const anchor = document.createElement("a");
9972
- anchor.href = url;
9973
- anchor.download = filename;
9974
- anchor.style.display = "none";
9975
- document.body.appendChild(anchor);
9976
- anchor.click();
9977
- document.body.removeChild(anchor);
9978
- setTimeout(() => URL.revokeObjectURL(url), 0);
10377
+ await core.downloadFile({
10378
+ filename,
10379
+ content: xml,
10380
+ mimeType: "application/vnd.ms-excel;charset=utf-8"
10381
+ });
9979
10382
  }
9980
10383
 
9981
10384
  // src/primitives/tabs/context.ts
@@ -16367,12 +16770,12 @@ function defaultFilter(query, item) {
16367
16770
  if (!q) return 0;
16368
16771
  const haystacks = [item.label, ...item.keywords ?? []].map((s) => s.toLowerCase());
16369
16772
  let best = null;
16370
- for (const h122 of haystacks) {
16773
+ for (const h123 of haystacks) {
16371
16774
  let qi = 0;
16372
16775
  let lastIdx = -1;
16373
16776
  let score = 0;
16374
- for (let i = 0; i < h122.length && qi < q.length; i += 1) {
16375
- if (h122[i] === q[qi]) {
16777
+ for (let i = 0; i < h123.length && qi < q.length; i += 1) {
16778
+ if (h123[i] === q[qi]) {
16376
16779
  score += lastIdx === -1 ? i : i - lastIdx - 1;
16377
16780
  lastIdx = i;
16378
16781
  qi += 1;
@@ -16738,8 +17141,8 @@ var IrisTimePicker = vue.defineComponent({
16738
17141
  if (props.format === "24h") {
16739
17142
  return { h: value.value.hours, m: value.value.minutes };
16740
17143
  }
16741
- const h122 = value.value.hours % 12 === 0 ? 12 : value.value.hours % 12;
16742
- return { h: h122, m: value.value.minutes };
17144
+ const h123 = value.value.hours % 12 === 0 ? 12 : value.value.hours % 12;
17145
+ return { h: h123, m: value.value.minutes };
16743
17146
  });
16744
17147
  const emitNew = (next) => {
16745
17148
  emit("update:modelValue", next);
@@ -16755,16 +17158,16 @@ var IrisTimePicker = vue.defineComponent({
16755
17158
  };
16756
17159
  const toggleMeridiem = () => {
16757
17160
  const isPM = meridiem.value === "PM";
16758
- const h122 = value.value.hours % 12;
16759
- const newH24 = isPM ? h122 : h122 + 12;
17161
+ const h123 = value.value.hours % 12;
17162
+ const newH24 = isPM ? h123 : h123 + 12;
16760
17163
  emitNew({ hours: newH24, minutes: value.value.minutes });
16761
17164
  };
16762
17165
  const onHoursInput = (e) => {
16763
17166
  const v = parseInt(e.target.value || "0", 10);
16764
17167
  if (Number.isNaN(v)) return;
16765
17168
  if (props.format === "12h") {
16766
- const h122 = clamp5(v, 1, 12);
16767
- const wrap = h122 === 12 ? 0 : h122;
17169
+ const h123 = clamp5(v, 1, 12);
17170
+ const wrap = h123 === 12 ? 0 : h123;
16768
17171
  const newH24 = meridiem.value === "PM" ? wrap + 12 : wrap;
16769
17172
  setHours24(newH24);
16770
17173
  } else {
@@ -17947,164 +18350,6 @@ var IrisClickOutside = vue.defineComponent({
17947
18350
  );
17948
18351
  }
17949
18352
  });
17950
- var SORTABLE_ITEM_ATTR = "data-iris-sortable-item";
17951
- var IrisSortable = vue.defineComponent({
17952
- name: "IrisSortable",
17953
- inheritAttrs: false,
17954
- props: {
17955
- /** The ordered items. Used to detect which item is at which position. */
17956
- items: {
17957
- type: Array,
17958
- required: true
17959
- },
17960
- /** Called when the user drops an item in a new position. */
17961
- onReorder: {
17962
- type: Function,
17963
- default: void 0
17964
- },
17965
- /** Optional item key getter. Defaults to `String(index)`. */
17966
- getKey: {
17967
- type: Function,
17968
- default: void 0
17969
- },
17970
- disabled: {
17971
- type: Boolean,
17972
- default: false
17973
- },
17974
- class: {
17975
- type: String,
17976
- default: void 0
17977
- },
17978
- style: {
17979
- type: Object,
17980
- default: void 0
17981
- }
17982
- },
17983
- emits: {
17984
- reorder: (_next) => true
17985
- },
17986
- setup(props, { slots, attrs, emit }) {
17987
- const containerRef = vue.ref(null);
17988
- const sortable = core.createSortable();
17989
- const activeKey = vue.ref(null);
17990
- const unsub = sortable.subscribe((state) => {
17991
- activeKey.value = state.activeId;
17992
- });
17993
- vue.onBeforeUnmount(unsub);
17994
- const indexOf = (key) => {
17995
- const container = containerRef.value;
17996
- if (!container) return -1;
17997
- return Array.from(
17998
- container.querySelectorAll(`[${SORTABLE_ITEM_ATTR}]`)
17999
- ).findIndex((el) => el.getAttribute(SORTABLE_ITEM_ATTR) === key);
18000
- };
18001
- const onPointerDown = (e) => {
18002
- if (props.disabled) return;
18003
- const target = e.target.closest(`[${SORTABLE_ITEM_ATTR}]`);
18004
- if (!target) return;
18005
- const container = containerRef.value;
18006
- if (!container) return;
18007
- const key = target.getAttribute(SORTABLE_ITEM_ATTR) ?? "";
18008
- const index = indexOf(key);
18009
- if (index < 0) return;
18010
- sortable.press(key, e.clientX, e.clientY);
18011
- };
18012
- const onPointerMove = (e) => {
18013
- if (!sortable.isPending() && sortable.getState().activeId === null) return;
18014
- const items = containerRef.value?.querySelectorAll(`[${SORTABLE_ITEM_ATTR}]`);
18015
- const rects = Array.from(items ?? []).map((el) => {
18016
- const rect = el.getBoundingClientRect();
18017
- return {
18018
- id: el.getAttribute(SORTABLE_ITEM_ATTR) ?? "",
18019
- left: rect.left,
18020
- top: rect.top,
18021
- width: rect.width,
18022
- height: rect.height
18023
- };
18024
- });
18025
- sortable.tryStart(e.clientX, e.clientY);
18026
- if (sortable.getState().activeId !== null) {
18027
- sortable.moveOver({ x: e.clientX, y: e.clientY }, rects);
18028
- }
18029
- };
18030
- const onPointerUp = () => {
18031
- const state = sortable.getState();
18032
- if (state.activeId === null) {
18033
- sortable.cancel();
18034
- return;
18035
- }
18036
- const result = sortable.end();
18037
- if (result.activeId && result.overId && result.activeId !== result.overId) {
18038
- const from = indexOf(result.activeId);
18039
- const to = indexOf(result.overId);
18040
- if (from >= 0 && to >= 0) {
18041
- const next = [...props.items];
18042
- const [moved] = next.splice(from, 1);
18043
- next.splice(to, 0, moved);
18044
- if (props.onReorder) {
18045
- props.onReorder(next);
18046
- }
18047
- emit("reorder", next);
18048
- }
18049
- }
18050
- };
18051
- const resolveKey = (item, index) => props.getKey ? props.getKey(item, index) : String(index);
18052
- return () => {
18053
- const children = [];
18054
- const defaultSlots = slots.default?.();
18055
- if (defaultSlots) {
18056
- const itemsArray = props.items;
18057
- defaultSlots.forEach((child, index) => {
18058
- const item = itemsArray[index];
18059
- const key = resolveKey(item, index);
18060
- const isDragging = key === activeKey.value;
18061
- children.push(
18062
- vue.h(
18063
- "div",
18064
- {
18065
- key,
18066
- [SORTABLE_ITEM_ATTR]: key,
18067
- "data-iris-sortable-dragging": isDragging ? "" : void 0,
18068
- style: {
18069
- transition: isDragging ? "none" : "transform 150ms ease",
18070
- opacity: isDragging ? 0.4 : 1,
18071
- position: "relative",
18072
- zIndex: isDragging ? 100 : void 0
18073
- }
18074
- },
18075
- [child]
18076
- )
18077
- );
18078
- });
18079
- }
18080
- return vue.h(
18081
- "div",
18082
- {
18083
- ...attrs,
18084
- ref: (el) => {
18085
- containerRef.value = el ?? null;
18086
- },
18087
- "data-iris-sortable": "",
18088
- "data-state": activeKey.value ? "dragging" : "idle",
18089
- class: props.class,
18090
- style: {
18091
- display: "flex",
18092
- flexDirection: "column",
18093
- gap: "var(--iris-gap-sm, 4px)",
18094
- opacity: props.disabled ? 0.6 : 1,
18095
- userSelect: activeKey.value ? "none" : void 0,
18096
- ...props.style ?? {}
18097
- },
18098
- onPointerdown: onPointerDown,
18099
- onPointermove: onPointerMove,
18100
- onPointerup: onPointerUp,
18101
- onPointerleave: onPointerUp
18102
- },
18103
- children
18104
- );
18105
- };
18106
- }
18107
- });
18108
18353
  var IrisLongPress = vue.defineComponent({
18109
18354
  name: "IrisLongPress",
18110
18355
  inheritAttrs: false,
@@ -18160,90 +18405,6 @@ var IrisLongPress = vue.defineComponent({
18160
18405
  }
18161
18406
  });
18162
18407
 
18163
- Object.defineProperty(exports, "applyTheme", {
18164
- enumerable: true,
18165
- get: function () { return theme.applyTheme; }
18166
- });
18167
- Object.defineProperty(exports, "createThemeStore", {
18168
- enumerable: true,
18169
- get: function () { return theme.createThemeStore; }
18170
- });
18171
- Object.defineProperty(exports, "getCssVar", {
18172
- enumerable: true,
18173
- get: function () { return theme.getCssVar; }
18174
- });
18175
- Object.defineProperty(exports, "toCssVarName", {
18176
- enumerable: true,
18177
- get: function () { return theme.toCssVarName; }
18178
- });
18179
- Object.defineProperty(exports, "SkinResolutionError", {
18180
- enumerable: true,
18181
- get: function () { return skins.SkinResolutionError; }
18182
- });
18183
- Object.defineProperty(exports, "applySkin", {
18184
- enumerable: true,
18185
- get: function () { return skins.applySkin; }
18186
- });
18187
- Object.defineProperty(exports, "builtinSkins", {
18188
- enumerable: true,
18189
- get: function () { return skins.builtinSkins; }
18190
- });
18191
- Object.defineProperty(exports, "createSkinCatalog", {
18192
- enumerable: true,
18193
- get: function () { return skins.createSkinCatalog; }
18194
- });
18195
- Object.defineProperty(exports, "createSkinEngine", {
18196
- enumerable: true,
18197
- get: function () { return skins.createSkinEngine; }
18198
- });
18199
- Object.defineProperty(exports, "createSkinRegistry", {
18200
- enumerable: true,
18201
- get: function () { return skins.createSkinRegistry; }
18202
- });
18203
- Object.defineProperty(exports, "darkSkin", {
18204
- enumerable: true,
18205
- get: function () { return skins.darkSkin; }
18206
- });
18207
- Object.defineProperty(exports, "lightSkin", {
18208
- enumerable: true,
18209
- get: function () { return skins.lightSkin; }
18210
- });
18211
- Object.defineProperty(exports, "loadSkin", {
18212
- enumerable: true,
18213
- get: function () { return skins.loadSkin; }
18214
- });
18215
- Object.defineProperty(exports, "localStorageSkinStorage", {
18216
- enumerable: true,
18217
- get: function () { return skins.localStorageSkinStorage; }
18218
- });
18219
- Object.defineProperty(exports, "memorySkinStorage", {
18220
- enumerable: true,
18221
- get: function () { return skins.memorySkinStorage; }
18222
- });
18223
- Object.defineProperty(exports, "renderSkinStyle", {
18224
- enumerable: true,
18225
- get: function () { return skins.renderSkinStyle; }
18226
- });
18227
- Object.defineProperty(exports, "resolveSkin", {
18228
- enumerable: true,
18229
- get: function () { return skins.resolveSkin; }
18230
- });
18231
- Object.defineProperty(exports, "skinBootScript", {
18232
- enumerable: true,
18233
- get: function () { return skins.skinBootScript; }
18234
- });
18235
- Object.defineProperty(exports, "skinError", {
18236
- enumerable: true,
18237
- get: function () { return skins.skinError; }
18238
- });
18239
- Object.defineProperty(exports, "skinToCssEntries", {
18240
- enumerable: true,
18241
- get: function () { return skins.skinToCssEntries; }
18242
- });
18243
- Object.defineProperty(exports, "validateSkin", {
18244
- enumerable: true,
18245
- get: function () { return skins.validateSkin; }
18246
- });
18247
18408
  Object.defineProperty(exports, "addDays", {
18248
18409
  enumerable: true,
18249
18410
  get: function () { return core.addDays; }
@@ -18268,6 +18429,10 @@ Object.defineProperty(exports, "composeEventHandlers", {
18268
18429
  enumerable: true,
18269
18430
  get: function () { return core.composeEventHandlers; }
18270
18431
  });
18432
+ Object.defineProperty(exports, "createAdminPreferences", {
18433
+ enumerable: true,
18434
+ get: function () { return core.createAdminPreferences; }
18435
+ });
18271
18436
  Object.defineProperty(exports, "createClientDataSource", {
18272
18437
  enumerable: true,
18273
18438
  get: function () { return core.createClientDataSource; }
@@ -18308,6 +18473,10 @@ Object.defineProperty(exports, "endOfMonth", {
18308
18473
  enumerable: true,
18309
18474
  get: function () { return core.endOfMonth; }
18310
18475
  });
18476
+ Object.defineProperty(exports, "filterNavByAccess", {
18477
+ enumerable: true,
18478
+ get: function () { return core.filterNavByAccess; }
18479
+ });
18311
18480
  Object.defineProperty(exports, "findNavNode", {
18312
18481
  enumerable: true,
18313
18482
  get: function () { return core.findNavNode; }
@@ -18376,10 +18545,18 @@ Object.defineProperty(exports, "isSameMonth", {
18376
18545
  enumerable: true,
18377
18546
  get: function () { return core.isSameMonth; }
18378
18547
  });
18548
+ Object.defineProperty(exports, "localStorageAdminPreferencesStorage", {
18549
+ enumerable: true,
18550
+ get: function () { return core.localStorageAdminPreferencesStorage; }
18551
+ });
18379
18552
  Object.defineProperty(exports, "mergeProps", {
18380
18553
  enumerable: true,
18381
18554
  get: function () { return core.mergeProps; }
18382
18555
  });
18556
+ Object.defineProperty(exports, "nodeAllowsRoles", {
18557
+ enumerable: true,
18558
+ get: function () { return core.nodeAllowsRoles; }
18559
+ });
18383
18560
  Object.defineProperty(exports, "rgbToHex", {
18384
18561
  enumerable: true,
18385
18562
  get: function () { return core.rgbToHex; }
@@ -18404,6 +18581,90 @@ Object.defineProperty(exports, "visibleNav", {
18404
18581
  enumerable: true,
18405
18582
  get: function () { return core.visibleNav; }
18406
18583
  });
18584
+ Object.defineProperty(exports, "applyTheme", {
18585
+ enumerable: true,
18586
+ get: function () { return theme.applyTheme; }
18587
+ });
18588
+ Object.defineProperty(exports, "createThemeStore", {
18589
+ enumerable: true,
18590
+ get: function () { return theme.createThemeStore; }
18591
+ });
18592
+ Object.defineProperty(exports, "getCssVar", {
18593
+ enumerable: true,
18594
+ get: function () { return theme.getCssVar; }
18595
+ });
18596
+ Object.defineProperty(exports, "toCssVarName", {
18597
+ enumerable: true,
18598
+ get: function () { return theme.toCssVarName; }
18599
+ });
18600
+ Object.defineProperty(exports, "SkinResolutionError", {
18601
+ enumerable: true,
18602
+ get: function () { return skins.SkinResolutionError; }
18603
+ });
18604
+ Object.defineProperty(exports, "applySkin", {
18605
+ enumerable: true,
18606
+ get: function () { return skins.applySkin; }
18607
+ });
18608
+ Object.defineProperty(exports, "builtinSkins", {
18609
+ enumerable: true,
18610
+ get: function () { return skins.builtinSkins; }
18611
+ });
18612
+ Object.defineProperty(exports, "createSkinCatalog", {
18613
+ enumerable: true,
18614
+ get: function () { return skins.createSkinCatalog; }
18615
+ });
18616
+ Object.defineProperty(exports, "createSkinEngine", {
18617
+ enumerable: true,
18618
+ get: function () { return skins.createSkinEngine; }
18619
+ });
18620
+ Object.defineProperty(exports, "createSkinRegistry", {
18621
+ enumerable: true,
18622
+ get: function () { return skins.createSkinRegistry; }
18623
+ });
18624
+ Object.defineProperty(exports, "darkSkin", {
18625
+ enumerable: true,
18626
+ get: function () { return skins.darkSkin; }
18627
+ });
18628
+ Object.defineProperty(exports, "lightSkin", {
18629
+ enumerable: true,
18630
+ get: function () { return skins.lightSkin; }
18631
+ });
18632
+ Object.defineProperty(exports, "loadSkin", {
18633
+ enumerable: true,
18634
+ get: function () { return skins.loadSkin; }
18635
+ });
18636
+ Object.defineProperty(exports, "localStorageSkinStorage", {
18637
+ enumerable: true,
18638
+ get: function () { return skins.localStorageSkinStorage; }
18639
+ });
18640
+ Object.defineProperty(exports, "memorySkinStorage", {
18641
+ enumerable: true,
18642
+ get: function () { return skins.memorySkinStorage; }
18643
+ });
18644
+ Object.defineProperty(exports, "renderSkinStyle", {
18645
+ enumerable: true,
18646
+ get: function () { return skins.renderSkinStyle; }
18647
+ });
18648
+ Object.defineProperty(exports, "resolveSkin", {
18649
+ enumerable: true,
18650
+ get: function () { return skins.resolveSkin; }
18651
+ });
18652
+ Object.defineProperty(exports, "skinBootScript", {
18653
+ enumerable: true,
18654
+ get: function () { return skins.skinBootScript; }
18655
+ });
18656
+ Object.defineProperty(exports, "skinError", {
18657
+ enumerable: true,
18658
+ get: function () { return skins.skinError; }
18659
+ });
18660
+ Object.defineProperty(exports, "skinToCssEntries", {
18661
+ enumerable: true,
18662
+ get: function () { return skins.skinToCssEntries; }
18663
+ });
18664
+ Object.defineProperty(exports, "validateSkin", {
18665
+ enumerable: true,
18666
+ get: function () { return skins.validateSkin; }
18667
+ });
18407
18668
  Object.defineProperty(exports, "createIconRegistry", {
18408
18669
  enumerable: true,
18409
18670
  get: function () { return icons.createIconRegistry; }
@@ -18637,6 +18898,7 @@ exports.installDataStateStyles = installDataStateStyles;
18637
18898
  exports.mergeSlotProps = mergeSlotProps;
18638
18899
  exports.pushToast = pushToast;
18639
18900
  exports.subscribeToasts = subscribeToasts;
18901
+ exports.useAdminPreferences = useAdminPreferences;
18640
18902
  exports.useAdminShell = useAdminShell;
18641
18903
  exports.useAsyncResource = useAsyncResource;
18642
18904
  exports.useBodyScrollLock = useBodyScrollLock;
@@ -18645,6 +18907,7 @@ exports.useDataSource = useDataSource;
18645
18907
  exports.useDataState = useDataState;
18646
18908
  exports.useDirection = useDirection;
18647
18909
  exports.useDismiss = useDismiss;
18910
+ exports.useDisposableScope = useDisposableScope;
18648
18911
  exports.useDrag = useDrag;
18649
18912
  exports.useField = useField;
18650
18913
  exports.useFieldArray = useFieldArray;
@@ -18659,6 +18922,8 @@ exports.usePaginatedResource = usePaginatedResource;
18659
18922
  exports.usePlugin = usePlugin;
18660
18923
  exports.usePluginStore = usePluginStore;
18661
18924
  exports.usePrefersReducedMotion = usePrefersReducedMotion;
18925
+ exports.useReconnectingSource = useReconnectingSource;
18926
+ exports.useResilientFetcher = useResilientFetcher;
18662
18927
  exports.useResourceController = useResourceController;
18663
18928
  exports.useSkin = useSkin;
18664
18929
  exports.useSkinContext = useSkinContext;