@iris-ui-kit/react 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 (154) hide show
  1. package/LICENSE +21 -0
  2. package/dist/SidebarLayout-fWQRvK0a.d.cts +26 -0
  3. package/dist/SidebarLayout-fWQRvK0a.d.ts +26 -0
  4. package/dist/admin.cjs +1583 -0
  5. package/dist/admin.cjs.map +1 -0
  6. package/dist/admin.d.cts +183 -0
  7. package/dist/admin.d.ts +183 -0
  8. package/dist/admin.js +9 -0
  9. package/dist/admin.js.map +1 -0
  10. package/dist/async.cjs +97 -0
  11. package/dist/async.cjs.map +1 -0
  12. package/dist/async.d.cts +57 -0
  13. package/dist/async.d.ts +57 -0
  14. package/dist/async.js +5 -0
  15. package/dist/async.js.map +1 -0
  16. package/dist/behaviors.cjs +569 -0
  17. package/dist/behaviors.cjs.map +1 -0
  18. package/dist/behaviors.d.cts +188 -0
  19. package/dist/behaviors.d.ts +188 -0
  20. package/dist/behaviors.js +4 -0
  21. package/dist/behaviors.js.map +1 -0
  22. package/dist/chunk-2TQSTINK.js +541 -0
  23. package/dist/chunk-2TQSTINK.js.map +1 -0
  24. package/dist/chunk-53KFLVIZ.js +68 -0
  25. package/dist/chunk-53KFLVIZ.js.map +1 -0
  26. package/dist/chunk-6BMFMCMQ.js +140 -0
  27. package/dist/chunk-6BMFMCMQ.js.map +1 -0
  28. package/dist/chunk-AUA5GBT6.js +143 -0
  29. package/dist/chunk-AUA5GBT6.js.map +1 -0
  30. package/dist/chunk-DE6V6NOI.js +122 -0
  31. package/dist/chunk-DE6V6NOI.js.map +1 -0
  32. package/dist/chunk-HEJGN6UI.js +78 -0
  33. package/dist/chunk-HEJGN6UI.js.map +1 -0
  34. package/dist/chunk-IDD35UJ6.js +83 -0
  35. package/dist/chunk-IDD35UJ6.js.map +1 -0
  36. package/dist/chunk-J5FB2UB2.js +166 -0
  37. package/dist/chunk-J5FB2UB2.js.map +1 -0
  38. package/dist/chunk-OMOTUHYI.js +66 -0
  39. package/dist/chunk-OMOTUHYI.js.map +1 -0
  40. package/dist/chunk-RZNYIFV2.js +34 -0
  41. package/dist/chunk-RZNYIFV2.js.map +1 -0
  42. package/dist/chunk-SJO74IB3.js +54 -0
  43. package/dist/chunk-SJO74IB3.js.map +1 -0
  44. package/dist/chunk-SORLRLS4.js +53 -0
  45. package/dist/chunk-SORLRLS4.js.map +1 -0
  46. package/dist/chunk-TO7YVSAI.js +64 -0
  47. package/dist/chunk-TO7YVSAI.js.map +1 -0
  48. package/dist/chunk-TQ33XJIK.js +22 -0
  49. package/dist/chunk-TQ33XJIK.js.map +1 -0
  50. package/dist/chunk-UWUUEZCD.js +950 -0
  51. package/dist/chunk-UWUUEZCD.js.map +1 -0
  52. package/dist/chunk-VWCJJRSC.js +1200 -0
  53. package/dist/chunk-VWCJJRSC.js.map +1 -0
  54. package/dist/chunk-WIHBIDVJ.js +54 -0
  55. package/dist/chunk-WIHBIDVJ.js.map +1 -0
  56. package/dist/chunk-XCK4RIXB.js +66 -0
  57. package/dist/chunk-XCK4RIXB.js.map +1 -0
  58. package/dist/chunk-YAHXR2CJ.js +48 -0
  59. package/dist/chunk-YAHXR2CJ.js.map +1 -0
  60. package/dist/chunk-YXIO5THG.js +4 -0
  61. package/dist/chunk-YXIO5THG.js.map +1 -0
  62. package/dist/chunk-ZKBDUWUD.js +156 -0
  63. package/dist/chunk-ZKBDUWUD.js.map +1 -0
  64. package/dist/data.cjs +112 -0
  65. package/dist/data.cjs.map +1 -0
  66. package/dist/data.d.cts +53 -0
  67. package/dist/data.d.ts +53 -0
  68. package/dist/data.js +5 -0
  69. package/dist/data.js.map +1 -0
  70. package/dist/error-boundary.cjs +106 -0
  71. package/dist/error-boundary.cjs.map +1 -0
  72. package/dist/error-boundary.d.cts +41 -0
  73. package/dist/error-boundary.d.ts +41 -0
  74. package/dist/error-boundary.js +6 -0
  75. package/dist/error-boundary.js.map +1 -0
  76. package/dist/floating.cjs +163 -0
  77. package/dist/floating.cjs.map +1 -0
  78. package/dist/floating.d.cts +92 -0
  79. package/dist/floating.d.ts +92 -0
  80. package/dist/floating.js +5 -0
  81. package/dist/floating.js.map +1 -0
  82. package/dist/form.cjs +159 -0
  83. package/dist/form.cjs.map +1 -0
  84. package/dist/form.d.cts +120 -0
  85. package/dist/form.d.ts +120 -0
  86. package/dist/form.js +5 -0
  87. package/dist/form.js.map +1 -0
  88. package/dist/i18n.cjs +100 -0
  89. package/dist/i18n.cjs.map +1 -0
  90. package/dist/i18n.d.cts +50 -0
  91. package/dist/i18n.d.ts +50 -0
  92. package/dist/i18n.js +5 -0
  93. package/dist/i18n.js.map +1 -0
  94. package/dist/index.cjs +16635 -0
  95. package/dist/index.cjs.map +1 -0
  96. package/dist/index.d.cts +2964 -0
  97. package/dist/index.d.ts +2964 -0
  98. package/dist/index.js +12217 -0
  99. package/dist/index.js.map +1 -0
  100. package/dist/layouts.cjs +386 -0
  101. package/dist/layouts.cjs.map +1 -0
  102. package/dist/layouts.d.cts +92 -0
  103. package/dist/layouts.d.ts +92 -0
  104. package/dist/layouts.js +6 -0
  105. package/dist/layouts.js.map +1 -0
  106. package/dist/modal-utils.cjs +168 -0
  107. package/dist/modal-utils.cjs.map +1 -0
  108. package/dist/modal-utils.d.cts +43 -0
  109. package/dist/modal-utils.d.ts +43 -0
  110. package/dist/modal-utils.js +4 -0
  111. package/dist/modal-utils.js.map +1 -0
  112. package/dist/motion.cjs +104 -0
  113. package/dist/motion.cjs.map +1 -0
  114. package/dist/motion.d.cts +41 -0
  115. package/dist/motion.d.ts +41 -0
  116. package/dist/motion.js +4 -0
  117. package/dist/motion.js.map +1 -0
  118. package/dist/provider.cjs +191 -0
  119. package/dist/provider.cjs.map +1 -0
  120. package/dist/provider.d.cts +62 -0
  121. package/dist/provider.d.ts +62 -0
  122. package/dist/provider.js +8 -0
  123. package/dist/provider.js.map +1 -0
  124. package/dist/resource.cjs +61 -0
  125. package/dist/resource.cjs.map +1 -0
  126. package/dist/resource.d.cts +21 -0
  127. package/dist/resource.d.ts +21 -0
  128. package/dist/resource.js +5 -0
  129. package/dist/resource.js.map +1 -0
  130. package/dist/skeletons.cjs +1304 -0
  131. package/dist/skeletons.cjs.map +1 -0
  132. package/dist/skeletons.d.cts +70 -0
  133. package/dist/skeletons.d.ts +70 -0
  134. package/dist/skeletons.js +8 -0
  135. package/dist/skeletons.js.map +1 -0
  136. package/dist/skins.cjs +134 -0
  137. package/dist/skins.cjs.map +1 -0
  138. package/dist/skins.d.cts +45 -0
  139. package/dist/skins.d.ts +45 -0
  140. package/dist/skins.js +5 -0
  141. package/dist/skins.js.map +1 -0
  142. package/dist/theme.cjs +100 -0
  143. package/dist/theme.cjs.map +1 -0
  144. package/dist/theme.d.cts +71 -0
  145. package/dist/theme.d.ts +71 -0
  146. package/dist/theme.js +5 -0
  147. package/dist/theme.js.map +1 -0
  148. package/dist/undo.cjs +73 -0
  149. package/dist/undo.cjs.map +1 -0
  150. package/dist/undo.d.cts +47 -0
  151. package/dist/undo.d.ts +47 -0
  152. package/dist/undo.js +4 -0
  153. package/dist/undo.js.map +1 -0
  154. package/package.json +61 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/floating/useFloating.ts","../src/floating/useDismiss.ts"],"names":["React","offsetMiddleware","flipMiddleware","shiftMiddleware","sizeMiddleware","arrowMiddleware","computePosition","autoUpdate","React2"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA8EO,SAAS,YAAY,OAAA,EAAgD;AAC1E,EAAA,MAAM;AAAA,IACJ,MAAA;AAAA,IACA,QAAA;AAAA,IACA,IAAA;AAAA,IACA,SAAA,GAAY,QAAA;AAAA,IACZ,QAAA,GAAW,UAAA;AAAA,IACX,MAAA;AAAA,IACA,IAAA,GAAO,IAAA;AAAA,IACP,KAAA,GAAQ,IAAA;AAAA,IACR,IAAA,GAAO,KAAA;AAAA,IACP,UAAA,EAAY,eAAA;AAAA,IACZ;AAAA,GACF,GAAI,OAAA;AAEJ,EAAA,MAAM,CAAC,CAAA,EAAG,IAAI,CAAA,GAAUA,0BAAS,CAAC,CAAA;AAClC,EAAA,MAAM,CAAC,CAAA,EAAG,IAAI,CAAA,GAAUA,0BAAS,CAAC,CAAA;AAClC,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAUA,0BAAoB,SAAS,CAAA;AAC/E,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAUA,gBAAA,CAAA,QAAA,EAA6B;AAC/D,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAUA,gBAAA,CAAA,QAAA,EAA6B;AAE/D,EAAA,MAAM,UAAA,GAAmBA,yBAAsB,MAAM;AACnD,IAAA,MAAM,KAAmB,EAAC;AAC1B,IAAA,IAAI,WAAW,MAAA,EAAW,EAAA,CAAG,IAAA,CAAKC,UAAA,CAAiB,MAAM,CAAC,CAAA;AAC1D,IAAA,IAAI,IAAA,EAAM,EAAA,CAAG,IAAA,CAAKC,QAAA,EAAgB,CAAA;AAClC,IAAA,IAAI,KAAA,KAAU,IAAA,CAAKC,SAAA,CAAgB,EAAE,OAAA,EAAS,CAAA,EAAG,CAAC,CAAA;AAClD,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,MAAM,OAAA,GAAU,OAAO,IAAA,KAAS,QAAA,GAAW,IAAA,GAAO,CAAA;AAClD,MAAA,EAAA,CAAG,IAAA;AAAA,QACDC,QAAA,CAAe;AAAA,UACb,OAAA;AAAA,UACA,KAAA,CAAM,EAAE,cAAA,EAAgB,eAAA,EAAiB,UAAS,EAAG;AACnD,YAAA,MAAA,CAAO,MAAA,CAAO,QAAA,CAAS,QAAA,CAAS,KAAA,EAAO;AAAA,cACrC,QAAA,EAAU,GAAG,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,KAAA,CAAM,cAAc,CAAC,CAAC,CAAA,EAAA,CAAA;AAAA,cACpD,SAAA,EAAW,GAAG,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,KAAA,CAAM,eAAe,CAAC,CAAC,CAAA,EAAA;AAAA,aACvD,CAAA;AAAA,UACH;AAAA,SACD;AAAA,OACH;AAAA,IACF;AACA,IAAA,IAAI,KAAA,EAAO,OAAA,EAAS,EAAA,CAAG,IAAA,CAAKC,SAAA,CAAgB,EAAE,OAAA,EAAS,KAAA,CAAM,OAAA,EAAS,CAAC,CAAA;AACvE,IAAA,IAAI,eAAA,EAAiB,EAAA,CAAG,IAAA,CAAK,GAAG,eAAe,CAAA;AAC/C,IAAA,OAAO,EAAA;AAAA,EACT,CAAA,EAAG,CAAC,MAAA,EAAQ,IAAA,EAAM,OAAO,IAAA,EAAM,eAAA,EAAiB,KAAK,CAAC,CAAA;AAItD,EAAA,MAAM,aAAA,GAAsBL,wBAAO,UAAU,CAAA;AAC7C,EAAA,aAAA,CAAc,OAAA,GAAU,UAAA;AAMxB,EAAA,MAAM,QAAA,GAAiBA,wBAAO,CAAC,CAAA;AAE/B,EAAA,MAAM,MAAA,GAAeA,6BAAY,YAAY;AAC3C,IAAA,MAAM,IAAI,MAAA,CAAO,OAAA;AACjB,IAAA,MAAM,IAAI,QAAA,CAAS,OAAA;AACnB,IAAA,IAAI,CAAC,CAAA,IAAK,CAAC,CAAA,EAAG;AACd,IAAA,MAAM,KAAA,GAAQ,EAAE,QAAA,CAAS,OAAA;AACzB,IAAA,MAAM,MAAA,GAAS,MAAMM,mBAAA,CAAgB,CAAA,EAAG,CAAA,EAAG;AAAA,MACzC,SAAA;AAAA,MACA,QAAA;AAAA,MACA,YAAY,aAAA,CAAc;AAAA,KAC3B,CAAA;AAED,IAAA,IAAI,KAAA,KAAU,SAAS,OAAA,EAAS;AAChC,IAAA,IAAA,CAAK,OAAO,CAAC,CAAA;AACb,IAAA,IAAA,CAAK,OAAO,CAAC,CAAA;AACb,IAAA,iBAAA,CAAkB,OAAO,SAAS,CAAA;AAClC,IAAA,MAAM,SAAA,GAAY,OAAO,cAAA,CAAe,KAAA;AACxC,IAAA,SAAA,CAAU,WAAW,CAAC,CAAA;AACtB,IAAA,SAAA,CAAU,WAAW,CAAC,CAAA;AAAA,EACxB,GAAG,CAAC,MAAA,EAAQ,QAAA,EAAU,SAAA,EAAW,QAAQ,CAAC,CAAA;AAE1C,EAAMN,2BAAU,MAAM;AACpB,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,IAAI,MAAA,CAAO,OAAA;AACjB,IAAA,MAAM,IAAI,QAAA,CAAS,OAAA;AACnB,IAAA,IAAI,CAAC,CAAA,IAAK,CAAC,CAAA,EAAG;AACd,IAAA,MAAM,OAAA,GAAUO,cAAA,CAAW,CAAA,EAAG,CAAA,EAAG,MAAM;AACrC,MAAA,KAAK,MAAA,EAAO;AAAA,IACd,CAAC,CAAA;AACD,IAAA,OAAO,MAAM;AAEX,MAAA,QAAA,CAAS,OAAA,EAAA;AACT,MAAA,OAAA,EAAQ;AAAA,IACV,CAAA;AAAA,EACF,GAAG,CAAC,IAAA,EAAM,MAAA,EAAQ,QAAA,EAAU,MAAM,CAAC,CAAA;AAEnC,EAAA,MAAM,cAAA,GAAuBP,gBAAA,CAAA,OAAA;AAAA,IAC3B,OAAO;AAAA,MACL,QAAA,EAAU,QAAA;AAAA,MACV,GAAA,EAAK,CAAA;AAAA,MACL,IAAA,EAAM,CAAA;AAAA,MACN,SAAA,EAAW,CAAA,YAAA,EAAe,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC,CAAA,IAAA,EAAO,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC,CAAA,MAAA,CAAA;AAAA,MAC3D,KAAA,EAAO;AAAA,KACT,CAAA;AAAA,IACA,CAAC,QAAA,EAAU,CAAA,EAAG,CAAC;AAAA,GACjB;AAEA,EAAA,MAAM,QAAA,GAAgE;AAAA,IACpE,GAAA,EAAK,QAAA;AAAA,IACL,MAAA,EAAQ,KAAA;AAAA,IACR,IAAA,EAAM,OAAA;AAAA,IACN,KAAA,EAAO;AAAA,GACT;AACA,EAAA,MAAM,YAAY,QAAA,CAAS,cAAA,CAAe,MAAM,GAAG,CAAA,CAAE,CAAC,CAAC,CAAA;AAOvD,EAAA,OAAO,EAAE,GAAG,CAAA,EAAG,QAAA,EAAU,gBAAgB,cAAA,EAAgB,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,SAAA,EAAU;AAC7F;ACzKO,SAAS,WAAW,OAAA,EAAkC;AAC3D,EAAA,MAAM,EAAE,OAAA,EAAS,MAAA,GAAS,IAAA,EAAM,kBAAA,GAAqB,MAAK,GAAI,OAAA;AAE9D,EAAA,MAAM,YAAA,GAAqBQ,gBAAA,CAAA,MAAA,CAAO,OAAA,CAAQ,SAAS,CAAA;AACnD,EAAA,MAAM,UAAA,GAAmBA,gBAAA,CAAA,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA;AAC/C,EAAMA,2BAAU,MAAM;AACpB,IAAA,YAAA,CAAa,UAAU,OAAA,CAAQ,SAAA;AAC/B,IAAA,UAAA,CAAW,UAAU,OAAA,CAAQ,OAAA;AAAA,EAC/B,CAAC,CAAA;AAED,EAAMA,2BAAU,MAAM;AACpB,IAAA,IAAI,CAAC,OAAA,IAAW,OAAO,QAAA,KAAa,WAAA,EAAa;AAEjD,IAAA,MAAM,UAAA,GAAa,CAAC,MAAA,KAAwC;AAC1D,MAAA,IAAI,CAAC,MAAA,IAAU,EAAE,MAAA,YAAkB,OAAO,OAAO,KAAA;AACjD,MAAA,KAAA,MAAW,CAAA,IAAK,WAAW,OAAA,EAAS;AAClC,QAAA,MAAM,KAAK,CAAA,CAAE,OAAA;AACb,QAAA,IAAI,OAAO,EAAA,KAAO,MAAA,IAAU,GAAG,QAAA,CAAS,MAAM,IAAI,OAAO,IAAA;AAAA,MAC3D;AACA,MAAA,OAAO,KAAA;AAAA,IACT,CAAA;AAEA,IAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAwB;AAC7C,MAAA,IAAI,UAAA,CAAW,KAAA,CAAM,MAAM,CAAA,EAAG;AAC9B,MAAA,YAAA,CAAa,OAAA,EAAQ;AAAA,IACvB,CAAA;AACA,IAAA,MAAM,SAAA,GAAY,CAAC,KAAA,KAAyB;AAC1C,MAAA,IAAI,KAAA,CAAM,QAAQ,QAAA,EAAU;AAC1B,QAAA,KAAA,CAAM,eAAA,EAAgB;AACtB,QAAA,YAAA,CAAa,OAAA,EAAQ;AAAA,MACvB;AAAA,IACF,CAAA;AAEA,IAAA,IAAI,kBAAA,EAAoB,QAAA,CAAS,gBAAA,CAAiB,aAAA,EAAe,eAAe,IAAI,CAAA;AACpF,IAAA,IAAI,MAAA,EAAQ,QAAA,CAAS,gBAAA,CAAiB,SAAA,EAAW,SAAS,CAAA;AAC1D,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,aAAA,EAAe,aAAA,EAAe,IAAI,CAAA;AAC/D,MAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,SAAS,CAAA;AAAA,IACnD,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,MAAA,EAAQ,kBAAkB,CAAC,CAAA;AAC1C","file":"floating.cjs","sourcesContent":["import * as React from 'react'\nimport {\n autoUpdate,\n computePosition,\n arrow as arrowMiddleware,\n flip as flipMiddleware,\n offset as offsetMiddleware,\n shift as shiftMiddleware,\n size as sizeMiddleware,\n type Middleware,\n type Placement,\n type Strategy,\n} from '@floating-ui/dom'\n\nexport interface UseFloatingOptions {\n /** Element the floating panel is positioned relative to. */\n anchor: React.RefObject<HTMLElement | null>\n /** The floating element itself. */\n floating: React.RefObject<HTMLElement | null>\n /** Whether the floating element is visible. Controls `autoUpdate` lifecycle. */\n open: boolean\n /** Default placement. Floating UI may flip it if `flip` is true. */\n placement?: Placement\n /** CSS position strategy. */\n strategy?: Strategy\n /** Pixel offset between anchor and floating element. */\n offset?: number\n /** Flip to the opposite side when the requested side overflows. Default `true`. */\n flip?: boolean\n /** Shift along the cross-axis to stay in view. Default `true`. */\n shift?: boolean\n /**\n * Constrain the floating element to the available viewport space — sets\n * `maxWidth`/`maxHeight` (minus 8px padding) on it so a long dropdown/popover\n * never overflows the screen (pair with `overflow:auto` for scroll). Off by\n * default. Pass a number to override the viewport padding.\n */\n size?: boolean | number\n /** Extra Floating UI middleware to append. */\n middleware?: Middleware[]\n /**\n * Optional ref to an arrow element inside the floating panel. When provided,\n * `arrowX`, `arrowY`, and `arrowSide` in the return value are populated by the\n * `@floating-ui/dom` arrow middleware so you can position the caret CSS.\n */\n arrow?: React.RefObject<HTMLElement | null>\n}\n\nexport interface UseFloatingReturn {\n x: number\n y: number\n strategy: Strategy\n finalPlacement: Placement\n /** Ready-to-bind inline style object for the floating element. */\n floatingStyles: React.CSSProperties\n /** Trigger a manual recompute. Usually not needed — `autoUpdate` handles scroll/resize. */\n update: () => Promise<void>\n /** Arrow x offset (px from floating start edge). Present when `arrow` option is set. */\n arrowX: number | undefined\n /** Arrow y offset (px from floating start edge). Present when `arrow` option is set. */\n arrowY: number | undefined\n /**\n * The side of the floating element the arrow is on — use as the CSS property\n * to apply `bottom: 0` / `top: 0` etc. to the arrow element.\n * E.g. `'bottom'` placement → arrow is on `'top'` of the floating element.\n */\n arrowSide: 'top' | 'right' | 'bottom' | 'left' | undefined\n}\n\n/**\n * Reactive Floating UI integration for React. Subscribes `autoUpdate`\n * whenever `open === true` and both refs are populated; tears it down on\n * close, unmount, or ref clearing.\n *\n * Pure positioning — does NOT render anything, does NOT manage focus,\n * does NOT handle dismiss behavior. Those concerns live in the consuming\n * primitive (Popover, Tooltip, Dialog, Menu, …).\n */\nexport function useFloating(options: UseFloatingOptions): UseFloatingReturn {\n const {\n anchor,\n floating,\n open,\n placement = 'bottom',\n strategy = 'absolute',\n offset,\n flip = true,\n shift = true,\n size = false,\n middleware: extraMiddleware,\n arrow,\n } = options\n\n const [x, setX] = React.useState(0)\n const [y, setY] = React.useState(0)\n const [finalPlacement, setFinalPlacement] = React.useState<Placement>(placement)\n const [arrowX, setArrowX] = React.useState<number | undefined>()\n const [arrowY, setArrowY] = React.useState<number | undefined>()\n\n const middleware = React.useMemo<Middleware[]>(() => {\n const mw: Middleware[] = []\n if (offset !== undefined) mw.push(offsetMiddleware(offset))\n if (flip) mw.push(flipMiddleware())\n if (shift) mw.push(shiftMiddleware({ padding: 8 }))\n if (size) {\n const padding = typeof size === 'number' ? size : 8\n mw.push(\n sizeMiddleware({\n padding,\n apply({ availableWidth, availableHeight, elements }) {\n Object.assign(elements.floating.style, {\n maxWidth: `${Math.max(0, Math.floor(availableWidth))}px`,\n maxHeight: `${Math.max(0, Math.floor(availableHeight))}px`,\n })\n },\n }),\n )\n }\n if (arrow?.current) mw.push(arrowMiddleware({ element: arrow.current }))\n if (extraMiddleware) mw.push(...extraMiddleware)\n return mw\n }, [offset, flip, shift, size, extraMiddleware, arrow])\n\n // Hold the latest middleware in a ref so `update` always sees current value\n // without being re-created (which would churn the autoUpdate subscription).\n const middlewareRef = React.useRef(middleware)\n middlewareRef.current = middleware\n\n // Monotonic token bumped on every new positioning cycle and on teardown.\n // `computePosition` is async; without this guard a result that resolves\n // after the panel closed/unmounted (or after a newer update started) would\n // apply stale coordinates and call setState on an unmounted component.\n const epochRef = React.useRef(0)\n\n const update = React.useCallback(async () => {\n const a = anchor.current\n const f = floating.current\n if (!a || !f) return\n const token = ++epochRef.current\n const result = await computePosition(a, f, {\n placement,\n strategy,\n middleware: middlewareRef.current,\n })\n // A newer update() started, or the effect tore down, while awaiting — drop.\n if (token !== epochRef.current) return\n setX(result.x)\n setY(result.y)\n setFinalPlacement(result.placement)\n const arrowData = result.middlewareData.arrow as { x?: number; y?: number } | undefined\n setArrowX(arrowData?.x)\n setArrowY(arrowData?.y)\n }, [anchor, floating, placement, strategy])\n\n React.useEffect(() => {\n if (!open) return\n const a = anchor.current\n const f = floating.current\n if (!a || !f) return\n const cleanup = autoUpdate(a, f, () => {\n void update()\n })\n return () => {\n // Invalidate any in-flight update() so its late result never lands.\n epochRef.current++\n cleanup()\n }\n }, [open, anchor, floating, update])\n\n const floatingStyles = React.useMemo<React.CSSProperties>(\n () => ({\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n width: 'max-content',\n }),\n [strategy, x, y],\n )\n\n const OPPOSITE: Record<string, 'top' | 'right' | 'bottom' | 'left'> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n }\n const arrowSide = OPPOSITE[finalPlacement.split('-')[0]] as\n | 'top'\n | 'right'\n | 'bottom'\n | 'left'\n | undefined\n\n return { x, y, strategy, finalPlacement, floatingStyles, update, arrowX, arrowY, arrowSide }\n}\n","import * as React from 'react'\n\nexport interface UseDismissOptions {\n /** While true, the dismiss listeners are active. */\n enabled: boolean\n /** Elements that, if clicked, should NOT trigger dismiss (typically trigger + content). */\n exclude: Array<React.RefObject<HTMLElement | null>>\n /** Called when the user attempts to dismiss the surface. */\n onDismiss: () => void\n /** Close on Escape key. Default `true`. */\n escape?: boolean\n /** Close on pointerdown outside the excluded elements. Default `true`. */\n outsidePointerDown?: boolean\n}\n\n/**\n * Listen for the universal \"dismiss\" gestures: Escape key and outside\n * pointer-down. Used by Popover / Menu / Dropdown. Tooltip does NOT use this —\n * it dismisses on mouseleave/blur instead.\n *\n * Listeners attach to `document` (pointerdown in the capture phase, mirroring\n * the Vue adapter) only while `enabled` is true, and detach on disable /\n * unmount. SSR-safe (no-op without `document`). The latest `onDismiss` /\n * `exclude` are read through refs so toggling them never re-subscribes.\n */\nexport function useDismiss(options: UseDismissOptions): void {\n const { enabled, escape = true, outsidePointerDown = true } = options\n\n const onDismissRef = React.useRef(options.onDismiss)\n const excludeRef = React.useRef(options.exclude)\n React.useEffect(() => {\n onDismissRef.current = options.onDismiss\n excludeRef.current = options.exclude\n })\n\n React.useEffect(() => {\n if (!enabled || typeof document === 'undefined') return\n\n const isExcluded = (target: EventTarget | null): boolean => {\n if (!target || !(target instanceof Node)) return false\n for (const r of excludeRef.current) {\n const el = r.current\n if (el && (el === target || el.contains(target))) return true\n }\n return false\n }\n\n const onPointerDown = (event: PointerEvent) => {\n if (isExcluded(event.target)) return\n onDismissRef.current()\n }\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.stopPropagation()\n onDismissRef.current()\n }\n }\n\n if (outsidePointerDown) document.addEventListener('pointerdown', onPointerDown, true)\n if (escape) document.addEventListener('keydown', onKeyDown)\n return () => {\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown)\n }\n }, [enabled, escape, outsidePointerDown])\n}\n"]}
