@iris-ui-kit/vue 0.1.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 (164) hide show
  1. package/LICENSE +21 -0
  2. package/dist/admin.cjs +1869 -0
  3. package/dist/admin.cjs.map +1 -0
  4. package/dist/admin.d.cts +376 -0
  5. package/dist/admin.d.ts +376 -0
  6. package/dist/admin.js +10 -0
  7. package/dist/admin.js.map +1 -0
  8. package/dist/async.cjs +76 -0
  9. package/dist/async.cjs.map +1 -0
  10. package/dist/async.d.cts +59 -0
  11. package/dist/async.d.ts +59 -0
  12. package/dist/async.js +3 -0
  13. package/dist/async.js.map +1 -0
  14. package/dist/behaviors.cjs +659 -0
  15. package/dist/behaviors.cjs.map +1 -0
  16. package/dist/behaviors.d.cts +441 -0
  17. package/dist/behaviors.d.ts +441 -0
  18. package/dist/behaviors.js +3 -0
  19. package/dist/behaviors.js.map +1 -0
  20. package/dist/chunk-3FJUCHCC.js +146 -0
  21. package/dist/chunk-3FJUCHCC.js.map +1 -0
  22. package/dist/chunk-3R3QDLJC.js +172 -0
  23. package/dist/chunk-3R3QDLJC.js.map +1 -0
  24. package/dist/chunk-4FLIW67H.js +137 -0
  25. package/dist/chunk-4FLIW67H.js.map +1 -0
  26. package/dist/chunk-4FQ7XF52.js +3 -0
  27. package/dist/chunk-4FQ7XF52.js.map +1 -0
  28. package/dist/chunk-72PZMU6R.js +99 -0
  29. package/dist/chunk-72PZMU6R.js.map +1 -0
  30. package/dist/chunk-75GSYEJS.js +17 -0
  31. package/dist/chunk-75GSYEJS.js.map +1 -0
  32. package/dist/chunk-7IOJADZC.js +38 -0
  33. package/dist/chunk-7IOJADZC.js.map +1 -0
  34. package/dist/chunk-CIZGSGXN.js +651 -0
  35. package/dist/chunk-CIZGSGXN.js.map +1 -0
  36. package/dist/chunk-F77KIPOH.js +103 -0
  37. package/dist/chunk-F77KIPOH.js.map +1 -0
  38. package/dist/chunk-FJBYAIL4.js +1318 -0
  39. package/dist/chunk-FJBYAIL4.js.map +1 -0
  40. package/dist/chunk-H7HVVPYR.js +66 -0
  41. package/dist/chunk-H7HVVPYR.js.map +1 -0
  42. package/dist/chunk-I6D5VXQK.js +167 -0
  43. package/dist/chunk-I6D5VXQK.js.map +1 -0
  44. package/dist/chunk-PPYNXNGZ.js +73 -0
  45. package/dist/chunk-PPYNXNGZ.js.map +1 -0
  46. package/dist/chunk-QLUIKEMJ.js +1197 -0
  47. package/dist/chunk-QLUIKEMJ.js.map +1 -0
  48. package/dist/chunk-ROJV6RON.js +3 -0
  49. package/dist/chunk-ROJV6RON.js.map +1 -0
  50. package/dist/chunk-S43IHHBU.js +82 -0
  51. package/dist/chunk-S43IHHBU.js.map +1 -0
  52. package/dist/chunk-TCAXRWT6.js +108 -0
  53. package/dist/chunk-TCAXRWT6.js.map +1 -0
  54. package/dist/chunk-TQB5LVOH.js +17 -0
  55. package/dist/chunk-TQB5LVOH.js.map +1 -0
  56. package/dist/chunk-VM2CXEUA.js +46 -0
  57. package/dist/chunk-VM2CXEUA.js.map +1 -0
  58. package/dist/chunk-W2JVHGFR.js +103 -0
  59. package/dist/chunk-W2JVHGFR.js.map +1 -0
  60. package/dist/chunk-WL67XCH5.js +59 -0
  61. package/dist/chunk-WL67XCH5.js.map +1 -0
  62. package/dist/chunk-XCNCIG2I.js +165 -0
  63. package/dist/chunk-XCNCIG2I.js.map +1 -0
  64. package/dist/chunk-XSLBANUV.js +16 -0
  65. package/dist/chunk-XSLBANUV.js.map +1 -0
  66. package/dist/chunk-ZY4NLITM.js +73 -0
  67. package/dist/chunk-ZY4NLITM.js.map +1 -0
  68. package/dist/data.cjs +59 -0
  69. package/dist/data.cjs.map +1 -0
  70. package/dist/data.d.cts +46 -0
  71. package/dist/data.d.ts +46 -0
  72. package/dist/data.js +4 -0
  73. package/dist/data.js.map +1 -0
  74. package/dist/error-boundary.cjs +115 -0
  75. package/dist/error-boundary.cjs.map +1 -0
  76. package/dist/error-boundary.d.cts +60 -0
  77. package/dist/error-boundary.d.ts +60 -0
  78. package/dist/error-boundary.js +4 -0
  79. package/dist/error-boundary.js.map +1 -0
  80. package/dist/floating.cjs +149 -0
  81. package/dist/floating.cjs.map +1 -0
  82. package/dist/floating.d.cts +106 -0
  83. package/dist/floating.d.ts +106 -0
  84. package/dist/floating.js +4 -0
  85. package/dist/floating.js.map +1 -0
  86. package/dist/form.cjs +144 -0
  87. package/dist/form.cjs.map +1 -0
  88. package/dist/form.d.cts +128 -0
  89. package/dist/form.d.ts +128 -0
  90. package/dist/form.js +3 -0
  91. package/dist/form.js.map +1 -0
  92. package/dist/i18n.cjs +112 -0
  93. package/dist/i18n.cjs.map +1 -0
  94. package/dist/i18n.d.cts +99 -0
  95. package/dist/i18n.d.ts +99 -0
  96. package/dist/i18n.js +3 -0
  97. package/dist/i18n.js.map +1 -0
  98. package/dist/index.cjs +18673 -0
  99. package/dist/index.cjs.map +1 -0
  100. package/dist/index.d.cts +8087 -0
  101. package/dist/index.d.ts +8087 -0
  102. package/dist/index.js +13525 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/layouts.cjs +392 -0
  105. package/dist/layouts.cjs.map +1 -0
  106. package/dist/layouts.d.cts +406 -0
  107. package/dist/layouts.d.ts +406 -0
  108. package/dist/layouts.js +5 -0
  109. package/dist/layouts.js.map +1 -0
  110. package/dist/machine.cjs +19 -0
  111. package/dist/machine.cjs.map +1 -0
  112. package/dist/machine.d.cts +18 -0
  113. package/dist/machine.d.ts +18 -0
  114. package/dist/machine.js +4 -0
  115. package/dist/machine.js.map +1 -0
  116. package/dist/modal-utils.cjs +170 -0
  117. package/dist/modal-utils.cjs.map +1 -0
  118. package/dist/modal-utils.d.cts +43 -0
  119. package/dist/modal-utils.d.ts +43 -0
  120. package/dist/modal-utils.js +3 -0
  121. package/dist/modal-utils.js.map +1 -0
  122. package/dist/motion.cjs +88 -0
  123. package/dist/motion.cjs.map +1 -0
  124. package/dist/motion.d.cts +43 -0
  125. package/dist/motion.d.ts +43 -0
  126. package/dist/motion.js +3 -0
  127. package/dist/motion.js.map +1 -0
  128. package/dist/provider.cjs +272 -0
  129. package/dist/provider.cjs.map +1 -0
  130. package/dist/provider.d.cts +130 -0
  131. package/dist/provider.d.ts +130 -0
  132. package/dist/provider.js +6 -0
  133. package/dist/provider.js.map +1 -0
  134. package/dist/resource.cjs +25 -0
  135. package/dist/resource.cjs.map +1 -0
  136. package/dist/resource.d.cts +17 -0
  137. package/dist/resource.d.ts +17 -0
  138. package/dist/resource.js +3 -0
  139. package/dist/resource.js.map +1 -0
  140. package/dist/skeletons.cjs +1659 -0
  141. package/dist/skeletons.cjs.map +1 -0
  142. package/dist/skeletons.d.cts +179 -0
  143. package/dist/skeletons.d.ts +179 -0
  144. package/dist/skeletons.js +7 -0
  145. package/dist/skeletons.js.map +1 -0
  146. package/dist/skins.cjs +138 -0
  147. package/dist/skins.cjs.map +1 -0
  148. package/dist/skins.d.cts +67 -0
  149. package/dist/skins.d.ts +67 -0
  150. package/dist/skins.js +3 -0
  151. package/dist/skins.js.map +1 -0
  152. package/dist/theme.cjs +106 -0
  153. package/dist/theme.cjs.map +1 -0
  154. package/dist/theme.d.cts +103 -0
  155. package/dist/theme.d.ts +103 -0
  156. package/dist/theme.js +3 -0
  157. package/dist/theme.js.map +1 -0
  158. package/dist/undo.cjs +51 -0
  159. package/dist/undo.cjs.map +1 -0
  160. package/dist/undo.d.cts +48 -0
  161. package/dist/undo.d.ts +48 -0
  162. package/dist/undo.js +3 -0
  163. package/dist/undo.js.map +1 -0
  164. package/package.json +59 -0