@@ -0,0 +1,92 @@
1
+ import * as React from 'react';
2
+ import { Placement, Strategy, Middleware } from '@floating-ui/dom';
3
+
4
+ interface UseFloatingOptions {
5
+ /** Element the floating panel is positioned relative to. */
6
+ anchor: React.RefObject<HTMLElement | null>;
7
+ /** The floating element itself. */
8
+ floating: React.RefObject<HTMLElement | null>;
9
+ /** Whether the floating element is visible. Controls `autoUpdate` lifecycle. */
10
+ open: boolean;
11
+ /** Default placement. Floating UI may flip it if `flip` is true. */
12
+ placement?: Placement;
13
+ /** CSS position strategy. */
14
+ strategy?: Strategy;
15
+ /** Pixel offset between anchor and floating element. */
16
+ offset?: number;
17
+ /** Flip to the opposite side when the requested side overflows. Default `true`. */
18
+ flip?: boolean;
19
+ /** Shift along the cross-axis to stay in view. Default `true`. */
20
+ shift?: boolean;
21
+ /**
22
+ * Constrain the floating element to the available viewport space — sets
23
+ * `maxWidth`/`maxHeight` (minus 8px padding) on it so a long dropdown/popover
24
+ * never overflows the screen (pair with `overflow:auto` for scroll). Off by
25
+ * default. Pass a number to override the viewport padding.
26
+ */
27
+ size?: boolean | number;
28
+ /** Extra Floating UI middleware to append. */
29
+ middleware?: Middleware[];
30
+ /**
31
+ * Optional ref to an arrow element inside the floating panel. When provided,
32
+ * `arrowX`, `arrowY`, and `arrowSide` in the return value are populated by the
33
+ * `@floating-ui/dom` arrow middleware so you can position the caret CSS.
34
+ */
35
+ arrow?: React.RefObject<HTMLElement | null>;
36
+ }
37
+ interface UseFloatingReturn {
38
+ x: number;
39
+ y: number;
40
+ strategy: Strategy;
41
+ finalPlacement: Placement;
42
+ /** Ready-to-bind inline style object for the floating element. */
43
+ floatingStyles: React.CSSProperties;
44
+ /** Trigger a manual recompute. Usually not needed — `autoUpdate` handles scroll/resize. */
45
+ update: () => Promise<void>;
46
+ /** Arrow x offset (px from floating start edge). Present when `arrow` option is set. */
47
+ arrowX: number | undefined;
48
+ /** Arrow y offset (px from floating start edge). Present when `arrow` option is set. */
49
+ arrowY: number | undefined;
50
+ /**
51
+ * The side of the floating element the arrow is on — use as the CSS property
52
+ * to apply `bottom: 0` / `top: 0` etc. to the arrow element.
53
+ * E.g. `'bottom'` placement → arrow is on `'top'` of the floating element.
54
+ */
55
+ arrowSide: 'top' | 'right' | 'bottom' | 'left' | undefined;
56
+ }
57
+ /**
58
+ * Reactive Floating UI integration for React. Subscribes `autoUpdate`
59
+ * whenever `open === true` and both refs are populated; tears it down on
60
+ * close, unmount, or ref clearing.
61
+ *
62
+ * Pure positioning — does NOT render anything, does NOT manage focus,
63
+ * does NOT handle dismiss behavior. Those concerns live in the consuming
64
+ * primitive (Popover, Tooltip, Dialog, Menu, …).
65
+ */
66
+ declare function useFloating(options: UseFloatingOptions): UseFloatingReturn;
67
+
68
+ interface UseDismissOptions {
69
+ /** While true, the dismiss listeners are active. */
70
+ enabled: boolean;
71
+ /** Elements that, if clicked, should NOT trigger dismiss (typically trigger + content). */
72
+ exclude: Array<React.RefObject<HTMLElement | null>>;
73
+ /** Called when the user attempts to dismiss the surface. */
74
+ onDismiss: () => void;
75
+ /** Close on Escape key. Default `true`. */
76
+ escape?: boolean;
77
+ /** Close on pointerdown outside the excluded elements. Default `true`. */
78
+ outsidePointerDown?: boolean;
79
+ }
80
+ /**
81
+ * Listen for the universal "dismiss" gestures: Escape key and outside
82
+ * pointer-down. Used by Popover / Menu / Dropdown. Tooltip does NOT use this —
83
+ * it dismisses on mouseleave/blur instead.
84
+ *
85
+ * Listeners attach to `document` (pointerdown in the capture phase, mirroring
86
+ * the Vue adapter) only while `enabled` is true, and detach on disable /
87
+ * unmount. SSR-safe (no-op without `document`). The latest `onDismiss` /
88
+ * `exclude` are read through refs so toggling them never re-subscribes.
89
+ */
90
+ declare function useDismiss(options: UseDismissOptions): void;
91
+
92
+ export { type UseDismissOptions, type UseFloatingOptions, type UseFloatingReturn, useDismiss, useFloating };
@@ -0,0 +1,92 @@
1
+ import * as React from 'react';
2
+ import { Placement, Strategy, Middleware } from '@floating-ui/dom';
3
+
4
+ interface UseFloatingOptions {
5
+ /** Element the floating panel is positioned relative to. */
6
+ anchor: React.RefObject<HTMLElement | null>;
7
+ /** The floating element itself. */
8
+ floating: React.RefObject<HTMLElement | null>;
9
+ /** Whether the floating element is visible. Controls `autoUpdate` lifecycle. */
10
+ open: boolean;
11
+ /** Default placement. Floating UI may flip it if `flip` is true. */
12
+ placement?: Placement;
13
+ /** CSS position strategy. */
14
+ strategy?: Strategy;
15
+ /** Pixel offset between anchor and floating element. */
16
+ offset?: number;
17
+ /** Flip to the opposite side when the requested side overflows. Default `true`. */
18
+ flip?: boolean;
19
+ /** Shift along the cross-axis to stay in view. Default `true`. */
20
+ shift?: boolean;
21
+ /**
22
+ * Constrain the floating element to the available viewport space — sets
23
+ * `maxWidth`/`maxHeight` (minus 8px padding) on it so a long dropdown/popover
24
+ * never overflows the screen (pair with `overflow:auto` for scroll). Off by
25
+ * default. Pass a number to override the viewport padding.
26
+ */
27
+ size?: boolean | number;
28
+ /** Extra Floating UI middleware to append. */
29
+ middleware?: Middleware[];
30
+ /**
31
+ * Optional ref to an arrow element inside the floating panel. When provided,
32
+ * `arrowX`, `arrowY`, and `arrowSide` in the return value are populated by the
33
+ * `@floating-ui/dom` arrow middleware so you can position the caret CSS.
34
+ */
35
+ arrow?: React.RefObject<HTMLElement | null>;
36
+ }
37
+ interface UseFloatingReturn {
38
+ x: number;
39
+ y: number;
40
+ strategy: Strategy;
41
+ finalPlacement: Placement;
42
+ /** Ready-to-bind inline style object for the floating element. */
43
+ floatingStyles: React.CSSProperties;
44
+ /** Trigger a manual recompute. Usually not needed — `autoUpdate` handles scroll/resize. */
45
+ update: () => Promise<void>;
46
+ /** Arrow x offset (px from floating start edge). Present when `arrow` option is set. */
47
+ arrowX: number | undefined;
48
+ /** Arrow y offset (px from floating start edge). Present when `arrow` option is set. */
49
+ arrowY: number | undefined;
50
+ /**
51
+ * The side of the floating element the arrow is on — use as the CSS property
52
+ * to apply `bottom: 0` / `top: 0` etc. to the arrow element.
53
+ * E.g. `'bottom'` placement → arrow is on `'top'` of the floating element.
54
+ */
55
+ arrowSide: 'top' | 'right' | 'bottom' | 'left' | undefined;
56
+ }
57
+ /**
58
+ * Reactive Floating UI integration for React. Subscribes `autoUpdate`
59
+ * whenever `open === true` and both refs are populated; tears it down on
60
+ * close, unmount, or ref clearing.
61
+ *
62
+ * Pure positioning — does NOT render anything, does NOT manage focus,
63
+ * does NOT handle dismiss behavior. Those concerns live in the consuming
64
+ * primitive (Popover, Tooltip, Dialog, Menu, …).
65
+ */
66
+ declare function useFloating(options: UseFloatingOptions): UseFloatingReturn;
67
+
68
+ interface UseDismissOptions {
69
+ /** While true, the dismiss listeners are active. */
70
+ enabled: boolean;
71
+ /** Elements that, if clicked, should NOT trigger dismiss (typically trigger + content). */
72
+ exclude: Array<React.RefObject<HTMLElement | null>>;
73
+ /** Called when the user attempts to dismiss the surface. */
74
+ onDismiss: () => void;
75
+ /** Close on Escape key. Default `true`. */
76
+ escape?: boolean;
77
+ /** Close on pointerdown outside the excluded elements. Default `true`. */
78
+ outsidePointerDown?: boolean;
79
+ }
80
+ /**
81
+ * Listen for the universal "dismiss" gestures: Escape key and outside
82
+ * pointer-down. Used by Popover / Menu / Dropdown. Tooltip does NOT use this —
83
+ * it dismisses on mouseleave/blur instead.
84
+ *
85
+ * Listeners attach to `document` (pointerdown in the capture phase, mirroring
86
+ * the Vue adapter) only while `enabled` is true, and detach on disable /
87
+ * unmount. SSR-safe (no-op without `document`). The latest `onDismiss` /
88
+ * `exclude` are read through refs so toggling them never re-subscribes.
89
+ */
90
+ declare function useDismiss(options: UseDismissOptions): void;
91
+
92
+ export { type UseDismissOptions, type UseFloatingOptions, type UseFloatingReturn, useDismiss, useFloating };
@@ -0,0 +1,5 @@
1
+ 'use client'
2
+ import './chunk-YXIO5THG.js';
3
+ export { useDismiss, useFloating } from './chunk-6BMFMCMQ.js';
4
+ //# sourceMappingURL=floating.js.map
5
+ //# sourceMappingURL=floating.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":";","file":"floating.js"}
package/dist/form.cjs ADDED
@@ -0,0 +1,159 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ var React = require('react');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var core = require('@iris-ui-kit/core');
7
+
8
+ function _interopNamespace(e) {
9
+ if (e && e.__esModule) return e;
10
+ var n = Object.create(null);
11
+ if (e) {
12
+ Object.keys(e).forEach(function (k) {
13
+ if (k !== 'default') {
14
+ var d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: function () { return e[k]; }
18
+ });
19
+ }
20
+ });
21
+ }
22
+ n.default = e;
23
+ return Object.freeze(n);
24
+ }
25
+
26
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
27
+
28
+ // src/form/Form.tsx
29
+ var FormContext = React__namespace.createContext(null);
30
+ function useFormContext() {
31
+ const ctx = React__namespace.useContext(FormContext);
32
+ if (!ctx) {
33
+ throw new Error("useField / useFormContext must be used within an <IrisForm>");
34
+ }
35
+ return ctx;
36
+ }
37
+ function focusFirstError(formEl, errors) {
38
+ if (!formEl) return;
39
+ const keys = Object.keys(errors);
40
+ if (keys.length === 0) return;
41
+ const controls = formEl.querySelectorAll(
42
+ "input[name], select[name], textarea[name], [data-iris-field]"
43
+ );
44
+ for (const el of Array.from(controls)) {
45
+ const name = el.getAttribute("name") ?? el.getAttribute("data-iris-field");
46
+ if (name && keys.includes(name)) {
47
+ el.focus();
48
+ try {
49
+ el.scrollIntoView({ block: "center" });
50
+ } catch {
51
+ }
52
+ return;
53
+ }
54
+ }
55
+ }
56
+ function IrisForm({ form, children, ...rest }) {
57
+ const formRef = React__namespace.useRef(null);
58
+ return /* @__PURE__ */ jsxRuntime.jsx(FormContext.Provider, { value: form, children: /* @__PURE__ */ jsxRuntime.jsx(
59
+ "form",
60
+ {
61
+ ...rest,
62
+ ref: formRef,
63
+ "data-iris-form": "",
64
+ onSubmit: (event) => {
65
+ event.preventDefault();
66
+ void form.handleSubmit().then(() => focusFirstError(formRef.current, form.getState().errors));
67
+ },
68
+ children
69
+ }
70
+ ) });
71
+ }
72
+ function useStore(store) {
73
+ return React.useSyncExternalStore(
74
+ store.subscribe,
75
+ store.getState,
76
+ store.getState
77
+ // SSR fallback — same as client snapshot in our case.
78
+ );
79
+ }
80
+
81
+ // src/form/useForm.ts
82
+ function useForm(config) {
83
+ const latest = React__namespace.useRef(config);
84
+ latest.current = config;
85
+ const ref = React__namespace.useRef(null);
86
+ if (ref.current === null) {
87
+ ref.current = core.createFormStore({
88
+ initialValues: config.initialValues,
89
+ validators: config.validators,
90
+ validateOnChange: config.validateOnChange,
91
+ validateOnBlur: config.validateOnBlur,
92
+ validate: (values) => latest.current.validate?.(values) ?? {},
93
+ onSubmit: (values) => latest.current.onSubmit?.(values)
94
+ });
95
+ }
96
+ const form = ref.current;
97
+ const state = useStore(form.store);
98
+ return {
99
+ ...state,
100
+ store: form.store,
101
+ form,
102
+ isValid: Object.keys(state.errors).length === 0,
103
+ setFieldValue: form.setFieldValue,
104
+ setValues: form.setValues,
105
+ setFieldTouched: form.setFieldTouched,
106
+ setFieldError: form.setFieldError,
107
+ setErrors: form.setErrors,
108
+ validateField: form.validateField,
109
+ validateForm: form.validateForm,
110
+ handleSubmit: form.handleSubmit,
111
+ reset: form.reset
112
+ };
113
+ }
114
+ function useField(name) {
115
+ const form = useFormContext();
116
+ const state = useStore(form.store);
117
+ const key = core.formatPath(name);
118
+ const value = core.getByPath(state.values, name);
119
+ return {
120
+ name,
121
+ value,
122
+ error: state.errors[key],
123
+ touched: Boolean(state.touched[key]),
124
+ dirty: Boolean(state.dirty[key]),
125
+ setValue: (next) => form.setFieldValue(name, next),
126
+ setTouched: (touched = true) => form.setFieldTouched(name, touched),
127
+ inputProps: {
128
+ name,
129
+ value: value ?? "",
130
+ onChange: (event) => form.setFieldValue(name, event.target.value),
131
+ onBlur: () => form.setFieldTouched(name, true)
132
+ }
133
+ };
134
+ }
135
+
136
+ // src/form/useFieldArray.ts
137
+ function useFieldArray(name) {
138
+ const form = useFormContext();
139
+ const state = useStore(form.store);
140
+ const fields = Array.isArray(state.values[name]) ? state.values[name] : [];
141
+ return {
142
+ name,
143
+ fields,
144
+ push: (item) => form.arrayPush(name, item),
145
+ remove: (index) => form.arrayRemove(name, index),
146
+ insert: (index, item) => form.arrayInsert(name, index, item),
147
+ move: (from, to) => form.arrayMove(name, from, to),
148
+ replace: (items) => form.setFieldValue(name, items)
149
+ };
150
+ }
151
+
152
+ exports.FormContext = FormContext;
153
+ exports.IrisForm = IrisForm;
154
+ exports.useField = useField;
155
+ exports.useFieldArray = useFieldArray;
156
+ exports.useForm = useForm;
157
+ exports.useFormContext = useFormContext;
158
+ //# sourceMappingURL=form.cjs.map
159
+ //# sourceMappingURL=form.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/form/context.ts","../src/form/Form.tsx","../src/useStore.ts","../src/form/useForm.ts","../src/form/useField.ts","../src/form/useFieldArray.ts"],"names":["React","React2","jsx","useSyncExternalStore","React4","createFormStore","formatPath","getByPath"],"mappings":"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","file":"form.cjs","sourcesContent":["import * as React from 'react'\nimport type { FormStore, FormValues } from '@iris-ui-kit/core'\n\n/**\n * Carries the active form's {@link FormStore} down to descendant fields so\n * `useField` can bind without prop drilling. The generic is erased at the\n * context boundary; `useField<T>` re-applies the value type at the call site.\n */\nexport const FormContext = React.createContext<FormStore<FormValues> | null>(null)\n\nexport function useFormContext(): FormStore<FormValues> {\n const ctx = React.useContext(FormContext)\n if (!ctx) {\n throw new Error('useField / useFormContext must be used within an <IrisForm>')\n }\n return ctx\n}\n","import * as React from 'react'\nimport type { FormStore, FormValues } from '@iris-ui-kit/core'\nimport { FormContext } from './context'\n\n/** Focus (and best-effort scroll to) the first errored named control in DOM order. */\nfunction focusFirstError(\n formEl: HTMLFormElement | null,\n errors: Record<string, string | undefined>,\n): void {\n if (!formEl) return\n const keys = Object.keys(errors)\n if (keys.length === 0) return\n const controls = formEl.querySelectorAll<HTMLElement>(\n 'input[name], select[name], textarea[name], [data-iris-field]',\n )\n for (const el of Array.from(controls)) {\n const name = el.getAttribute('name') ?? el.getAttribute('data-iris-field')\n if (name && keys.includes(name)) {\n el.focus()\n try {\n el.scrollIntoView({ block: 'center' })\n } catch {\n /* scrollIntoView is unavailable in jsdom — focus is the contract */\n }\n return\n }\n }\n}\n\nexport interface IrisFormProps<V extends FormValues> extends Omit<\n React.FormHTMLAttributes<HTMLFormElement>,\n 'onSubmit'\n> {\n /** The store from `useForm(...).form`. */\n form: FormStore<V>\n children?: React.ReactNode\n}\n\n/**\n * Provides the form store to descendant `useField` calls and wires the native\n * `<form>` submit to `handleSubmit` (with `preventDefault`).\n *\n * @example\n * const f = useForm({ initialValues: { email: '' }, onSubmit })\n * <IrisForm form={f.form}>\n * <IrisFormField label=\"Email\"><EmailField /></IrisFormField>\n * <IrisButton type=\"submit\" disabled={f.isSubmitting}>Save</IrisButton>\n * </IrisForm>\n */\nexport function IrisForm<V extends FormValues>({ form, children, ...rest }: IrisFormProps<V>) {\n const formRef = React.useRef<HTMLFormElement | null>(null)\n return (\n <FormContext.Provider value={form as unknown as FormStore<FormValues>}>\n <form\n {...rest}\n ref={formRef}\n data-iris-form=\"\"\n onSubmit={(event) => {\n event.preventDefault()\n // On a failed submit, move focus to the first errored field (a11y).\n void form\n .handleSubmit()\n .then(() => focusFirstError(formRef.current, form.getState().errors))\n }}\n >\n {children}\n </form>\n </FormContext.Provider>\n )\n}\n","import * as React from 'react'\nimport { useSyncExternalStore } from 'react'\nimport type { ReadonlyStore, Store } from '@iris-ui-kit/core'\n\n/**\n * Bridge a framework-agnostic `@iris-ui-kit/core` store into React reactivity.\n * Uses React 18's `useSyncExternalStore` — the contract is identical to the\n * one Vue uses via `ref + onMounted` and Solid uses via `createSignal`. The\n * **same** store can power Button, Popover, Dialog, etc. on any framework.\n */\nexport function useStore<T>(store: ReadonlyStore<T>): T {\n return useSyncExternalStore(\n store.subscribe,\n store.getState,\n store.getState, // SSR fallback — same as client snapshot in our case.\n )\n}\n\n/**\n * Subscribe to a DERIVED slice of a core store — the component re-renders only\n * when `selector(state)` changes per `isEqual` (default `Object.is`), not on\n * every store emission. Built on {@link Store.subscribeWith}. Inline closures\n * for `selector`/`isEqual` are fine (captured via refs; the subscription is not\n * re-created between renders).\n */\nexport function useStoreSelector<T, U>(\n store: Store<T>,\n selector: (state: T) => U,\n isEqual?: (a: U, b: U) => boolean,\n): U {\n const [slice, setSlice] = React.useState(() => selector(store.getState()))\n const selRef = React.useRef(selector)\n selRef.current = selector\n const eqRef = React.useRef(isEqual)\n eqRef.current = isEqual\n React.useEffect(() => {\n const read = (s: T): U => selRef.current(s)\n const eq = (a: U, b: U): boolean => (eqRef.current ?? Object.is)(a, b)\n // Re-sync in case the store moved between render and this effect.\n setSlice((prev) => {\n const next = read(store.getState())\n return eq(prev, next) ? prev : next\n })\n return store.subscribeWith(read, setSlice, eq)\n }, [store])\n return slice\n}\n","import * as React from 'react'\nimport {\n createFormStore,\n type FormConfig,\n type FormState,\n type FormStore,\n type FormValues,\n} from '@iris-ui-kit/core'\nimport { useStore } from '../useStore'\n\nexport interface UseFormReturn<V extends FormValues> extends FormState<V> {\n /** Underlying subscribable store. */\n store: FormStore<V>['store']\n /** The form store itself — pass to `<IrisForm form={...}>`. */\n form: FormStore<V>\n isValid: boolean\n setFieldValue: FormStore<V>['setFieldValue']\n setValues: FormStore<V>['setValues']\n setFieldTouched: FormStore<V>['setFieldTouched']\n setFieldError: FormStore<V>['setFieldError']\n setErrors: FormStore<V>['setErrors']\n validateField: FormStore<V>['validateField']\n validateForm: FormStore<V>['validateForm']\n handleSubmit: FormStore<V>['handleSubmit']\n reset: FormStore<V>['reset']\n}\n\n/**\n * React binding for the framework-agnostic form engine. Instantiates the store\n * once (like `useState`'s lazy initializer) and bridges it into React via\n * `useSyncExternalStore`. `initialValues` / `validators` / timing are captured\n * on first render; `onSubmit` and `validate` are read through a ref each render\n * so they always see the latest closures (no stale-callback footgun).\n */\nexport function useForm<V extends FormValues>(config: FormConfig<V>): UseFormReturn<V> {\n const latest = React.useRef(config)\n latest.current = config\n\n const ref = React.useRef<FormStore<V> | null>(null)\n if (ref.current === null) {\n ref.current = createFormStore<V>({\n initialValues: config.initialValues,\n validators: config.validators,\n validateOnChange: config.validateOnChange,\n validateOnBlur: config.validateOnBlur,\n validate: (values) => latest.current.validate?.(values) ?? {},\n onSubmit: (values) => latest.current.onSubmit?.(values),\n })\n }\n const form = ref.current\n const state = useStore(form.store)\n\n return {\n ...state,\n store: form.store,\n form,\n isValid: Object.keys(state.errors).length === 0,\n setFieldValue: form.setFieldValue,\n setValues: form.setValues,\n setFieldTouched: form.setFieldTouched,\n setFieldError: form.setFieldError,\n setErrors: form.setErrors,\n validateField: form.validateField,\n validateForm: form.validateForm,\n handleSubmit: form.handleSubmit,\n reset: form.reset,\n }\n}\n","import * as React from 'react'\nimport { formatPath, getByPath } from '@iris-ui-kit/core'\nimport { useStore } from '../useStore'\nimport { useFormContext } from './context'\n\nexport interface FieldInputProps {\n name: string\n value: string\n onChange: (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void\n onBlur: () => void\n}\n\nexport interface UseFieldReturn<T> {\n name: string\n value: T\n error: string | undefined\n touched: boolean\n dirty: boolean\n setValue: (value: T) => void\n setTouched: (touched?: boolean) => void\n /**\n * Convenience bundle for a native text input / textarea. Spread onto\n * `IrisInput` / `IrisTextarea`. Non-text controls (checkbox, select,\n * number, custom) should wire `value` + `setValue` directly.\n */\n inputProps: FieldInputProps\n}\n\n/**\n * Binds a single field to the surrounding `<IrisForm>`. Re-renders only its\n * host component when the form store changes. `T` is the value type at the\n * call site (the context erases the form's generic).\n *\n * `name` may be a flat top-level key (`'email'`) OR a nested PATH\n * (`'address.city'`, `'items[2].sku'`) — the form keys its per-field state by\n * the canonical path, so a flat key is just a 1-segment path and stays 100%\n * back-compatible (v3 R19).\n */\nexport function useField<T = unknown>(name: string): UseFieldReturn<T> {\n const form = useFormContext()\n const state = useStore(form.store)\n // Canonical key for per-field state lookups (a flat key maps to itself).\n const key = formatPath(name)\n const value = getByPath(state.values, name) as T\n\n return {\n name,\n value,\n error: state.errors[key],\n touched: Boolean(state.touched[key]),\n dirty: Boolean(state.dirty[key]),\n setValue: (next) => form.setFieldValue(name, next as never),\n setTouched: (touched = true) => form.setFieldTouched(name, touched),\n inputProps: {\n name,\n value: (value ?? '') as string,\n onChange: (event) => form.setFieldValue(name, event.target.value as never),\n onBlur: () => form.setFieldTouched(name, true),\n },\n }\n}\n","import { useStore } from '../useStore'\nimport { useFormContext } from './context'\n\nexport interface UseFieldArrayReturn<T> {\n name: string\n /** Current array value (reactive). */\n fields: T[]\n /** Append an item. */\n push: (item: T) => void\n /** Remove the item at `index`. */\n remove: (index: number) => void\n /** Insert `item` at `index` (shifting the rest right). */\n insert: (index: number, item: T) => void\n /** Move the item from `from` to `to`. */\n move: (from: number, to: number) => void\n /** Replace the whole array. */\n replace: (items: T[]) => void\n}\n\n/**\n * Manage a dynamic array field (repeatable rows) inside an `<IrisForm>`. Mutators\n * delegate to the core {@link FormStore} array helpers (`arrayPush`/`arrayInsert`/\n * `arrayRemove`/`arrayMove`), which RE-KEY each element's error/touched/dirty/\n * validating state across the mutation — so a row's per-element validation state\n * FOLLOWS the row when rows are removed or reordered (removing `items[0]` shifts\n * `items[2]`'s error down to `items[1]`). `replace` swaps the whole array.\n *\n * ```tsx\n * const items = useFieldArray<{ sku: string }>('items')\n * items.fields.map((_, i) => <SkuRow key={i} index={i} />)\n * <button onClick={() => items.push({ sku: '' })}>Add</button>\n * ```\n */\nexport function useFieldArray<T = unknown>(name: string): UseFieldArrayReturn<T> {\n const form = useFormContext()\n const state = useStore(form.store)\n const fields = (Array.isArray(state.values[name]) ? state.values[name] : []) as T[]\n\n return {\n name,\n fields,\n push: (item) => form.arrayPush(name as never, item as never),\n remove: (index) => form.arrayRemove(name as never, index),\n insert: (index, item) => form.arrayInsert(name as never, index, item as never),\n move: (from, to) => form.arrayMove(name as never, from, to),\n replace: (items) => form.setFieldValue(name, items as never),\n }\n}\n"]}
@@ -0,0 +1,120 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { FormValues, FormStore, FormState, FormConfig } from '@iris-ui-kit/core';
4
+
5
+ interface IrisFormProps<V extends FormValues> extends Omit<React.FormHTMLAttributes<HTMLFormElement>, 'onSubmit'> {
6
+ /** The store from `useForm(...).form`. */
7
+ form: FormStore<V>;
8
+ children?: React.ReactNode;
9
+ }
10
+ /**
11
+ * Provides the form store to descendant `useField` calls and wires the native
12
+ * `<form>` submit to `handleSubmit` (with `preventDefault`).
13
+ *
14
+ * @example
15
+ * const f = useForm({ initialValues: { email: '' }, onSubmit })
16
+ * <IrisForm form={f.form}>
17
+ * <IrisFormField label="Email"><EmailField /></IrisFormField>
18
+ * <IrisButton type="submit" disabled={f.isSubmitting}>Save</IrisButton>
19
+ * </IrisForm>
20
+ */
21
+ declare function IrisForm<V extends FormValues>({ form, children, ...rest }: IrisFormProps<V>): react_jsx_runtime.JSX.Element;
22
+
23
+ interface UseFormReturn<V extends FormValues> extends FormState<V> {
24
+ /** Underlying subscribable store. */
25
+ store: FormStore<V>['store'];
26
+ /** The form store itself — pass to `<IrisForm form={...}>`. */
27
+ form: FormStore<V>;
28
+ isValid: boolean;
29
+ setFieldValue: FormStore<V>['setFieldValue'];
30
+ setValues: FormStore<V>['setValues'];
31
+ setFieldTouched: FormStore<V>['setFieldTouched'];
32
+ setFieldError: FormStore<V>['setFieldError'];
33
+ setErrors: FormStore<V>['setErrors'];
34
+ validateField: FormStore<V>['validateField'];
35
+ validateForm: FormStore<V>['validateForm'];
36
+ handleSubmit: FormStore<V>['handleSubmit'];
37
+ reset: FormStore<V>['reset'];
38
+ }
39
+ /**
40
+ * React binding for the framework-agnostic form engine. Instantiates the store
41
+ * once (like `useState`'s lazy initializer) and bridges it into React via
42
+ * `useSyncExternalStore`. `initialValues` / `validators` / timing are captured
43
+ * on first render; `onSubmit` and `validate` are read through a ref each render
44
+ * so they always see the latest closures (no stale-callback footgun).
45
+ */
46
+ declare function useForm<V extends FormValues>(config: FormConfig<V>): UseFormReturn<V>;
47
+
48
+ interface FieldInputProps {
49
+ name: string;
50
+ value: string;
51
+ onChange: (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
52
+ onBlur: () => void;
53
+ }
54
+ interface UseFieldReturn<T> {
55
+ name: string;
56
+ value: T;
57
+ error: string | undefined;
58
+ touched: boolean;
59
+ dirty: boolean;
60
+ setValue: (value: T) => void;
61
+ setTouched: (touched?: boolean) => void;
62
+ /**
63
+ * Convenience bundle for a native text input / textarea. Spread onto
64
+ * `IrisInput` / `IrisTextarea`. Non-text controls (checkbox, select,
65
+ * number, custom) should wire `value` + `setValue` directly.
66
+ */
67
+ inputProps: FieldInputProps;
68
+ }
69
+ /**
70
+ * Binds a single field to the surrounding `<IrisForm>`. Re-renders only its
71
+ * host component when the form store changes. `T` is the value type at the
72
+ * call site (the context erases the form's generic).
73
+ *
74
+ * `name` may be a flat top-level key (`'email'`) OR a nested PATH
75
+ * (`'address.city'`, `'items[2].sku'`) — the form keys its per-field state by
76
+ * the canonical path, so a flat key is just a 1-segment path and stays 100%
77
+ * back-compatible (v3 R19).
78
+ */
79
+ declare function useField<T = unknown>(name: string): UseFieldReturn<T>;
80
+
81
+ interface UseFieldArrayReturn<T> {
82
+ name: string;
83
+ /** Current array value (reactive). */
84
+ fields: T[];
85
+ /** Append an item. */
86
+ push: (item: T) => void;
87
+ /** Remove the item at `index`. */
88
+ remove: (index: number) => void;
89
+ /** Insert `item` at `index` (shifting the rest right). */
90
+ insert: (index: number, item: T) => void;
91
+ /** Move the item from `from` to `to`. */
92
+ move: (from: number, to: number) => void;
93
+ /** Replace the whole array. */
94
+ replace: (items: T[]) => void;
95
+ }
96
+ /**
97
+ * Manage a dynamic array field (repeatable rows) inside an `<IrisForm>`. Mutators
98
+ * delegate to the core {@link FormStore} array helpers (`arrayPush`/`arrayInsert`/
99
+ * `arrayRemove`/`arrayMove`), which RE-KEY each element's error/touched/dirty/
100
+ * validating state across the mutation — so a row's per-element validation state
101
+ * FOLLOWS the row when rows are removed or reordered (removing `items[0]` shifts
102
+ * `items[2]`'s error down to `items[1]`). `replace` swaps the whole array.
103
+ *
104
+ * ```tsx
105
+ * const items = useFieldArray<{ sku: string }>('items')
106
+ * items.fields.map((_, i) => <SkuRow key={i} index={i} />)
107
+ * <button onClick={() => items.push({ sku: '' })}>Add</button>
108
+ * ```
109
+ */
110
+ declare function useFieldArray<T = unknown>(name: string): UseFieldArrayReturn<T>;
111
+
112
+ /**
113
+ * Carries the active form's {@link FormStore} down to descendant fields so
114
+ * `useField` can bind without prop drilling. The generic is erased at the
115
+ * context boundary; `useField<T>` re-applies the value type at the call site.
116
+ */
117
+ declare const FormContext: React.Context<FormStore<FormValues> | null>;
118
+ declare function useFormContext(): FormStore<FormValues>;
119
+
120
+ export { type FieldInputProps, FormContext, IrisForm, type IrisFormProps, type UseFieldArrayReturn, type UseFieldReturn, type UseFormReturn, useField, useFieldArray, useForm, useFormContext };