@@ -0,0 +1,43 @@
1
+ import { Ref } from 'vue';
2
+
3
+ interface UseFocusTrapOptions {
4
+ /** Element whose Tab key cycle is being trapped. */
5
+ container: Ref<HTMLElement | null>;
6
+ /** Whether the trap is currently active. */
7
+ active: Ref<boolean>;
8
+ /** Element to restore focus to when the trap deactivates. */
9
+ returnFocusTo?: Ref<HTMLElement | null | undefined>;
10
+ /** Whether to focus the first focusable element on activation. Default `true`. */
11
+ initialFocus?: boolean;
12
+ }
13
+ /**
14
+ * Constrain Tab / Shift+Tab focus traversal to descendants of `container`.
15
+ *
16
+ * Behavior on activation:
17
+ * - Records the currently focused element.
18
+ * - If `initialFocus !== false`, focuses the first focusable descendant
19
+ * (or the container itself if there are none).
20
+ *
21
+ * Behavior while active:
22
+ * - Tab on the last focusable element wraps to the first; Shift+Tab on
23
+ * the first wraps to the last.
24
+ *
25
+ * Behavior on deactivation:
26
+ * - Restores focus to `returnFocusTo?.value` if provided, else to the
27
+ * element that was focused when the trap activated.
28
+ */
29
+ declare function useFocusTrap(options: UseFocusTrapOptions): void;
30
+
31
+ /**
32
+ * Lock the document body's scroll while `active` is true. Reference-counted
33
+ * so multiple stacked Dialogs cooperate. Restores prior `overflow` and
34
+ * `padding-right` (to compensate for the scrollbar gap) when the last lock
35
+ * releases. SSR-safe.
36
+ */
37
+ declare function useBodyScrollLock(active: Ref<boolean>): void;
38
+ /** Test-only: read the current lock count. */
39
+ declare function __getBodyScrollLockCount(): number;
40
+ /** Test-only: hard-reset the module-level lock state. */
41
+ declare function __resetBodyScrollLock(): void;
42
+
43
+ export { type UseFocusTrapOptions, __getBodyScrollLockCount, __resetBodyScrollLock, useBodyScrollLock, useFocusTrap };
@@ -0,0 +1,43 @@
1
+ import { Ref } from 'vue';
2
+
3
+ interface UseFocusTrapOptions {
4
+ /** Element whose Tab key cycle is being trapped. */
5
+ container: Ref<HTMLElement | null>;
6
+ /** Whether the trap is currently active. */
7
+ active: Ref<boolean>;
8
+ /** Element to restore focus to when the trap deactivates. */
9
+ returnFocusTo?: Ref<HTMLElement | null | undefined>;
10
+ /** Whether to focus the first focusable element on activation. Default `true`. */
11
+ initialFocus?: boolean;
12
+ }
13
+ /**
14
+ * Constrain Tab / Shift+Tab focus traversal to descendants of `container`.
15
+ *
16
+ * Behavior on activation:
17
+ * - Records the currently focused element.
18
+ * - If `initialFocus !== false`, focuses the first focusable descendant
19
+ * (or the container itself if there are none).
20
+ *
21
+ * Behavior while active:
22
+ * - Tab on the last focusable element wraps to the first; Shift+Tab on
23
+ * the first wraps to the last.
24
+ *
25
+ * Behavior on deactivation:
26
+ * - Restores focus to `returnFocusTo?.value` if provided, else to the
27
+ * element that was focused when the trap activated.
28
+ */
29
+ declare function useFocusTrap(options: UseFocusTrapOptions): void;
30
+
31
+ /**
32
+ * Lock the document body's scroll while `active` is true. Reference-counted
33
+ * so multiple stacked Dialogs cooperate. Restores prior `overflow` and
34
+ * `padding-right` (to compensate for the scrollbar gap) when the last lock
35
+ * releases. SSR-safe.
36
+ */
37
+ declare function useBodyScrollLock(active: Ref<boolean>): void;
38
+ /** Test-only: read the current lock count. */
39
+ declare function __getBodyScrollLockCount(): number;
40
+ /** Test-only: hard-reset the module-level lock state. */
41
+ declare function __resetBodyScrollLock(): void;
42
+
43
+ export { type UseFocusTrapOptions, __getBodyScrollLockCount, __resetBodyScrollLock, useBodyScrollLock, useFocusTrap };
@@ -0,0 +1,3 @@
1
+ export { __getBodyScrollLockCount, __resetBodyScrollLock, useBodyScrollLock, useFocusTrap } from './chunk-XCNCIG2I.js';
2
+ //# sourceMappingURL=modal-utils.js.map
3
+ //# sourceMappingURL=modal-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"modal-utils.js"}
@@ -0,0 +1,88 @@
1
+ 'use strict';
2
+
3
+ var vue = require('vue');
4
+ var core = require('@iris-ui-kit/core');
5
+
6
+ // src/motion/usePrefersReducedMotion.ts
7
+ var QUERY = "(prefers-reduced-motion: reduce)";
8
+ function read() {
9
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
10
+ return window.matchMedia(QUERY).matches;
11
+ }
12
+ function usePrefersReducedMotion() {
13
+ const reduced = vue.ref(read());
14
+ let mq = null;
15
+ const onChange = () => {
16
+ if (mq) reduced.value = mq.matches;
17
+ };
18
+ vue.onMounted(() => {
19
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
20
+ mq = window.matchMedia(QUERY);
21
+ reduced.value = mq.matches;
22
+ mq.addEventListener?.("change", onChange);
23
+ });
24
+ vue.onBeforeUnmount(() => {
25
+ mq?.removeEventListener?.("change", onChange);
26
+ });
27
+ return reduced;
28
+ }
29
+
30
+ // src/motion/styles.ts
31
+ var __DATA_STATE_STYLE_ID = "iris-data-state-styles";
32
+ var DATA_STATE_CLASS = "iris-data-state-enter";
33
+ var CSS = `
34
+ @keyframes iris-data-state-enter {
35
+ from { opacity: 0; transform: translateY(4px); }
36
+ to { opacity: 1; transform: none; }
37
+ }
38
+ .${DATA_STATE_CLASS} {
39
+ animation: iris-data-state-enter var(--iris-duration-md, 200ms) ease;
40
+ }
41
+ @media (prefers-reduced-motion: reduce) {
42
+ .${DATA_STATE_CLASS} { animation: none; }
43
+ }
44
+ `.trim();
45
+ var installed = false;
46
+ function installDataStateStyles() {
47
+ if (installed) return;
48
+ if (typeof document === "undefined") return;
49
+ if (document.getElementById(__DATA_STATE_STYLE_ID)) {
50
+ installed = true;
51
+ return;
52
+ }
53
+ const el = document.createElement("style");
54
+ el.id = __DATA_STATE_STYLE_ID;
55
+ el.textContent = CSS;
56
+ document.head.appendChild(el);
57
+ installed = true;
58
+ }
59
+ function __resetDataStateStyles() {
60
+ installed = false;
61
+ if (typeof document !== "undefined") {
62
+ document.getElementById(__DATA_STATE_STYLE_ID)?.remove();
63
+ }
64
+ }
65
+
66
+ // src/motion/useDataState.ts
67
+ function useDataState(input) {
68
+ vue.onMounted(installDataStateStyles);
69
+ const reduced = usePrefersReducedMotion();
70
+ const state = vue.computed(() => core.resolveDataState(input()));
71
+ return {
72
+ state,
73
+ isContent: vue.computed(() => state.value === "content"),
74
+ stateKey: state,
75
+ stateProps: vue.computed(() => ({
76
+ class: reduced.value ? "" : DATA_STATE_CLASS,
77
+ "data-iris-state": state.value
78
+ }))
79
+ };
80
+ }
81
+
82
+ exports.DATA_STATE_CLASS = DATA_STATE_CLASS;
83
+ exports.__resetDataStateStyles = __resetDataStateStyles;
84
+ exports.installDataStateStyles = installDataStateStyles;
85
+ exports.useDataState = useDataState;
86
+ exports.usePrefersReducedMotion = usePrefersReducedMotion;
87
+ //# sourceMappingURL=motion.cjs.map
88
+ //# sourceMappingURL=motion.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/motion/usePrefersReducedMotion.ts","../src/motion/styles.ts","../src/motion/useDataState.ts"],"names":["ref","onMounted","onBeforeUnmount","computed","resolveDataState"],"mappings":";;;;;;AAEA,IAAM,KAAA,GAAQ,kCAAA;AAEd,SAAS,IAAA,GAAgB;AACvB,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,MAAA,CAAO,UAAA,KAAe,YAAY,OAAO,KAAA;AACrF,EAAA,OAAO,MAAA,CAAO,UAAA,CAAW,KAAK,CAAA,CAAE,OAAA;AAClC;AAOO,SAAS,uBAAA,GAAwC;AACtD,EAAA,MAAM,OAAA,GAAUA,OAAA,CAAa,IAAA,EAAM,CAAA;AACnC,EAAA,IAAI,EAAA,GAA4B,IAAA;AAChC,EAAA,MAAM,WAAW,MAAM;AACrB,IAAA,IAAI,EAAA,EAAI,OAAA,CAAQ,KAAA,GAAQ,EAAA,CAAG,OAAA;AAAA,EAC7B,CAAA;AAEA,EAAAC,aAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,MAAA,CAAO,eAAe,UAAA,EAAY;AAC9E,IAAA,EAAA,GAAK,MAAA,CAAO,WAAW,KAAK,CAAA;AAC5B,IAAA,OAAA,CAAQ,QAAQ,EAAA,CAAG,OAAA;AACnB,IAAA,EAAA,CAAG,gBAAA,GAAmB,UAAU,QAAQ,CAAA;AAAA,EAC1C,CAAC,CAAA;AACD,EAAAC,mBAAA,CAAgB,MAAM;AACpB,IAAA,EAAA,EAAI,mBAAA,GAAsB,UAAU,QAAQ,CAAA;AAAA,EAC9C,CAAC,CAAA;AAED,EAAA,OAAO,OAAA;AACT;;;AChCO,IAAM,qBAAA,GAAwB,wBAAA;AAG9B,IAAM,gBAAA,GAAmB;AAEhC,IAAM,GAAA,GAAM;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA,EAKT,gBAAgB,CAAA;AAAA;AAAA;AAAA;AAAA,GAAA,EAId,gBAAgB,CAAA;AAAA;AAAA,CAAA,CAEnB,IAAA,EAAK;AAEP,IAAI,SAAA,GAAY,KAAA;AAGT,SAAS,sBAAA,GAA+B;AAC7C,EAAA,IAAI,SAAA,EAAW;AACf,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACrC,EAAA,IAAI,QAAA,CAAS,cAAA,CAAe,qBAAqB,CAAA,EAAG;AAClD,IAAA,SAAA,GAAY,IAAA;AACZ,IAAA;AAAA,EACF;AACA,EAAA,MAAM,EAAA,GAAK,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AACzC,EAAA,EAAA,CAAG,EAAA,GAAK,qBAAA;AACR,EAAA,EAAA,CAAG,WAAA,GAAc,GAAA;AACjB,EAAA,QAAA,CAAS,IAAA,CAAK,YAAY,EAAE,CAAA;AAC5B,EAAA,SAAA,GAAY,IAAA;AACd;AAEO,SAAS,sBAAA,GAA+B;AAC7C,EAAA,SAAA,GAAY,KAAA;AACZ,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACnC,IAAA,QAAA,CAAS,cAAA,CAAe,qBAAqB,CAAA,EAAG,MAAA,EAAO;AAAA,EACzD;AACF;;;ACTO,SAAS,aAAa,KAAA,EAAiD;AAC5E,EAAAD,cAAU,sBAAsB,CAAA;AAChC,EAAA,MAAM,UAAU,uBAAA,EAAwB;AACxC,EAAA,MAAM,QAAQE,YAAA,CAAS,MAAMC,qBAAA,CAAiB,KAAA,EAAO,CAAC,CAAA;AACtD,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,SAAA,EAAWD,YAAA,CAAS,MAAM,KAAA,CAAM,UAAU,SAAS,CAAA;AAAA,IACnD,QAAA,EAAU,KAAA;AAAA,IACV,UAAA,EAAYA,aAAS,OAAO;AAAA,MAC1B,KAAA,EAAO,OAAA,CAAQ,KAAA,GAAQ,EAAA,GAAK,gBAAA;AAAA,MAC5B,mBAAmB,KAAA,CAAM;AAAA,KAC3B,CAAE;AAAA,GACJ;AACF","file":"motion.cjs","sourcesContent":["import { onBeforeUnmount, onMounted, ref, type Ref } from 'vue'\n\nconst QUERY = '(prefers-reduced-motion: reduce)'\n\nfunction read(): boolean {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return false\n return window.matchMedia(QUERY).matches\n}\n\n/**\n * Reactive `prefers-reduced-motion` flag. Returns `false` where `matchMedia`\n * is unavailable (SSR / older jsdom) so animation is the safe default only when\n * the user has not asked to reduce it.\n */\nexport function usePrefersReducedMotion(): Ref<boolean> {\n const reduced = ref<boolean>(read())\n let mq: MediaQueryList | null = null\n const onChange = () => {\n if (mq) reduced.value = mq.matches\n }\n\n onMounted(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return\n mq = window.matchMedia(QUERY)\n reduced.value = mq.matches\n mq.addEventListener?.('change', onChange)\n })\n onBeforeUnmount(() => {\n mq?.removeEventListener?.('change', onChange)\n })\n\n return reduced\n}\n","export const __DATA_STATE_STYLE_ID = 'iris-data-state-styles'\n\n/** Class applied to a state node so its entry cross-fades in. */\nexport const DATA_STATE_CLASS = 'iris-data-state-enter'\n\nconst CSS = `\n@keyframes iris-data-state-enter {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: none; }\n}\n.${DATA_STATE_CLASS} {\n animation: iris-data-state-enter var(--iris-duration-md, 200ms) ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .${DATA_STATE_CLASS} { animation: none; }\n}\n`.trim()\n\nlet installed = false\n\n/** Idempotently inject the data-state enter keyframes (SSR-safe no-op). */\nexport function installDataStateStyles(): void {\n if (installed) return\n if (typeof document === 'undefined') return\n if (document.getElementById(__DATA_STATE_STYLE_ID)) {\n installed = true\n return\n }\n const el = document.createElement('style')\n el.id = __DATA_STATE_STYLE_ID\n el.textContent = CSS\n document.head.appendChild(el)\n installed = true\n}\n\nexport function __resetDataStateStyles(): void {\n installed = false\n if (typeof document !== 'undefined') {\n document.getElementById(__DATA_STATE_STYLE_ID)?.remove()\n }\n}\n","import { computed, onMounted, type ComputedRef } from 'vue'\nimport { resolveDataState, type DataState, type DataStateInput } from '@iris-ui-kit/core'\nimport { DATA_STATE_CLASS, installDataStateStyles } from './styles'\nimport { usePrefersReducedMotion } from './usePrefersReducedMotion'\n\nexport interface DataStateNodeProps {\n class: string\n 'data-iris-state': DataState\n}\n\nexport interface UseDataStateReturn {\n /** Resolved state (`error → loading → empty → content` precedence). */\n state: ComputedRef<DataState>\n /** `true` when the host should render its real content. */\n isContent: ComputedRef<boolean>\n /** Use as the vnode `key` of the state node so the enter animation replays on each transition. */\n stateKey: ComputedRef<DataState>\n /** Spread onto the rendered loading/error/empty node. */\n stateProps: ComputedRef<DataStateNodeProps>\n}\n\n/**\n * State-transition + entry-animation composable for data components. Resolves\n * the active {@link DataState} from a reactive `{ loading, error, empty }`\n * getter, and returns props for the state node that (a) re-key on every\n * transition so the cross-fade replays and (b) drop the animation class when\n * the user prefers reduced motion.\n *\n * The framework-agnostic precedence lives in `@iris-ui-kit/core`'s\n * {@link resolveDataState}; this composable is the thin Vue animation bridge.\n */\nexport function useDataState(input: () => DataStateInput): UseDataStateReturn {\n onMounted(installDataStateStyles)\n const reduced = usePrefersReducedMotion()\n const state = computed(() => resolveDataState(input()))\n return {\n state,\n isContent: computed(() => state.value === 'content'),\n stateKey: state,\n stateProps: computed(() => ({\n class: reduced.value ? '' : DATA_STATE_CLASS,\n 'data-iris-state': state.value,\n })),\n }\n}\n"]}
@@ -0,0 +1,43 @@
1
+ import { Ref, ComputedRef } from 'vue';
2
+ import { DataState, DataStateInput } from '@iris-ui-kit/core';
3
+
4
+ /**
5
+ * Reactive `prefers-reduced-motion` flag. Returns `false` where `matchMedia`
6
+ * is unavailable (SSR / older jsdom) so animation is the safe default only when
7
+ * the user has not asked to reduce it.
8
+ */
9
+ declare function usePrefersReducedMotion(): Ref<boolean>;
10
+
11
+ interface DataStateNodeProps {
12
+ class: string;
13
+ 'data-iris-state': DataState;
14
+ }
15
+ interface UseDataStateReturn {
16
+ /** Resolved state (`error → loading → empty → content` precedence). */
17
+ state: ComputedRef<DataState>;
18
+ /** `true` when the host should render its real content. */
19
+ isContent: ComputedRef<boolean>;
20
+ /** Use as the vnode `key` of the state node so the enter animation replays on each transition. */
21
+ stateKey: ComputedRef<DataState>;
22
+ /** Spread onto the rendered loading/error/empty node. */
23
+ stateProps: ComputedRef<DataStateNodeProps>;
24
+ }
25
+ /**
26
+ * State-transition + entry-animation composable for data components. Resolves
27
+ * the active {@link DataState} from a reactive `{ loading, error, empty }`
28
+ * getter, and returns props for the state node that (a) re-key on every
29
+ * transition so the cross-fade replays and (b) drop the animation class when
30
+ * the user prefers reduced motion.
31
+ *
32
+ * The framework-agnostic precedence lives in `@iris-ui-kit/core`'s
33
+ * {@link resolveDataState}; this composable is the thin Vue animation bridge.
34
+ */
35
+ declare function useDataState(input: () => DataStateInput): UseDataStateReturn;
36
+
37
+ /** Class applied to a state node so its entry cross-fades in. */
38
+ declare const DATA_STATE_CLASS = "iris-data-state-enter";
39
+ /** Idempotently inject the data-state enter keyframes (SSR-safe no-op). */
40
+ declare function installDataStateStyles(): void;
41
+ declare function __resetDataStateStyles(): void;
42
+
43
+ export { DATA_STATE_CLASS, type DataStateNodeProps, type UseDataStateReturn, __resetDataStateStyles, installDataStateStyles, useDataState, usePrefersReducedMotion };
@@ -0,0 +1,43 @@
1
+ import { Ref, ComputedRef } from 'vue';
2
+ import { DataState, DataStateInput } from '@iris-ui-kit/core';
3
+
4
+ /**
5
+ * Reactive `prefers-reduced-motion` flag. Returns `false` where `matchMedia`
6
+ * is unavailable (SSR / older jsdom) so animation is the safe default only when
7
+ * the user has not asked to reduce it.
8
+ */
9
+ declare function usePrefersReducedMotion(): Ref<boolean>;
10
+
11
+ interface DataStateNodeProps {
12
+ class: string;
13
+ 'data-iris-state': DataState;
14
+ }
15
+ interface UseDataStateReturn {
16
+ /** Resolved state (`error → loading → empty → content` precedence). */
17
+ state: ComputedRef<DataState>;
18
+ /** `true` when the host should render its real content. */
19
+ isContent: ComputedRef<boolean>;
20
+ /** Use as the vnode `key` of the state node so the enter animation replays on each transition. */
21
+ stateKey: ComputedRef<DataState>;
22
+ /** Spread onto the rendered loading/error/empty node. */
23
+ stateProps: ComputedRef<DataStateNodeProps>;
24
+ }
25
+ /**
26
+ * State-transition + entry-animation composable for data components. Resolves
27
+ * the active {@link DataState} from a reactive `{ loading, error, empty }`
28
+ * getter, and returns props for the state node that (a) re-key on every
29
+ * transition so the cross-fade replays and (b) drop the animation class when
30
+ * the user prefers reduced motion.
31
+ *
32
+ * The framework-agnostic precedence lives in `@iris-ui-kit/core`'s
33
+ * {@link resolveDataState}; this composable is the thin Vue animation bridge.
34
+ */
35
+ declare function useDataState(input: () => DataStateInput): UseDataStateReturn;
36
+
37
+ /** Class applied to a state node so its entry cross-fades in. */
38
+ declare const DATA_STATE_CLASS = "iris-data-state-enter";
39
+ /** Idempotently inject the data-state enter keyframes (SSR-safe no-op). */
40
+ declare function installDataStateStyles(): void;
41
+ declare function __resetDataStateStyles(): void;
42
+
43
+ export { DATA_STATE_CLASS, type DataStateNodeProps, type UseDataStateReturn, __resetDataStateStyles, installDataStateStyles, useDataState, usePrefersReducedMotion };
package/dist/motion.js ADDED
@@ -0,0 +1,3 @@
1
+ export { DATA_STATE_CLASS, __resetDataStateStyles, installDataStateStyles, useDataState, usePrefersReducedMotion } from './chunk-S43IHHBU.js';
2
+ //# sourceMappingURL=motion.js.map
3
+ //# sourceMappingURL=motion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"motion.js"}
@@ -0,0 +1,272 @@
1
+ 'use strict';
2
+
3
+ var vue = require('vue');
4
+ var core = require('@iris-ui-kit/core');
5
+ var theme = require('@iris-ui-kit/theme');
6
+ var skins = require('@iris-ui-kit/skins');
7
+
8
+ // src/provider/IrisProvider.ts
9
+ var IrisThemeKey = /* @__PURE__ */ Symbol("IrisTheme");
10
+ var ThemeProvider = vue.defineComponent({
11
+ name: "IrisThemeProvider",
12
+ props: {
13
+ store: {
14
+ type: Object,
15
+ required: true
16
+ },
17
+ target: {
18
+ type: Object,
19
+ default: null
20
+ },
21
+ /** Writing direction; sets `dir` on the target for RTL. Default `'ltr'`. */
22
+ dir: {
23
+ type: String,
24
+ default: "ltr"
25
+ },
26
+ /** CSP nonce for injected inline stylesheets. */
27
+ cspNonce: {
28
+ type: String,
29
+ default: void 0
30
+ }
31
+ },
32
+ setup(props, { slots }) {
33
+ const current = vue.ref(props.store.store.getState());
34
+ const unsubscribe = props.store.store.subscribe((next) => {
35
+ current.value = next;
36
+ });
37
+ let applied = null;
38
+ let dirApplied = null;
39
+ const targetEl = () => props.target ?? document.documentElement;
40
+ const applyCurrent = () => {
41
+ applied?.revert();
42
+ applied = theme.applyTheme(current.value, targetEl());
43
+ };
44
+ const applyDir = () => {
45
+ dirApplied?.revert();
46
+ dirApplied = theme.applyDirection(props.dir, targetEl());
47
+ };
48
+ vue.onMounted(() => {
49
+ theme.injectGlobalStyles(props.cspNonce);
50
+ applyCurrent();
51
+ applyDir();
52
+ });
53
+ vue.watch(current, () => {
54
+ if (applied) applyCurrent();
55
+ });
56
+ vue.watch(
57
+ () => props.dir,
58
+ () => {
59
+ if (dirApplied) applyDir();
60
+ }
61
+ );
62
+ vue.onBeforeUnmount(() => {
63
+ unsubscribe();
64
+ applied?.revert();
65
+ applied = null;
66
+ dirApplied?.revert();
67
+ dirApplied = null;
68
+ });
69
+ vue.provide(IrisThemeKey, { store: props.store, current, dir: vue.computed(() => props.dir) });
70
+ return () => slots.default?.();
71
+ }
72
+ });
73
+ var IrisSkinKey = /* @__PURE__ */ Symbol("IrisSkin");
74
+ var SkinProvider = vue.defineComponent({
75
+ name: "IrisSkinProvider",
76
+ props: {
77
+ engine: { type: Object, required: true },
78
+ target: { type: Object, default: null },
79
+ cspNonce: { type: String, default: void 0 }
80
+ },
81
+ setup(props, { slots }) {
82
+ const current = vue.ref(props.engine.current());
83
+ const unsubscribe = props.engine.subscribe((next) => {
84
+ current.value = next;
85
+ });
86
+ let applied = null;
87
+ const targetEl = () => props.target ?? document.documentElement;
88
+ const apply = () => {
89
+ applied?.revert();
90
+ applied = skins.applySkin(current.value, targetEl());
91
+ };
92
+ vue.onMounted(() => {
93
+ theme.injectGlobalStyles(props.cspNonce);
94
+ apply();
95
+ });
96
+ vue.watch(current, () => {
97
+ if (applied) apply();
98
+ });
99
+ vue.onBeforeUnmount(() => {
100
+ unsubscribe();
101
+ applied?.revert();
102
+ applied = null;
103
+ });
104
+ vue.provide(IrisSkinKey, { engine: props.engine, current });
105
+ return () => slots.default?.();
106
+ }
107
+ });
108
+
109
+ // src/i18n/context.ts
110
+ var I18nInjectionKey = /* @__PURE__ */ Symbol("IrisI18n");
111
+
112
+ // src/i18n/I18nProvider.ts
113
+ var IrisI18nProvider = vue.defineComponent({
114
+ name: "IrisI18nProvider",
115
+ props: {
116
+ locale: { type: String, default: void 0 },
117
+ messages: { type: Object, default: void 0 },
118
+ i18n: { type: Object, default: void 0 },
119
+ /**
120
+ * When set, the locale's writing direction ({@link localeDirection}) is
121
+ * applied to `directionTarget` (`dir` + `data-iris-dir`) and `<html lang>`
122
+ * is set whenever `locale` changes — so "set locale → flip direction +
123
+ * announce language" needs no manual wiring. Off by default so it never
124
+ * fights an explicit `<ThemeProvider dir>`. Reverts on unmount.
125
+ */
126
+ autoDirection: { type: Boolean, default: false },
127
+ /** Element to receive dir/lang when `autoDirection` is set. Defaults to `document.documentElement`. */
128
+ directionTarget: { type: Object, default: void 0 }
129
+ },
130
+ setup(props, { slots }) {
131
+ const instance = props.i18n ?? core.createI18n({ locale: props.locale, messages: props.messages });
132
+ vue.provide(I18nInjectionKey, instance);
133
+ if (!props.i18n) {
134
+ vue.watch(
135
+ () => props.locale,
136
+ (locale) => {
137
+ if (locale) instance.setLocale(locale);
138
+ }
139
+ );
140
+ vue.watch(
141
+ () => props.messages,
142
+ (messages) => {
143
+ if (messages) instance.setMessages(messages);
144
+ }
145
+ );
146
+ }
147
+ let revertDirection = null;
148
+ vue.watch(
149
+ () => [props.autoDirection, props.locale, props.directionTarget],
150
+ ([autoDirection, locale]) => {
151
+ revertDirection?.();
152
+ revertDirection = null;
153
+ if (!autoDirection || !locale || typeof document === "undefined") return;
154
+ const el = props.directionTarget ?? document.documentElement;
155
+ const applied = theme.applyDirection(core.localeDirection(locale), el);
156
+ const prevLang = el.getAttribute("lang");
157
+ el.setAttribute("lang", locale);
158
+ revertDirection = () => {
159
+ applied.revert();
160
+ if (prevLang === null) el.removeAttribute("lang");
161
+ else el.setAttribute("lang", prevLang);
162
+ };
163
+ },
164
+ { immediate: true }
165
+ );
166
+ vue.onScopeDispose(() => {
167
+ revertDirection?.();
168
+ revertDirection = null;
169
+ });
170
+ return () => slots.default?.();
171
+ }
172
+ });
173
+
174
+ // src/provider/context.ts
175
+ var PluginStoreContextKey = /* @__PURE__ */ Symbol("IrisPluginStore");
176
+
177
+ // src/provider/IrisProvider.ts
178
+ var DEFAULT_LOCALE = "en-US";
179
+ var IrisProvider = vue.defineComponent({
180
+ name: "IrisProvider",
181
+ props: {
182
+ theme: { type: Object, default: void 0 },
183
+ skin: { type: Object, default: void 0 },
184
+ dir: { type: String, default: void 0 },
185
+ locale: { type: String, default: void 0 },
186
+ messages: { type: Object, default: void 0 },
187
+ plugins: { type: Array, default: void 0 },
188
+ target: { type: Object, default: null }
189
+ },
190
+ setup(props, { slots }) {
191
+ const collected = core.runPlugins(props.plugins ?? []);
192
+ let applied = null;
193
+ vue.onMounted(() => {
194
+ if (typeof document === "undefined") return;
195
+ const el = props.target ?? document.documentElement;
196
+ applied = theme.applyCssVars(Object.entries(collected.tokens), el);
197
+ });
198
+ vue.onBeforeUnmount(() => {
199
+ applied?.revert();
200
+ applied = null;
201
+ collected.teardown();
202
+ });
203
+ vue.provide(PluginStoreContextKey, {
204
+ stores: collected.stores,
205
+ installed: new Set((props.plugins ?? []).map((p) => p.name))
206
+ });
207
+ return () => {
208
+ const locale = props.locale ?? DEFAULT_LOCALE;
209
+ const messages = { ...collected.messages[locale], ...props.messages ?? {} };
210
+ let tree = vue.h(
211
+ IrisI18nProvider,
212
+ { locale: props.locale, messages },
213
+ { default: () => slots.default?.() }
214
+ );
215
+ if (props.skin) {
216
+ tree = vue.h(
217
+ SkinProvider,
218
+ { engine: props.skin, target: props.target },
219
+ { default: () => tree }
220
+ );
221
+ }
222
+ if (props.theme) {
223
+ tree = vue.h(
224
+ ThemeProvider,
225
+ { store: props.theme, target: props.target, dir: props.dir ?? "ltr" },
226
+ { default: () => tree }
227
+ );
228
+ }
229
+ return tree;
230
+ };
231
+ }
232
+ });
233
+ function usePlugin(name) {
234
+ const ctx = vue.inject(PluginStoreContextKey, null);
235
+ return ctx ? ctx.installed.has(name) : false;
236
+ }
237
+ var warnedKeys = /* @__PURE__ */ new Map();
238
+ function usePluginStore(nsOrKey, key) {
239
+ const ctx = vue.inject(PluginStoreContextKey, null);
240
+ if (!ctx) {
241
+ const displayKey = key !== void 0 ? `${nsOrKey}::${key}` : nsOrKey;
242
+ throw new Error(`[iris-ui] usePluginStore("${displayKey}"): no <IrisProvider> ancestor found`);
243
+ }
244
+ const fullKey = key !== void 0 ? `${nsOrKey}::${key}` : nsOrKey;
245
+ let store = ctx.stores.get(fullKey);
246
+ if (store !== void 0) return store;
247
+ if (key === void 0) {
248
+ store = ctx.stores.get(nsOrKey);
249
+ if (store !== void 0) return store;
250
+ for (const k of ctx.stores.keys()) {
251
+ if (typeof k === "string" && k.endsWith(`::${nsOrKey}`)) {
252
+ if (!warnedKeys.has(nsOrKey)) {
253
+ warnedKeys.set(nsOrKey, true);
254
+ console.warn(
255
+ `[iris-ui] Ambiguous plugin store key "${nsOrKey}". Found "${k}". Use the namespaced form: usePluginStore("${k}").`
256
+ );
257
+ }
258
+ return ctx.stores.get(k);
259
+ }
260
+ }
261
+ }
262
+ throw new Error(
263
+ `[iris-ui] Plugin store "${fullKey}" not found. Ensure the plugin is installed in IrisProvider and the key is correct.`
264
+ );
265
+ }
266
+
267
+ exports.IrisProvider = IrisProvider;
268
+ exports.PluginStoreContextKey = PluginStoreContextKey;
269
+ exports.usePlugin = usePlugin;
270
+ exports.usePluginStore = usePluginStore;
271
+ //# sourceMappingURL=provider.cjs.map
272
+ //# sourceMappingURL=provider.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/theme/ThemeProvider.ts","../src/skins/SkinProvider.ts","../src/i18n/context.ts","../src/i18n/I18nProvider.ts","../src/provider/context.ts","../src/provider/IrisProvider.ts","../src/provider/hooks.ts"],"names":["defineComponent","ref","applyTheme","applyDirection","onMounted","injectGlobalStyles","watch","onBeforeUnmount","provide","computed","applySkin","createI18n","localeDirection","onScopeDispose","runPlugins","applyCssVars","h","inject"],"mappings":"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","file":"provider.cjs","sourcesContent":["import {\n computed,\n defineComponent,\n inject,\n onBeforeUnmount,\n onMounted,\n provide,\n ref,\n watch,\n type ComputedRef,\n type InjectionKey,\n type PropType,\n type Ref,\n} from 'vue'\nimport {\n applyDirection,\n applyTheme,\n injectGlobalStyles,\n type ApplyDirectionResult,\n type ApplyThemeResult,\n type Direction,\n type ThemeStore,\n} from '@iris-ui-kit/theme'\nimport type { IrisTheme } from '@iris-ui-kit/tokens'\n\nexport interface IrisThemeContext {\n store: ThemeStore\n current: Ref<IrisTheme>\n dir: ComputedRef<Direction>\n}\n\nexport const IrisThemeKey: InjectionKey<IrisThemeContext> = Symbol('IrisTheme')\n\n/**\n * Renderless provider that:\n * 1. exposes the theme store to descendants via `provide`,\n * 2. applies the current theme to a target element on mount and on change,\n * 3. reverts the inline custom properties on unmount.\n *\n * `target` defaults to `document.documentElement`. Pass an element ref to\n * scope a theme to a subtree.\n */\nexport const ThemeProvider = defineComponent({\n name: 'IrisThemeProvider',\n props: {\n store: {\n type: Object as PropType<ThemeStore>,\n required: true,\n },\n target: {\n type: Object as PropType<HTMLElement | null>,\n default: null,\n },\n /** Writing direction; sets `dir` on the target for RTL. Default `'ltr'`. */\n dir: {\n type: String as PropType<Direction>,\n default: 'ltr',\n },\n /** CSP nonce for injected inline stylesheets. */\n cspNonce: {\n type: String,\n default: undefined,\n },\n },\n setup(props, { slots }) {\n const current = ref(props.store.store.getState()) as Ref<IrisTheme>\n const unsubscribe = props.store.store.subscribe((next) => {\n current.value = next\n })\n\n let applied: ApplyThemeResult | null = null\n let dirApplied: ApplyDirectionResult | null = null\n\n const targetEl = () => props.target ?? document.documentElement\n\n const applyCurrent = () => {\n applied?.revert()\n applied = applyTheme(current.value, targetEl())\n }\n\n const applyDir = () => {\n dirApplied?.revert()\n dirApplied = applyDirection(props.dir, targetEl())\n }\n\n onMounted(() => {\n injectGlobalStyles(props.cspNonce)\n applyCurrent()\n applyDir()\n })\n\n watch(current, () => {\n if (applied) applyCurrent()\n })\n\n watch(\n () => props.dir,\n () => {\n if (dirApplied) applyDir()\n },\n )\n\n onBeforeUnmount(() => {\n unsubscribe()\n applied?.revert()\n applied = null\n dirApplied?.revert()\n dirApplied = null\n })\n\n provide(IrisThemeKey, { store: props.store, current, dir: computed(() => props.dir) })\n\n return () => slots.default?.()\n },\n})\n\nexport function useThemeContext(): IrisThemeContext {\n const ctx = inject(IrisThemeKey)\n if (!ctx) {\n throw new Error('[iris-ui] useTheme(): no <ThemeProvider> ancestor found')\n }\n return ctx\n}\n\n/**\n * Current writing direction (`'ltr'` / `'rtl'`) from the nearest\n * `<ThemeProvider>`, or a static `'ltr'` ref when there is none.\n */\nexport function useDirection(): ComputedRef<Direction> {\n const ctx = inject(IrisThemeKey, null)\n return ctx ? ctx.dir : computed(() => 'ltr' as Direction)\n}\n","import {\n defineComponent,\n inject,\n onBeforeUnmount,\n onMounted,\n provide,\n ref,\n watch,\n type InjectionKey,\n type PropType,\n type Ref,\n} from 'vue'\nimport { injectGlobalStyles } from '@iris-ui-kit/theme'\nimport {\n applySkin,\n type ApplySkinResult,\n type ResolvedSkin,\n type SkinEngine,\n} from '@iris-ui-kit/skins'\n\nexport interface IrisSkinContext {\n engine: SkinEngine\n current: Ref<ResolvedSkin>\n}\n\nexport const IrisSkinKey: InjectionKey<IrisSkinContext> = Symbol('IrisSkin')\n\n/**\n * Renderless provider mirroring `<IrisThemeProvider>` for skins: subscribes to\n * the engine store, applies/reverts the resolved skin on the target element,\n * and provides the engine + current skin to descendants. Zero skin logic.\n */\nexport const SkinProvider = defineComponent({\n name: 'IrisSkinProvider',\n props: {\n engine: { type: Object as PropType<SkinEngine>, required: true },\n target: { type: Object as PropType<HTMLElement | null>, default: null },\n cspNonce: { type: String, default: undefined },\n },\n setup(props, { slots }) {\n const current = ref(props.engine.current()) as Ref<ResolvedSkin>\n const unsubscribe = props.engine.subscribe((next) => {\n current.value = next\n })\n\n let applied: ApplySkinResult | null = null\n const targetEl = () => props.target ?? document.documentElement\n const apply = () => {\n applied?.revert()\n applied = applySkin(current.value, targetEl())\n }\n\n onMounted(() => {\n injectGlobalStyles(props.cspNonce)\n apply()\n })\n watch(current, () => {\n if (applied) apply()\n })\n onBeforeUnmount(() => {\n unsubscribe()\n applied?.revert()\n applied = null\n })\n\n provide(IrisSkinKey, { engine: props.engine, current })\n return () => slots.default?.()\n },\n})\n\nexport function useSkinContext(): IrisSkinContext {\n const ctx = inject(IrisSkinKey)\n if (!ctx) throw new Error('[iris-ui] useSkin(): no <SkinProvider> ancestor found')\n return ctx\n}\n","import { type InjectionKey } from 'vue'\nimport type { I18n } from '@iris-ui-kit/core'\n\n/** Injection key carrying the active {@link I18n} instance to `useI18n`. */\nexport const I18nInjectionKey: InjectionKey<I18n> = Symbol('IrisI18n')\n","import { defineComponent, onScopeDispose, provide, watch, type PropType } from 'vue'\nimport { createI18n, localeDirection, type I18n, type I18nMessages } from '@iris-ui-kit/core'\nimport { applyDirection } from '@iris-ui-kit/theme'\nimport { I18nInjectionKey } from './context'\n\n/**\n * Makes a locale + message dictionary available to descendant components via\n * `useI18n`. Pass `locale` / `messages` (an instance is created and kept in\n * sync) or a pre-built `i18n` instance you control externally. Renderless:\n * renders its default slot.\n */\nexport const IrisI18nProvider = defineComponent({\n name: 'IrisI18nProvider',\n props: {\n locale: { type: String, default: undefined },\n messages: { type: Object as PropType<I18nMessages>, default: undefined },\n i18n: { type: Object as PropType<I18n>, default: undefined },\n /**\n * When set, the locale's writing direction ({@link localeDirection}) is\n * applied to `directionTarget` (`dir` + `data-iris-dir`) and `<html lang>`\n * is set whenever `locale` changes — so \"set locale → flip direction +\n * announce language\" needs no manual wiring. Off by default so it never\n * fights an explicit `<ThemeProvider dir>`. Reverts on unmount.\n */\n autoDirection: { type: Boolean, default: false },\n /** Element to receive dir/lang when `autoDirection` is set. Defaults to `document.documentElement`. */\n directionTarget: { type: Object as PropType<HTMLElement | null>, default: undefined },\n },\n setup(props, { slots }) {\n const instance = props.i18n ?? createI18n({ locale: props.locale, messages: props.messages })\n provide(I18nInjectionKey, instance)\n\n if (!props.i18n) {\n watch(\n () => props.locale,\n (locale) => {\n if (locale) instance.setLocale(locale)\n },\n )\n watch(\n () => props.messages,\n (messages) => {\n if (messages) instance.setMessages(messages)\n },\n )\n }\n\n // Auto-apply writing direction + `lang` from the active locale (opt-in).\n let revertDirection: (() => void) | null = null\n watch(\n () => [props.autoDirection, props.locale, props.directionTarget] as const,\n ([autoDirection, locale]) => {\n revertDirection?.()\n revertDirection = null\n if (!autoDirection || !locale || typeof document === 'undefined') return\n const el = props.directionTarget ?? document.documentElement\n const applied = applyDirection(localeDirection(locale), el)\n const prevLang = el.getAttribute('lang')\n el.setAttribute('lang', locale)\n revertDirection = () => {\n applied.revert()\n if (prevLang === null) el.removeAttribute('lang')\n else el.setAttribute('lang', prevLang)\n }\n },\n { immediate: true },\n )\n onScopeDispose(() => {\n revertDirection?.()\n revertDirection = null\n })\n\n return () => slots.default?.()\n },\n})\n","import { type InjectionKey } from 'vue'\n\n/**\n * Shape carried by the plugin-store context: the live store instances collected\n * from every installed plugin, plus the set of installed plugin names. Surfaced\n * to descendants through `usePluginStore` / `usePlugin`.\n */\nexport interface PluginStoreContext {\n stores: Map<string, unknown>\n installed: Set<string>\n}\n\n/**\n * Injection key for the {@link PluginStoreContext}. The name ends in `Key` (and\n * the type in `Context`) so the manifest's discover step never mistakes it for a\n * component export.\n */\nexport const PluginStoreContextKey: InjectionKey<PluginStoreContext> = Symbol('IrisPluginStore')\n","import {\n defineComponent,\n h,\n onBeforeUnmount,\n onMounted,\n provide,\n type PropType,\n type VNode,\n} from 'vue'\nimport { runPlugins, type IrisPlugin } from '@iris-ui-kit/core'\nimport { applyCssVars, type ApplyCssVarsResult, type ThemeStore } from '@iris-ui-kit/theme'\nimport type { SkinEngine } from '@iris-ui-kit/skins'\nimport { ThemeProvider } from '../theme'\nimport { SkinProvider } from '../skins'\nimport { IrisI18nProvider } from '../i18n'\nimport { PluginStoreContextKey } from './context'\n\nconst DEFAULT_LOCALE = 'en-US'\n\n/** Public prop surface of {@link IrisProvider}. */\nexport interface IrisProviderProps {\n /** Theme store; when present the inner `ThemeProvider` wraps the subtree. */\n theme?: ThemeStore\n /** Skin engine; when present the inner `SkinProvider` wraps the subtree. */\n skin?: SkinEngine\n /** Writing direction, forwarded to `ThemeProvider` when a theme is given. */\n dir?: 'ltr' | 'rtl'\n /** Active BCP-47 locale; defaults to `'en-US'`. */\n locale?: string\n /** User messages — merged OVER plugin-registered messages (user wins). */\n messages?: Record<string, string>\n /** Plugins to install; their tokens / messages / stores are collected once. */\n plugins?: IrisPlugin[]\n /** Element receiving the plugin token layer; defaults to `documentElement`. */\n target?: HTMLElement | null\n}\n\n/**\n * The single unified Iris entry point. Runs `plugins` through the core\n * `runPlugins` collector and wires the result into the theme (tokens), i18n\n * (messages) and a plugin-store context, composing the existing per-framework\n * providers. A thin bridge — the real logic lives in `@iris-ui-kit/core`.\n *\n * Render order when present: Theme → Skin → I18n → PluginContext → children.\n */\nexport const IrisProvider = defineComponent({\n name: 'IrisProvider',\n props: {\n theme: { type: Object as PropType<ThemeStore>, default: undefined },\n skin: { type: Object as PropType<SkinEngine>, default: undefined },\n dir: { type: String as PropType<'ltr' | 'rtl'>, default: undefined },\n locale: { type: String, default: undefined },\n messages: { type: Object as PropType<Record<string, string>>, default: undefined },\n plugins: { type: Array as PropType<IrisPlugin[]>, default: undefined },\n target: { type: Object as PropType<HTMLElement | null>, default: null },\n },\n setup(props, { slots }) {\n // Sync, pure, deterministic — computed once per setup over `plugins`.\n const collected = runPlugins(props.plugins ?? [])\n\n // tokens → additive CSS-var layer over the active theme; reverted on unmount.\n let applied: ApplyCssVarsResult | null = null\n onMounted(() => {\n if (typeof document === 'undefined') return\n const el = props.target ?? document.documentElement\n applied = applyCssVars(Object.entries(collected.tokens), el)\n })\n onBeforeUnmount(() => {\n applied?.revert()\n applied = null\n // Run plugin teardowns on unmount so eager stores / subscriptions /\n // timers don't leak. Idempotent and safe with no plugins.\n collected.teardown()\n })\n\n // stores + installed names → PluginStoreContext.\n provide(PluginStoreContextKey, {\n stores: collected.stores,\n installed: new Set((props.plugins ?? []).map((p) => p.name)),\n })\n\n return () => {\n const locale = props.locale ?? DEFAULT_LOCALE\n // Plugin messages as BASE, user messages WIN.\n const messages = { ...collected.messages[locale], ...(props.messages ?? {}) }\n\n // I18n always renders, wrapping children.\n let tree: VNode = h(\n IrisI18nProvider,\n { locale: props.locale, messages },\n { default: () => slots.default?.() },\n )\n // Skin wraps only when a `skin` engine is supplied.\n if (props.skin) {\n tree = h(\n SkinProvider,\n { engine: props.skin, target: props.target },\n { default: () => tree },\n )\n }\n // Theme wraps only when a `theme` store is supplied.\n if (props.theme) {\n tree = h(\n ThemeProvider,\n { store: props.theme, target: props.target, dir: props.dir ?? 'ltr' },\n { default: () => tree },\n )\n }\n return tree\n }\n },\n})\n","import { inject } from 'vue'\nimport { PluginStoreContextKey } from './context'\n\n/** Whether the named plugin is installed by the nearest `<IrisProvider>`. */\nexport function usePlugin(name: string): boolean {\n const ctx = inject(PluginStoreContextKey, null)\n return ctx ? ctx.installed.has(name) : false\n}\n\n// Tracks ambiguous store key warnings to avoid spamming the console.\nconst warnedKeys = new Map<string, boolean>()\n\n/**\n * Read a plugin-registered store by `key` (backward-compatible single-arg form).\n * Throws a clear error when used outside an `<IrisProvider>`.\n */\nexport function usePluginStore<T>(key: string): T\n\n/**\n * Read a plugin-registered store by `namespace` + `key`.\n */\nexport function usePluginStore<T>(namespace: string, key: string): T\n\nexport function usePluginStore<T>(nsOrKey: string, key?: string): T {\n const ctx = inject(PluginStoreContextKey, null)\n if (!ctx) {\n const displayKey = key !== undefined ? `${nsOrKey}::${key}` : nsOrKey\n throw new Error(`[iris-ui] usePluginStore(\"${displayKey}\"): no <IrisProvider> ancestor found`)\n }\n\n const fullKey = key !== undefined ? `${nsOrKey}::${key}` : nsOrKey\n\n // 1. Direct lookup\n let store = ctx.stores.get(fullKey) as T | undefined\n if (store !== undefined) return store\n\n // 2. Single-arg fallback\n if (key === undefined) {\n store = ctx.stores.get(nsOrKey) as T | undefined\n if (store !== undefined) return store\n\n for (const k of ctx.stores.keys()) {\n if (typeof k === 'string' && k.endsWith(`::${nsOrKey}`)) {\n // Warn at most once per ambiguous key.\n if (!warnedKeys.has(nsOrKey)) {\n warnedKeys.set(nsOrKey, true)\n console.warn(\n `[iris-ui] Ambiguous plugin store key \"${nsOrKey}\". ` +\n `Found \"${k}\". Use the namespaced form: usePluginStore(\"${k}\").`,\n )\n }\n return ctx.stores.get(k) as T\n }\n }\n }\n\n throw new Error(\n `[iris-ui] Plugin store \"${fullKey}\" not found. ` +\n `Ensure the plugin is installed in IrisProvider and the key is correct.`,\n )\n}\n"]}