@vielzeug/refine 2.0.2 → 2.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 (100) hide show
  1. package/dist/combobox.cjs +1 -1
  2. package/dist/combobox.cjs.map +1 -1
  3. package/dist/combobox.js +1 -1
  4. package/dist/combobox.js.map +1 -1
  5. package/dist/content/text/text.css.cjs +1 -1
  6. package/dist/content/text/text.css.cjs.map +1 -1
  7. package/dist/content/text/text.css.js +1 -1
  8. package/dist/content/text/text.css.js.map +1 -1
  9. package/dist/content/text/text.d.ts +1 -1
  10. package/dist/content/text/text.d.ts.map +1 -1
  11. package/dist/core/choice-field.cjs +1 -1
  12. package/dist/core/choice-field.cjs.map +1 -1
  13. package/dist/core/choice-field.d.ts.map +1 -1
  14. package/dist/core/choice-field.js +18 -17
  15. package/dist/core/choice-field.js.map +1 -1
  16. package/dist/core/focus.cjs +1 -1
  17. package/dist/core/focus.cjs.map +1 -1
  18. package/dist/core/focus.d.ts +5 -0
  19. package/dist/core/focus.d.ts.map +1 -1
  20. package/dist/core/focus.js +12 -5
  21. package/dist/core/focus.js.map +1 -1
  22. package/dist/core/index.d.ts +3 -3
  23. package/dist/core/index.d.ts.map +1 -1
  24. package/dist/core/option-list.cjs +1 -1
  25. package/dist/core/option-list.cjs.map +1 -1
  26. package/dist/core/option-list.d.ts +5 -0
  27. package/dist/core/option-list.d.ts.map +1 -1
  28. package/dist/core/option-list.js +20 -13
  29. package/dist/core/option-list.js.map +1 -1
  30. package/dist/core/overlay.cjs +1 -1
  31. package/dist/core/overlay.cjs.map +1 -1
  32. package/dist/core/overlay.d.ts +10 -4
  33. package/dist/core/overlay.d.ts.map +1 -1
  34. package/dist/core/overlay.js +1 -1
  35. package/dist/core/overlay.js.map +1 -1
  36. package/dist/core/positioner.cjs +1 -1
  37. package/dist/core/positioner.cjs.map +1 -1
  38. package/dist/core/positioner.d.ts +6 -1
  39. package/dist/core/positioner.d.ts.map +1 -1
  40. package/dist/core/positioner.js +11 -11
  41. package/dist/core/positioner.js.map +1 -1
  42. package/dist/custom-elements.json +6719 -6688
  43. package/dist/frameworks/elements.d.ts +86 -0
  44. package/dist/frameworks/react.d.ts +18 -0
  45. package/dist/frameworks/vue.d.ts +16 -0
  46. package/dist/inputs/button/button.css.cjs +1 -1
  47. package/dist/inputs/button/button.css.cjs.map +1 -1
  48. package/dist/inputs/button/button.css.js +1 -1
  49. package/dist/inputs/button/button.css.js.map +1 -1
  50. package/dist/inputs/select/select.d.ts.map +1 -1
  51. package/dist/menu.cjs +3 -3
  52. package/dist/menu.cjs.map +1 -1
  53. package/dist/menu.js +35 -35
  54. package/dist/menu.js.map +1 -1
  55. package/dist/navigation-menu.cjs +11 -0
  56. package/dist/navigation-menu.cjs.map +1 -0
  57. package/dist/navigation-menu.js +139 -0
  58. package/dist/navigation-menu.js.map +1 -0
  59. package/dist/overlay/index.d.ts +2 -0
  60. package/dist/overlay/index.d.ts.map +1 -1
  61. package/dist/overlay/menu/menu.d.ts.map +1 -1
  62. package/dist/overlay/navigation-menu/navigation-menu-item.css.cjs +2 -0
  63. package/dist/overlay/navigation-menu/navigation-menu-item.css.cjs.map +1 -0
  64. package/dist/overlay/navigation-menu/navigation-menu-item.css.js +6 -0
  65. package/dist/overlay/navigation-menu/navigation-menu-item.css.js.map +1 -0
  66. package/dist/overlay/navigation-menu/navigation-menu-panel.css.cjs +2 -0
  67. package/dist/overlay/navigation-menu/navigation-menu-panel.css.cjs.map +1 -0
  68. package/dist/overlay/navigation-menu/navigation-menu-panel.css.js +6 -0
  69. package/dist/overlay/navigation-menu/navigation-menu-panel.css.js.map +1 -0
  70. package/dist/overlay/navigation-menu/navigation-menu.css.cjs +2 -0
  71. package/dist/overlay/navigation-menu/navigation-menu.css.cjs.map +1 -0
  72. package/dist/overlay/navigation-menu/navigation-menu.css.js +6 -0
  73. package/dist/overlay/navigation-menu/navigation-menu.css.js.map +1 -0
  74. package/dist/overlay/navigation-menu/navigation-menu.d.ts +75 -0
  75. package/dist/overlay/navigation-menu/navigation-menu.d.ts.map +1 -0
  76. package/dist/overlay/shared/use-dialog.cjs +1 -1
  77. package/dist/overlay/shared/use-dialog.cjs.map +1 -1
  78. package/dist/overlay/shared/use-dialog.d.ts.map +1 -1
  79. package/dist/overlay/shared/use-dialog.js +5 -5
  80. package/dist/overlay/shared/use-dialog.js.map +1 -1
  81. package/dist/overlay/shared/use-floating-trigger.cjs.map +1 -1
  82. package/dist/overlay/shared/use-floating-trigger.d.ts.map +1 -1
  83. package/dist/overlay/shared/use-floating-trigger.js.map +1 -1
  84. package/dist/refine.cjs +120 -111
  85. package/dist/refine.cjs.map +1 -1
  86. package/dist/refine.iife.js +120 -111
  87. package/dist/refine.iife.js.map +1 -1
  88. package/dist/refine.js +99 -90
  89. package/dist/refine.js.map +1 -1
  90. package/dist/select.cjs +1 -1
  91. package/dist/select.cjs.map +1 -1
  92. package/dist/select.js +17 -17
  93. package/dist/select.js.map +1 -1
  94. package/dist/text.cjs.map +1 -1
  95. package/dist/text.js.map +1 -1
  96. package/package.json +65 -37
  97. package/dist/core/_internal.d.ts +0 -15
  98. package/dist/core/_internal.d.ts.map +0 -1
  99. package/dist/core/paginated-list.d.ts +0 -42
  100. package/dist/core/paginated-list.d.ts.map +0 -1
@@ -1,5 +1,5 @@
1
1
  //#region src/content/text/text.css?inline
2
- var e = ":host{--_size:var(--text-size,var(--text-base));--_weight:var(--text-weight,var(--font-normal));--_color:var(--text-color,var(--text-color-body));--_line-height:var(--text-line-height,var(--leading-normal));--_letter-spacing:var(--text-letter-spacing,normal);font-size:var(--_size);font-weight:var(--_weight);line-height:var(--_line-height);color:var(--_color);letter-spacing:var(--_letter-spacing);display:block}:host([hidden]){display:none}:host([lines]){-webkit-line-clamp:var(--_lines);-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}:host(:is([as=span],[as=label],[as=code]):not([align],[truncate])){display:inline}:host([variant=heading]){--_size:var(--text-size,var(--heading-md));--_weight:var(--text-weight,var(--font-semibold));--_color:var(--text-color,var(--text-color-heading));--_line-height:var(--text-line-height,var(--leading-tight));--_letter-spacing:var(--text-letter-spacing,var(--tracking-header))}:host([variant=label]){--_size:var(--text-size,var(--text-sm));--_weight:var(--text-weight,var(--font-medium));--_color:var(--text-color,var(--text-color-heading));--_line-height:var(--text-line-height,var(--leading-snug))}:host([variant=caption]){--_size:var(--text-size,var(--text-sm));--_color:var(--text-color,var(--text-color-secondary))}:host([variant=overline]){--_size:var(--text-size,var(--text-xs));--_weight:var(--text-weight,var(--font-semibold));--_line-height:var(--text-line-height,var(--leading-none));--_letter-spacing:var(--text-letter-spacing,.08em);text-transform:uppercase}:host([variant=code]){--_size:var(--text-size,var(--text-sm));font-family:var(--font-mono,monospace)}:host([size=xs]){--_size:var(--text-size,var(--text-xs))}:host([size=sm]){--_size:var(--text-size,var(--text-sm))}:host([size=md]){--_size:var(--text-size,var(--text-base))}:host([size=lg]){--_size:var(--text-size,var(--text-lg))}:host([size=xl]){--_size:var(--text-size,var(--text-xl))}:host([size=\"2xl\"]){--_size:var(--text-size,var(--text-2xl))}:host([variant=heading][size=xs]){--_size:var(--text-size,var(--heading-xs))}:host([variant=heading][size=sm]){--_size:var(--text-size,var(--heading-sm))}:host([variant=heading][size=md]){--_size:var(--text-size,var(--heading-md))}:host([variant=heading][size=lg]){--_size:var(--text-size,var(--heading-lg))}:host([variant=heading][size=xl]){--_size:var(--text-size,var(--heading-xl))}:host([variant=heading][size=\"2xl\"]){--_size:var(--text-size,var(--heading-2xl))}:host([weight=normal]){--_weight:var(--text-weight,var(--font-normal))}:host([weight=medium]){--_weight:var(--text-weight,var(--font-medium))}:host([weight=semibold]){--_weight:var(--text-weight,var(--font-semibold))}:host([weight=bold]){--_weight:var(--text-weight,var(--font-bold))}:host([color=primary]){--_color:var(--text-color,var(--color-primary))}:host([color=secondary]){--_color:var(--text-color,var(--color-secondary))}:host([color=info]){--_color:var(--text-color,var(--color-info))}:host([color=success]){--_color:var(--text-color,var(--color-success))}:host([color=warning]){--_color:var(--text-color,var(--color-warning))}:host([color=error]){--_color:var(--text-color,var(--color-error))}:host([color=heading]){--_color:var(--text-color,var(--text-color-heading))}:host([color=body]){--_color:var(--text-color,var(--text-color-body))}:host([color=muted]){--_color:var(--text-color,var(--text-color-secondary))}:host([color=tertiary]){--_color:var(--text-color,var(--text-color-tertiary))}:host([color=disabled]){--_color:var(--text-color,var(--text-color-disabled))}:host([color=contrast]){--_color:var(--text-color,var(--text-color-contrast))}@layer refine.utilities{:host([align]){display:block}:host([align=left]){text-align:start}:host([align=center]){text-align:center}:host([align=right]){text-align:end}:host([align=justify]){text-align:justify}:host([truncate]){text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}:host([italic]){font-style:italic}:host([as=p]),:host([as=div]),:host(:is([as=h1],[as=h2],[as=h3],[as=h4],[as=h5],[as=h6])){display:block}}";
2
+ var e = ":host{--_size:var(--text-size,var(--text-base));--_weight:var(--text-weight,var(--font-normal));--_color:var(--text-color,var(--text-color-body));--_line-height:var(--text-line-height,var(--leading-normal));--_letter-spacing:var(--text-letter-spacing,normal);font-size:var(--_size);font-weight:var(--_weight);line-height:var(--_line-height);color:var(--_color);letter-spacing:var(--_letter-spacing);display:block}:host([hidden]){display:none}:host([lines]){-webkit-line-clamp:var(--_lines);-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}:host(:is([as=span],[as=label],[as=code]):not([align],[truncate])){display:inline}:host([variant=heading]){--_size:var(--text-size,var(--heading-md));--_weight:var(--text-weight,var(--font-semibold));--_color:var(--text-color,var(--text-color-heading));--_line-height:var(--text-line-height,var(--leading-tight));--_letter-spacing:var(--text-letter-spacing,var(--tracking-header))}:host([variant=label]){--_size:var(--text-size,var(--text-sm));--_weight:var(--text-weight,var(--font-medium));--_color:var(--text-color,var(--text-color-heading));--_line-height:var(--text-line-height,var(--leading-snug))}:host([variant=caption]){--_size:var(--text-size,var(--text-sm));--_color:var(--text-color,var(--text-color-secondary))}:host([variant=overline]){--_size:var(--text-size,var(--text-xs));--_weight:var(--text-weight,var(--font-semibold));--_line-height:var(--text-line-height,var(--leading-none));--_letter-spacing:var(--text-letter-spacing,.08em);text-transform:uppercase}:host([variant=code]){--_size:var(--text-size,var(--text-sm));font-family:var(--font-mono,monospace)}:host([size=\"2xs\"]){--_size:var(--text-size,var(--text-2xs))}:host([size=xs]){--_size:var(--text-size,var(--text-xs))}:host([size=sm]){--_size:var(--text-size,var(--text-sm))}:host([size=md]){--_size:var(--text-size,var(--text-base))}:host([size=lg]){--_size:var(--text-size,var(--text-lg))}:host([size=xl]){--_size:var(--text-size,var(--text-xl))}:host([size=\"2xl\"]){--_size:var(--text-size,var(--text-2xl))}:host([variant=heading][size=xs]){--_size:var(--text-size,var(--heading-xs))}:host([variant=heading][size=sm]){--_size:var(--text-size,var(--heading-sm))}:host([variant=heading][size=md]){--_size:var(--text-size,var(--heading-md))}:host([variant=heading][size=lg]){--_size:var(--text-size,var(--heading-lg))}:host([variant=heading][size=xl]){--_size:var(--text-size,var(--heading-xl))}:host([variant=heading][size=\"2xl\"]){--_size:var(--text-size,var(--heading-2xl))}:host([weight=normal]){--_weight:var(--text-weight,var(--font-normal))}:host([weight=medium]){--_weight:var(--text-weight,var(--font-medium))}:host([weight=semibold]){--_weight:var(--text-weight,var(--font-semibold))}:host([weight=bold]){--_weight:var(--text-weight,var(--font-bold))}:host([color=primary]){--_color:var(--text-color,var(--color-primary))}:host([color=secondary]){--_color:var(--text-color,var(--color-secondary))}:host([color=info]){--_color:var(--text-color,var(--color-info))}:host([color=success]){--_color:var(--text-color,var(--color-success))}:host([color=warning]){--_color:var(--text-color,var(--color-warning))}:host([color=error]){--_color:var(--text-color,var(--color-error))}:host([color=heading]){--_color:var(--text-color,var(--text-color-heading))}:host([color=body]){--_color:var(--text-color,var(--text-color-body))}:host([color=muted]){--_color:var(--text-color,var(--text-color-secondary))}:host([color=tertiary]){--_color:var(--text-color,var(--text-color-tertiary))}:host([color=disabled]){--_color:var(--text-color,var(--text-color-disabled))}:host([color=contrast]){--_color:var(--text-color,var(--text-color-contrast))}@layer refine.utilities{:host([align]){display:block}:host([align=left]){text-align:start}:host([align=center]){text-align:center}:host([align=right]){text-align:end}:host([align=justify]){text-align:justify}:host([truncate]){text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}:host([italic]){font-style:italic}:host([as=p]),:host([as=div]),:host(:is([as=h1],[as=h2],[as=h3],[as=h4],[as=h5],[as=h6])){display:block}}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"text.css.js","names":[],"sources":["../../../src/content/text/text.css?inline"],"sourcesContent":["/* ========================================\n Base Styles & Defaults\n ======================================== */\n\n:host {\n /* Internal variables with CSS custom property fallbacks */\n --_size: var(--text-size, var(--text-base));\n --_weight: var(--text-weight, var(--font-normal));\n --_color: var(--text-color, var(--text-color-body));\n --_line-height: var(--text-line-height, var(--leading-normal));\n --_letter-spacing: var(--text-letter-spacing, normal);\n\n display: block;\n font-size: var(--_size);\n font-weight: var(--_weight);\n line-height: var(--_line-height);\n color: var(--_color);\n letter-spacing: var(--_letter-spacing);\n}\n\n:host([hidden]) {\n display: none;\n}\n\n/* ========================================\n Unlayered display overrides\n These must live outside any @layer so they can beat the unlayered\n display: block on :host. Same cascade rule that was fixed for [lines].\n ======================================== */\n\n/* Multi-line truncation */\n:host([lines]) {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n overflow: hidden;\n -webkit-line-clamp: var(--_lines);\n}\n\n/* Inline semantic tags — but not when align/truncate force block layout */\n:host(:is([as='span'], [as='label'], [as='code']):not([align], [truncate])) {\n display: inline;\n}\n\n/* ========================================\n Variant Styles\n ======================================== */\n\n/* Body (default) — uses base defaults above */\n\n/* Heading\n Default size: --heading-md (24px)\n Letter-spacing: --tracking-header (-0.05em) per theme guidelines\n Line-height: --leading-tight (1.15) for display headings */\n:host([variant='heading']) {\n --_size: var(--text-size, var(--heading-md));\n --_weight: var(--text-weight, var(--font-semibold));\n --_color: var(--text-color, var(--text-color-heading));\n --_line-height: var(--text-line-height, var(--leading-tight));\n --_letter-spacing: var(--text-letter-spacing, var(--tracking-header));\n}\n\n/* Label — slightly tighter line-height for UI labels */\n:host([variant='label']) {\n --_size: var(--text-size, var(--text-sm));\n --_weight: var(--text-weight, var(--font-medium));\n --_color: var(--text-color, var(--text-color-heading));\n --_line-height: var(--text-line-height, var(--leading-snug));\n}\n\n/* Caption */\n:host([variant='caption']) {\n --_size: var(--text-size, var(--text-sm));\n --_color: var(--text-color, var(--text-color-secondary));\n}\n\n/* Overline */\n:host([variant='overline']) {\n --_size: var(--text-size, var(--text-xs));\n --_weight: var(--text-weight, var(--font-semibold));\n --_line-height: var(--text-line-height, var(--leading-none));\n --_letter-spacing: var(--text-letter-spacing, 0.08em);\n\n text-transform: uppercase;\n}\n\n/* Code */\n:host([variant='code']) {\n --_size: var(--text-size, var(--text-sm));\n\n font-family: var(--font-mono, monospace);\n}\n\n/* ========================================\n Size Variants — body scale (--text-*)\n Used by all variants except heading.\n ======================================== */\n\n:host([size='xs']) {\n --_size: var(--text-size, var(--text-xs));\n}\n\n:host([size='sm']) {\n --_size: var(--text-size, var(--text-sm));\n}\n\n:host([size='md']) {\n --_size: var(--text-size, var(--text-base));\n}\n\n:host([size='lg']) {\n --_size: var(--text-size, var(--text-lg));\n}\n\n:host([size='xl']) {\n --_size: var(--text-size, var(--text-xl));\n}\n\n:host([size='2xl']) {\n --_size: var(--text-size, var(--text-2xl));\n}\n\n/* ========================================\n Size Variants — heading scale (--heading-*)\n Compound selectors override the body-scale rules above when\n variant=\"heading\" and a size is also provided.\n ======================================== */\n\n:host([variant='heading'][size='xs']) {\n --_size: var(--text-size, var(--heading-xs));\n}\n\n:host([variant='heading'][size='sm']) {\n --_size: var(--text-size, var(--heading-sm));\n}\n\n:host([variant='heading'][size='md']) {\n --_size: var(--text-size, var(--heading-md));\n}\n\n:host([variant='heading'][size='lg']) {\n --_size: var(--text-size, var(--heading-lg));\n}\n\n:host([variant='heading'][size='xl']) {\n --_size: var(--text-size, var(--heading-xl));\n}\n\n:host([variant='heading'][size='2xl']) {\n --_size: var(--text-size, var(--heading-2xl));\n}\n\n/* ========================================\n Weight Variants\n ======================================== */\n\n:host([weight='normal']) {\n --_weight: var(--text-weight, var(--font-normal));\n}\n\n:host([weight='medium']) {\n --_weight: var(--text-weight, var(--font-medium));\n}\n\n:host([weight='semibold']) {\n --_weight: var(--text-weight, var(--font-semibold));\n}\n\n:host([weight='bold']) {\n --_weight: var(--text-weight, var(--font-bold));\n}\n\n/* ========================================\n Color Variants\n Semantic colors map to --text-color-* tokens.\n Theme colors map to --color-* base tokens.\n ======================================== */\n\n:host([color='primary']) {\n --_color: var(--text-color, var(--color-primary));\n}\n\n:host([color='secondary']) {\n --_color: var(--text-color, var(--color-secondary));\n}\n\n:host([color='info']) {\n --_color: var(--text-color, var(--color-info));\n}\n\n:host([color='success']) {\n --_color: var(--text-color, var(--color-success));\n}\n\n:host([color='warning']) {\n --_color: var(--text-color, var(--color-warning));\n}\n\n:host([color='error']) {\n --_color: var(--text-color, var(--color-error));\n}\n\n/* Semantic text colors */\n:host([color='heading']) {\n --_color: var(--text-color, var(--text-color-heading)); /* --color-contrast-900 */\n}\n\n:host([color='body']) {\n --_color: var(--text-color, var(--text-color-body)); /* --color-contrast-800 */\n}\n\n:host([color='muted']) {\n --_color: var(--text-color, var(--text-color-secondary)); /* --color-contrast-600 — AA compliant */\n}\n\n:host([color='tertiary']) {\n --_color: var(--text-color, var(--text-color-tertiary)); /* --color-contrast-500 — AA for large text */\n}\n\n:host([color='disabled']) {\n --_color: var(--text-color, var(--text-color-disabled)); /* --color-contrast-400 */\n}\n\n:host([color='contrast']) {\n --_color: var(--text-color, var(--text-color-contrast)); /* --color-contrast-100 */\n}\n\n@layer refine.utilities {\n /* ========================================\n Alignment\n ======================================== */\n\n :host([align]) {\n display: block;\n }\n\n :host([align='left']) {\n text-align: start;\n }\n\n :host([align='center']) {\n text-align: center;\n }\n\n :host([align='right']) {\n text-align: end;\n }\n\n :host([align='justify']) {\n text-align: justify;\n }\n\n /* ========================================\n Truncate (single-line)\n ======================================== */\n\n :host([truncate]) {\n display: block;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* ========================================\n Italic\n ======================================== */\n\n :host([italic]) {\n font-style: italic;\n }\n\n /* ========================================\n Block Display for Certain Tags\n ======================================== */\n\n :host([as='p']),\n :host([as='div']),\n :host(:is([as='h1'], [as='h2'], [as='h3'], [as='h4'], [as='h5'], [as='h6'])) {\n display: block;\n }\n\n /* Note: display: inline for span/label/code is handled outside this @layer\n (above) so it can override the unlayered :host { display: block }. */\n}\n"],"mappings":""}
1
+ {"version":3,"file":"text.css.js","names":[],"sources":["../../../src/content/text/text.css?inline"],"sourcesContent":["/* ========================================\n Base Styles & Defaults\n ======================================== */\n\n:host {\n /* Internal variables with CSS custom property fallbacks */\n --_size: var(--text-size, var(--text-base));\n --_weight: var(--text-weight, var(--font-normal));\n --_color: var(--text-color, var(--text-color-body));\n --_line-height: var(--text-line-height, var(--leading-normal));\n --_letter-spacing: var(--text-letter-spacing, normal);\n\n display: block;\n font-size: var(--_size);\n font-weight: var(--_weight);\n line-height: var(--_line-height);\n color: var(--_color);\n letter-spacing: var(--_letter-spacing);\n}\n\n:host([hidden]) {\n display: none;\n}\n\n/* ========================================\n Unlayered display overrides\n These must live outside any @layer so they can beat the unlayered\n display: block on :host. Same cascade rule that was fixed for [lines].\n ======================================== */\n\n/* Multi-line truncation */\n:host([lines]) {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n overflow: hidden;\n -webkit-line-clamp: var(--_lines);\n}\n\n/* Inline semantic tags — but not when align/truncate force block layout */\n:host(:is([as='span'], [as='label'], [as='code']):not([align], [truncate])) {\n display: inline;\n}\n\n/* ========================================\n Variant Styles\n ======================================== */\n\n/* Body (default) — uses base defaults above */\n\n/* Heading\n Default size: --heading-md (24px)\n Letter-spacing: --tracking-header (-0.05em) per theme guidelines\n Line-height: --leading-tight (1.15) for display headings */\n:host([variant='heading']) {\n --_size: var(--text-size, var(--heading-md));\n --_weight: var(--text-weight, var(--font-semibold));\n --_color: var(--text-color, var(--text-color-heading));\n --_line-height: var(--text-line-height, var(--leading-tight));\n --_letter-spacing: var(--text-letter-spacing, var(--tracking-header));\n}\n\n/* Label — slightly tighter line-height for UI labels */\n:host([variant='label']) {\n --_size: var(--text-size, var(--text-sm));\n --_weight: var(--text-weight, var(--font-medium));\n --_color: var(--text-color, var(--text-color-heading));\n --_line-height: var(--text-line-height, var(--leading-snug));\n}\n\n/* Caption */\n:host([variant='caption']) {\n --_size: var(--text-size, var(--text-sm));\n --_color: var(--text-color, var(--text-color-secondary));\n}\n\n/* Overline */\n:host([variant='overline']) {\n --_size: var(--text-size, var(--text-xs));\n --_weight: var(--text-weight, var(--font-semibold));\n --_line-height: var(--text-line-height, var(--leading-none));\n --_letter-spacing: var(--text-letter-spacing, 0.08em);\n\n text-transform: uppercase;\n}\n\n/* Code */\n:host([variant='code']) {\n --_size: var(--text-size, var(--text-sm));\n\n font-family: var(--font-mono, monospace);\n}\n\n/* ========================================\n Size Variants — body scale (--text-*)\n Used by all variants except heading.\n ======================================== */\n\n:host([size='2xs']) {\n --_size: var(--text-size, var(--text-2xs));\n}\n\n:host([size='xs']) {\n --_size: var(--text-size, var(--text-xs));\n}\n\n:host([size='sm']) {\n --_size: var(--text-size, var(--text-sm));\n}\n\n:host([size='md']) {\n --_size: var(--text-size, var(--text-base));\n}\n\n:host([size='lg']) {\n --_size: var(--text-size, var(--text-lg));\n}\n\n:host([size='xl']) {\n --_size: var(--text-size, var(--text-xl));\n}\n\n:host([size='2xl']) {\n --_size: var(--text-size, var(--text-2xl));\n}\n\n/* ========================================\n Size Variants — heading scale (--heading-*)\n Compound selectors override the body-scale rules above when\n variant=\"heading\" and a size is also provided.\n ======================================== */\n\n:host([variant='heading'][size='xs']) {\n --_size: var(--text-size, var(--heading-xs));\n}\n\n:host([variant='heading'][size='sm']) {\n --_size: var(--text-size, var(--heading-sm));\n}\n\n:host([variant='heading'][size='md']) {\n --_size: var(--text-size, var(--heading-md));\n}\n\n:host([variant='heading'][size='lg']) {\n --_size: var(--text-size, var(--heading-lg));\n}\n\n:host([variant='heading'][size='xl']) {\n --_size: var(--text-size, var(--heading-xl));\n}\n\n:host([variant='heading'][size='2xl']) {\n --_size: var(--text-size, var(--heading-2xl));\n}\n\n/* ========================================\n Weight Variants\n ======================================== */\n\n:host([weight='normal']) {\n --_weight: var(--text-weight, var(--font-normal));\n}\n\n:host([weight='medium']) {\n --_weight: var(--text-weight, var(--font-medium));\n}\n\n:host([weight='semibold']) {\n --_weight: var(--text-weight, var(--font-semibold));\n}\n\n:host([weight='bold']) {\n --_weight: var(--text-weight, var(--font-bold));\n}\n\n/* ========================================\n Color Variants\n Semantic colors map to --text-color-* tokens.\n Theme colors map to --color-* base tokens.\n ======================================== */\n\n:host([color='primary']) {\n --_color: var(--text-color, var(--color-primary));\n}\n\n:host([color='secondary']) {\n --_color: var(--text-color, var(--color-secondary));\n}\n\n:host([color='info']) {\n --_color: var(--text-color, var(--color-info));\n}\n\n:host([color='success']) {\n --_color: var(--text-color, var(--color-success));\n}\n\n:host([color='warning']) {\n --_color: var(--text-color, var(--color-warning));\n}\n\n:host([color='error']) {\n --_color: var(--text-color, var(--color-error));\n}\n\n/* Semantic text colors */\n:host([color='heading']) {\n --_color: var(--text-color, var(--text-color-heading)); /* --color-contrast-900 */\n}\n\n:host([color='body']) {\n --_color: var(--text-color, var(--text-color-body)); /* --color-contrast-800 */\n}\n\n:host([color='muted']) {\n --_color: var(--text-color, var(--text-color-secondary)); /* --color-contrast-600 — AA compliant */\n}\n\n:host([color='tertiary']) {\n --_color: var(--text-color, var(--text-color-tertiary)); /* --color-contrast-500 — AA for large text */\n}\n\n:host([color='disabled']) {\n --_color: var(--text-color, var(--text-color-disabled)); /* --color-contrast-400 */\n}\n\n:host([color='contrast']) {\n --_color: var(--text-color, var(--text-color-contrast)); /* --color-contrast-100 */\n}\n\n@layer refine.utilities {\n /* ========================================\n Alignment\n ======================================== */\n\n :host([align]) {\n display: block;\n }\n\n :host([align='left']) {\n text-align: start;\n }\n\n :host([align='center']) {\n text-align: center;\n }\n\n :host([align='right']) {\n text-align: end;\n }\n\n :host([align='justify']) {\n text-align: justify;\n }\n\n /* ========================================\n Truncate (single-line)\n ======================================== */\n\n :host([truncate]) {\n display: block;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* ========================================\n Italic\n ======================================== */\n\n :host([italic]) {\n font-style: italic;\n }\n\n /* ========================================\n Block Display for Certain Tags\n ======================================== */\n\n :host([as='p']),\n :host([as='div']),\n :host(:is([as='h1'], [as='h2'], [as='h3'], [as='h4'], [as='h5'], [as='h6'])) {\n display: block;\n }\n\n /* Note: display: inline for span/label/code is handled outside this @layer\n (above) so it can override the unlayered :host { display: block }. */\n}\n"],"mappings":""}
@@ -11,7 +11,7 @@ export type OreTextProps = {
11
11
  /** Clamp text to N lines with an ellipsis (multi-line truncation) */
12
12
  lines?: number;
13
13
  /** Text size — maps to --text-* tokens for body variants and --heading-* tokens for the heading variant */
14
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
14
+ size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
15
15
  /** Enable single-line text truncation with ellipsis */
16
16
  truncate?: boolean;
17
17
  /** Text semantic variant */
@@ -1 +1 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/content/text/text.ts"],"names":[],"mappings":"AAIA,gCAAgC;AAChC,MAAM,MAAM,YAAY,GAAG;IACzB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;IAChD,wFAAwF;IACxF,EAAE,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,CAAC;IACvF,2CAA2C;IAC3C,KAAK,CAAC,EACF,SAAS,GACT,WAAW,GACX,MAAM,GACN,SAAS,GACT,SAAS,GACT,OAAO,GACP,SAAS,GACT,MAAM,GACN,OAAO,GACP,UAAU,GACV,UAAU,GACV,UAAU,CAAC;IACf,wBAAwB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2GAA2G;IAC3G,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;IAChD,uDAAuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;IACzE,kBAAkB;IAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;CACpD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,eAAO,MAAM,QAAQ,EAAG,UAAmB,CAAC"}
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/content/text/text.ts"],"names":[],"mappings":"AAIA,gCAAgC;AAChC,MAAM,MAAM,YAAY,GAAG;IACzB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;IAChD,wFAAwF;IACxF,EAAE,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,CAAC;IACvF,2CAA2C;IAC3C,KAAK,CAAC,EACF,SAAS,GACT,WAAW,GACX,MAAM,GACN,SAAS,GACT,SAAS,GACT,OAAO,GACP,SAAS,GACT,MAAM,GACN,OAAO,GACP,UAAU,GACV,UAAU,GACV,UAAU,CAAC;IACf,wBAAwB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2GAA2G;IAC3G,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;IACxD,uDAAuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;IACzE,kBAAkB;IAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;CACpD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,eAAO,MAAM,QAAQ,EAAG,UAAmB,CAAC"}
@@ -1,2 +1,2 @@
1
- const e=require("./field-base.cjs");let t=require("@vielzeug/ripple"),n=require("@vielzeug/ripple/watch");var r=e=>e?Array.isArray(e)?e.filter(Boolean):e.split(`,`).map(e=>e.trim()).filter(Boolean):[],i=i=>{let a=(0,t.signal)([]),o=(0,t.computed)(()=>!!i.multiple?.value),s=(0,t.computed)(()=>o.value?a.value.join(`,`):a.value[0]??``),c=e=>{let t=o.value?e:e.slice(0,1);return[...new Set(t.filter(Boolean))]},l=e.createDirtyTracker(),u=e=>{a.value=c(e)},d=e=>{l.markDirty(),u(e)},f=()=>d([]),p=e=>{l.markDirty(),a.value=a.value.filter(t=>t!==e)},m=e=>{if(o.value){a.value.includes(e)||d([...a.value,e]);return}d([e])},h=e=>{o.value&&a.value.includes(e)?p(e):m(e)},g=e=>{u(r(e))},_=e.createField(i),v=(0,t.computed)(()=>i.required?.value&&a.value.length===0?{valueMissing:!0}:null),y=(0,t.computed)(()=>v.value?i.requiredMessage?.value||`Please make a selection.`:``),b=(0,n.watch)(i.value,g,{immediate:!0});if(i.signal.addEventListener(`abort`,()=>b.dispose(),{once:!0}),i.multiple){let e=(0,n.watch)(i.multiple,()=>g(i.value.value));i.signal.addEventListener(`abort`,()=>e.dispose(),{once:!0})}let x=a.value,S=()=>{u(l.isDirty?x:r(i.value.value)),l.clear(),_.triggerValidation(`change`)};return{..._,clear:f,formValue:s,removeValue:p,reset:S,selectedValue:(0,t.computed)(()=>a.value[0]),selectedValues:a,selectValue:m,setValues:d,toggleValue:h,validationMessage:y,validity:v}};exports.createChoiceField=i;
1
+ const e=require("./field-base.cjs"),t=require("./signals.cjs");let n=require("@vielzeug/ripple"),r=require("@vielzeug/ripple/watch");var i=e=>e?Array.isArray(e)?e.filter(Boolean):e.split(`,`).map(e=>e.trim()).filter(Boolean):[],a=a=>{let o=(0,n.computed)(()=>!!a.multiple?.value),s=e=>{let t=o.value?e:e.slice(0,1);return[...new Set(t.filter(Boolean))]},c=t.syncedSignal(a.value,a.signal,e=>s(i(e))),l=(0,n.computed)(()=>o.value?c.value.join(`,`):c.value[0]??``),u=e.createDirtyTracker(),d=e=>{c.value=s(e)},f=e=>{u.markDirty(),d(e)},p=()=>f([]),m=e=>{u.markDirty(),c.value=c.value.filter(t=>t!==e)},h=e=>{if(o.value){c.value.includes(e)||f([...c.value,e]);return}f([e])},g=e=>{o.value&&c.value.includes(e)?m(e):h(e)},_=e=>{d(i(e))},v=e.createField(a),y=(0,n.computed)(()=>a.required?.value&&c.value.length===0?{valueMissing:!0}:null),b=(0,n.computed)(()=>y.value?a.requiredMessage?.value||`Please make a selection.`:``);if(a.multiple){let e=(0,r.watch)(a.multiple,()=>_(a.value.value));a.signal.addEventListener(`abort`,()=>e.dispose(),{once:!0})}let x=c.value,S=()=>{d(u.isDirty?x:i(a.value.value)),u.clear(),v.triggerValidation(`change`)};return{...v,clear:p,formValue:l,removeValue:m,reset:S,selectedValue:(0,n.computed)(()=>c.value[0]),selectedValues:c,selectValue:h,setValues:f,toggleValue:g,validationMessage:b,validity:y}};exports.createChoiceField=a;
2
2
  //# sourceMappingURL=choice-field.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"choice-field.cjs","names":[],"sources":["../../src/core/choice-field.ts"],"sourcesContent":["import { computed, type Readable, signal } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple/watch';\n\nimport { createDirtyTracker, createField, type FieldHandle, type FieldOptions } from './field-base';\n\n// ── Choice change event payload ──────────────────────────────────────────────────────────────\n\nexport type ChoiceChangeDetail = {\n labels: string[];\n originalEvent?: Event;\n values: string[];\n};\n\n// ── Choice field ──────────────────────────────────────────────────────────────────────\n\nexport type ChoiceFieldOptions = FieldOptions & {\n multiple?: Readable<boolean | undefined>;\n /** Marks an empty selection invalid — feeds `validity`/`validationMessage` (see below). */\n required?: Readable<boolean | undefined>;\n /** Message for the empty-selection+required case. Defaults to `'Please make a selection.'`. */\n requiredMessage?: Readable<string | undefined>;\n /** `AbortSignal` from the component lifecycle. All internal subscriptions are disposed on abort. */\n signal: AbortSignal;\n /**\n * Current selection value(s). Accepts a comma-separated string\n * (legacy/single-select form serialisation) or a `string[]` array.\n * The field normalises both formats internally via `parseChoiceValues`.\n */\n value: Readable<string | string[] | undefined>;\n};\n\nexport type ChoiceFieldHandle = FieldHandle & {\n clear: () => void;\n formValue: Readable<string>;\n removeValue: (value: string) => void;\n /**\n * Restores the selection to its native \"default\". See `DirtyTracker` for the two-state\n * rationale.\n */\n reset: () => void;\n selectedValue: Readable<string | undefined>;\n selectedValues: Readable<string[]>;\n selectValue: (value: string) => void;\n setValues: (values: string[]) => void;\n /**\n * Toggles `value` in the selection.\n * - **Multiple mode**: adds if absent, removes if present.\n * - **Single mode**: always selects `value` (acts like `selectValue` — cannot\n * deselect; use `clear()` to reset a single-select field).\n */\n toggleValue: (value: string) => void;\n /** Reactive validation message paired with `validity`. Empty string when valid. */\n validationMessage: Readable<string>;\n /**\n * Reactive `ValidityStateFlags` — `{ valueMissing: true }` while `required` and no option is\n * selected, `null` (valid) otherwise. Pass straight to `useField({ validity: choice.validity })`.\n */\n validity: Readable<ValidityStateFlags | null>;\n};\n\nconst parseChoiceValues = (raw: string | string[] | undefined): string[] => {\n if (!raw) return [];\n\n if (Array.isArray(raw)) return raw.filter(Boolean);\n\n return raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n};\n\nexport const createChoiceField = (options: ChoiceFieldOptions): ChoiceFieldHandle => {\n const selectedValues = signal<string[]>([]);\n const isMultiple = computed(() => Boolean(options.multiple?.value));\n const formValue = computed(() =>\n isMultiple.value ? selectedValues.value.join(',') : (selectedValues.value[0] ?? ''),\n );\n\n const normalizeValues = (values: string[]): string[] => {\n const normalized = isMultiple.value ? values : values.slice(0, 1);\n\n return [...new Set(normalized.filter(Boolean))];\n };\n\n const dirtyTracker = createDirtyTracker();\n\n // The actual state setter, shared by every mutation path. Deliberately *not* where the dirty\n // tracker gets marked — `syncFromProp` (below) calls this directly to stay exempt from it,\n // since mirroring an external prop change is never \"the user changed the selection\".\n const applyValues = (values: string[]): void => {\n selectedValues.value = normalizeValues(values);\n };\n\n const setValues = (values: string[]): void => {\n dirtyTracker.markDirty();\n applyValues(values);\n };\n const clear = (): void => setValues([]);\n const removeValue = (value: string): void => {\n dirtyTracker.markDirty();\n selectedValues.value = selectedValues.value.filter((v) => v !== value);\n };\n\n const selectValue = (value: string): void => {\n if (isMultiple.value) {\n if (!selectedValues.value.includes(value)) setValues([...selectedValues.value, value]);\n\n return;\n }\n\n setValues([value]);\n };\n\n const toggleValue = (value: string): void => {\n if (isMultiple.value) {\n if (selectedValues.value.includes(value)) removeValue(value);\n else selectValue(value);\n } else {\n selectValue(value);\n }\n };\n\n const syncFromProp = (nextValue: string | string[] | undefined): void => {\n applyValues(parseChoiceValues(nextValue));\n };\n\n const field = createField(options);\n\n const validity = computed<ValidityStateFlags | null>(() =>\n options.required?.value && selectedValues.value.length === 0 ? { valueMissing: true } : null,\n );\n const validationMessage = computed(() =>\n validity.value ? options.requiredMessage?.value || 'Please make a selection.' : '',\n );\n\n const valueSub = watch(options.value, syncFromProp, { immediate: true });\n\n options.signal.addEventListener('abort', () => valueSub.dispose(), { once: true });\n\n if (options.multiple) {\n const multipleSub = watch(options.multiple, () => syncFromProp(options.value.value));\n\n options.signal.addEventListener('abort', () => multipleSub.dispose(), { once: true });\n }\n\n const initialValues = selectedValues.value;\n const reset = (): void => {\n applyValues(dirtyTracker.isDirty ? initialValues : parseChoiceValues(options.value.value));\n dirtyTracker.clear();\n field.triggerValidation('change');\n };\n\n return {\n ...field,\n clear,\n formValue,\n removeValue,\n reset,\n selectedValue: computed(() => selectedValues.value[0]),\n selectedValues,\n selectValue,\n setValues,\n toggleValue,\n validationMessage,\n validity,\n };\n};\n"],"mappings":"0GA4DA,IAAM,EAAqB,GACpB,EAED,MAAM,QAAQ,CAAG,EAAU,EAAI,OAAO,OAAO,EAE1C,EACJ,MAAM,GAAG,CAAC,CACV,IAAK,GAAU,EAAM,KAAK,CAAC,CAAC,CAC5B,OAAO,OAAO,EAPA,CAAC,EAUP,EAAqB,GAAmD,CACnF,IAAM,GAAA,EAAiB,EAAA,OAAA,CAAiB,CAAC,CAAC,EACpC,GAAA,EAAa,EAAA,SAAA,KAAe,EAAQ,EAAQ,UAAU,KAAM,EAC5D,GAAA,EAAY,EAAA,SAAA,KAChB,EAAW,MAAQ,EAAe,MAAM,KAAK,GAAG,EAAK,EAAe,MAAM,IAAM,EAClF,EAEM,EAAmB,GAA+B,CACtD,IAAM,EAAa,EAAW,MAAQ,EAAS,EAAO,MAAM,EAAG,CAAC,EAEhE,MAAO,CAAC,GAAG,IAAI,IAAI,EAAW,OAAO,OAAO,CAAC,CAAC,CAChD,EAEM,EAAe,EAAA,mBAAmB,EAKlC,EAAe,GAA2B,CAC9C,EAAe,MAAQ,EAAgB,CAAM,CAC/C,EAEM,EAAa,GAA2B,CAC5C,EAAa,UAAU,EACvB,EAAY,CAAM,CACpB,EACM,MAAoB,EAAU,CAAC,CAAC,EAChC,EAAe,GAAwB,CAC3C,EAAa,UAAU,EACvB,EAAe,MAAQ,EAAe,MAAM,OAAQ,GAAM,IAAM,CAAK,CACvE,EAEM,EAAe,GAAwB,CAC3C,GAAI,EAAW,MAAO,CACf,EAAe,MAAM,SAAS,CAAK,GAAG,EAAU,CAAC,GAAG,EAAe,MAAO,CAAK,CAAC,EAErF,MACF,CAEA,EAAU,CAAC,CAAK,CAAC,CACnB,EAEM,EAAe,GAAwB,CACvC,EAAW,OACT,EAAe,MAAM,SAAS,CAAK,EAAG,EAAY,CAAK,EACtD,EAAY,CAAK,CAI1B,EAEM,EAAgB,GAAmD,CACvE,EAAY,EAAkB,CAAS,CAAC,CAC1C,EAEM,EAAQ,EAAA,YAAY,CAAO,EAE3B,GAAA,EAAW,EAAA,SAAA,KACf,EAAQ,UAAU,OAAS,EAAe,MAAM,SAAW,EAAI,CAAE,aAAc,EAAK,EAAI,IAC1F,EACM,GAAA,EAAoB,EAAA,SAAA,KACxB,EAAS,MAAQ,EAAQ,iBAAiB,OAAS,2BAA6B,EAClF,EAEM,GAAA,EAAW,EAAA,MAAA,CAAM,EAAQ,MAAO,EAAc,CAAE,UAAW,EAAK,CAAC,EAIvE,GAFA,EAAQ,OAAO,iBAAiB,YAAe,EAAS,QAAQ,EAAG,CAAE,KAAM,EAAK,CAAC,EAE7E,EAAQ,SAAU,CACpB,IAAM,GAAA,EAAc,EAAA,MAAA,CAAM,EAAQ,aAAgB,EAAa,EAAQ,MAAM,KAAK,CAAC,EAEnF,EAAQ,OAAO,iBAAiB,YAAe,EAAY,QAAQ,EAAG,CAAE,KAAM,EAAK,CAAC,CACtF,CAEA,IAAM,EAAgB,EAAe,MAC/B,MAAoB,CACxB,EAAY,EAAa,QAAU,EAAgB,EAAkB,EAAQ,MAAM,KAAK,CAAC,EACzF,EAAa,MAAM,EACnB,EAAM,kBAAkB,QAAQ,CAClC,EAEA,MAAO,CACL,GAAG,EACH,QACA,YACA,cACA,QACA,eAAA,EAAe,EAAA,SAAA,KAAe,EAAe,MAAM,EAAE,EACrD,iBACA,cACA,YACA,cACA,oBACA,UACF,CACF"}
1
+ {"version":3,"file":"choice-field.cjs","names":[],"sources":["../../src/core/choice-field.ts"],"sourcesContent":["import { computed, type Readable } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple/watch';\n\nimport { createDirtyTracker, createField, type FieldHandle, type FieldOptions } from './field-base';\nimport { syncedSignal } from './signals';\n\n// ── Choice change event payload ──────────────────────────────────────────────────────────────\n\nexport type ChoiceChangeDetail = {\n labels: string[];\n originalEvent?: Event;\n values: string[];\n};\n\n// ── Choice field ──────────────────────────────────────────────────────────────────────\n\nexport type ChoiceFieldOptions = FieldOptions & {\n multiple?: Readable<boolean | undefined>;\n /** Marks an empty selection invalid — feeds `validity`/`validationMessage` (see below). */\n required?: Readable<boolean | undefined>;\n /** Message for the empty-selection+required case. Defaults to `'Please make a selection.'`. */\n requiredMessage?: Readable<string | undefined>;\n /** `AbortSignal` from the component lifecycle. All internal subscriptions are disposed on abort. */\n signal: AbortSignal;\n /**\n * Current selection value(s). Accepts a comma-separated string\n * (legacy/single-select form serialisation) or a `string[]` array.\n * The field normalises both formats internally via `parseChoiceValues`.\n */\n value: Readable<string | string[] | undefined>;\n};\n\nexport type ChoiceFieldHandle = FieldHandle & {\n clear: () => void;\n formValue: Readable<string>;\n removeValue: (value: string) => void;\n /**\n * Restores the selection to its native \"default\". See `DirtyTracker` for the two-state\n * rationale.\n */\n reset: () => void;\n selectedValue: Readable<string | undefined>;\n selectedValues: Readable<string[]>;\n selectValue: (value: string) => void;\n setValues: (values: string[]) => void;\n /**\n * Toggles `value` in the selection.\n * - **Multiple mode**: adds if absent, removes if present.\n * - **Single mode**: always selects `value` (acts like `selectValue` — cannot\n * deselect; use `clear()` to reset a single-select field).\n */\n toggleValue: (value: string) => void;\n /** Reactive validation message paired with `validity`. Empty string when valid. */\n validationMessage: Readable<string>;\n /**\n * Reactive `ValidityStateFlags` — `{ valueMissing: true }` while `required` and no option is\n * selected, `null` (valid) otherwise. Pass straight to `useField({ validity: choice.validity })`.\n */\n validity: Readable<ValidityStateFlags | null>;\n};\n\nconst parseChoiceValues = (raw: string | string[] | undefined): string[] => {\n if (!raw) return [];\n\n if (Array.isArray(raw)) return raw.filter(Boolean);\n\n return raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n};\n\nexport const createChoiceField = (options: ChoiceFieldOptions): ChoiceFieldHandle => {\n const isMultiple = computed(() => Boolean(options.multiple?.value));\n\n const normalizeValues = (values: string[]): string[] => {\n const normalized = isMultiple.value ? values : values.slice(0, 1);\n\n return [...new Set(normalized.filter(Boolean))];\n };\n\n // Kept in sync with `options.value` via the shared helper (see `checkable.ts`/`text-field.ts`\n // for the same pattern) rather than a hand-rolled signal + watch pair.\n const selectedValues = syncedSignal(options.value, options.signal, (raw) => normalizeValues(parseChoiceValues(raw)));\n const formValue = computed(() =>\n isMultiple.value ? selectedValues.value.join(',') : (selectedValues.value[0] ?? ''),\n );\n\n const dirtyTracker = createDirtyTracker();\n\n // The actual state setter, shared by every mutation path. Deliberately *not* where the dirty\n // tracker gets marked — `syncFromProp` (below) calls this directly to stay exempt from it,\n // since mirroring an external prop change is never \"the user changed the selection\".\n const applyValues = (values: string[]): void => {\n selectedValues.value = normalizeValues(values);\n };\n\n const setValues = (values: string[]): void => {\n dirtyTracker.markDirty();\n applyValues(values);\n };\n const clear = (): void => setValues([]);\n const removeValue = (value: string): void => {\n dirtyTracker.markDirty();\n selectedValues.value = selectedValues.value.filter((v) => v !== value);\n };\n\n const selectValue = (value: string): void => {\n if (isMultiple.value) {\n if (!selectedValues.value.includes(value)) setValues([...selectedValues.value, value]);\n\n return;\n }\n\n setValues([value]);\n };\n\n const toggleValue = (value: string): void => {\n if (isMultiple.value) {\n if (selectedValues.value.includes(value)) removeValue(value);\n else selectValue(value);\n } else {\n selectValue(value);\n }\n };\n\n const syncFromProp = (nextValue: string | string[] | undefined): void => {\n applyValues(parseChoiceValues(nextValue));\n };\n\n const field = createField(options);\n\n const validity = computed<ValidityStateFlags | null>(() =>\n options.required?.value && selectedValues.value.length === 0 ? { valueMissing: true } : null,\n );\n const validationMessage = computed(() =>\n validity.value ? options.requiredMessage?.value || 'Please make a selection.' : '',\n );\n\n if (options.multiple) {\n const multipleSub = watch(options.multiple, () => syncFromProp(options.value.value));\n\n options.signal.addEventListener('abort', () => multipleSub.dispose(), { once: true });\n }\n\n const initialValues = selectedValues.value;\n const reset = (): void => {\n applyValues(dirtyTracker.isDirty ? initialValues : parseChoiceValues(options.value.value));\n dirtyTracker.clear();\n field.triggerValidation('change');\n };\n\n return {\n ...field,\n clear,\n formValue,\n removeValue,\n reset,\n selectedValue: computed(() => selectedValues.value[0]),\n selectedValues,\n selectValue,\n setValues,\n toggleValue,\n validationMessage,\n validity,\n };\n};\n"],"mappings":"qIA6DA,IAAM,EAAqB,GACpB,EAED,MAAM,QAAQ,CAAG,EAAU,EAAI,OAAO,OAAO,EAE1C,EACJ,MAAM,GAAG,CAAC,CACV,IAAK,GAAU,EAAM,KAAK,CAAC,CAAC,CAC5B,OAAO,OAAO,EAPA,CAAC,EAUP,EAAqB,GAAmD,CACnF,IAAM,GAAA,EAAa,EAAA,SAAA,KAAe,EAAQ,EAAQ,UAAU,KAAM,EAE5D,EAAmB,GAA+B,CACtD,IAAM,EAAa,EAAW,MAAQ,EAAS,EAAO,MAAM,EAAG,CAAC,EAEhE,MAAO,CAAC,GAAG,IAAI,IAAI,EAAW,OAAO,OAAO,CAAC,CAAC,CAChD,EAIM,EAAiB,EAAA,aAAa,EAAQ,MAAO,EAAQ,OAAS,GAAQ,EAAgB,EAAkB,CAAG,CAAC,CAAC,EAC7G,GAAA,EAAY,EAAA,SAAA,KAChB,EAAW,MAAQ,EAAe,MAAM,KAAK,GAAG,EAAK,EAAe,MAAM,IAAM,EAClF,EAEM,EAAe,EAAA,mBAAmB,EAKlC,EAAe,GAA2B,CAC9C,EAAe,MAAQ,EAAgB,CAAM,CAC/C,EAEM,EAAa,GAA2B,CAC5C,EAAa,UAAU,EACvB,EAAY,CAAM,CACpB,EACM,MAAoB,EAAU,CAAC,CAAC,EAChC,EAAe,GAAwB,CAC3C,EAAa,UAAU,EACvB,EAAe,MAAQ,EAAe,MAAM,OAAQ,GAAM,IAAM,CAAK,CACvE,EAEM,EAAe,GAAwB,CAC3C,GAAI,EAAW,MAAO,CACf,EAAe,MAAM,SAAS,CAAK,GAAG,EAAU,CAAC,GAAG,EAAe,MAAO,CAAK,CAAC,EAErF,MACF,CAEA,EAAU,CAAC,CAAK,CAAC,CACnB,EAEM,EAAe,GAAwB,CACvC,EAAW,OACT,EAAe,MAAM,SAAS,CAAK,EAAG,EAAY,CAAK,EACtD,EAAY,CAAK,CAI1B,EAEM,EAAgB,GAAmD,CACvE,EAAY,EAAkB,CAAS,CAAC,CAC1C,EAEM,EAAQ,EAAA,YAAY,CAAO,EAE3B,GAAA,EAAW,EAAA,SAAA,KACf,EAAQ,UAAU,OAAS,EAAe,MAAM,SAAW,EAAI,CAAE,aAAc,EAAK,EAAI,IAC1F,EACM,GAAA,EAAoB,EAAA,SAAA,KACxB,EAAS,MAAQ,EAAQ,iBAAiB,OAAS,2BAA6B,EAClF,EAEA,GAAI,EAAQ,SAAU,CACpB,IAAM,GAAA,EAAc,EAAA,MAAA,CAAM,EAAQ,aAAgB,EAAa,EAAQ,MAAM,KAAK,CAAC,EAEnF,EAAQ,OAAO,iBAAiB,YAAe,EAAY,QAAQ,EAAG,CAAE,KAAM,EAAK,CAAC,CACtF,CAEA,IAAM,EAAgB,EAAe,MAC/B,MAAoB,CACxB,EAAY,EAAa,QAAU,EAAgB,EAAkB,EAAQ,MAAM,KAAK,CAAC,EACzF,EAAa,MAAM,EACnB,EAAM,kBAAkB,QAAQ,CAClC,EAEA,MAAO,CACL,GAAG,EACH,QACA,YACA,cACA,QACA,eAAA,EAAe,EAAA,SAAA,KAAe,EAAe,MAAM,EAAE,EACrD,iBACA,cACA,YACA,cACA,oBACA,UACF,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"choice-field.d.ts","sourceRoot":"","sources":["../../src/core/choice-field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAU,MAAM,kBAAkB,CAAC;AAGnE,OAAO,EAAmC,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAIpG,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,CAAC,EAAE,KAAK,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAIF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,+FAA+F;IAC/F,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,oGAAoG;IACpG,MAAM,EAAE,WAAW,CAAC;IACpB;;;;OAIG;IACH,KAAK,EAAE,QAAQ,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG;IAC5C,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5B,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;;OAGG;IACH,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,aAAa,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC5C,cAAc,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtC;;;;;OAKG;IACH,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,mFAAmF;IACnF,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC;;;OAGG;IACH,QAAQ,EAAE,QAAQ,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;CAC/C,CAAC;AAaF,eAAO,MAAM,iBAAiB,GAAI,SAAS,kBAAkB,KAAG,iBA+F/D,CAAC"}
1
+ {"version":3,"file":"choice-field.d.ts","sourceRoot":"","sources":["../../src/core/choice-field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG3D,OAAO,EAAmC,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAKpG,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,CAAC,EAAE,KAAK,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAIF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,+FAA+F;IAC/F,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,oGAAoG;IACpG,MAAM,EAAE,WAAW,CAAC;IACpB;;;;OAIG;IACH,KAAK,EAAE,QAAQ,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG;IAC5C,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5B,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;;OAGG;IACH,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,aAAa,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC5C,cAAc,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtC;;;;;OAKG;IACH,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,mFAAmF;IACnF,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC;;;OAGG;IACH,QAAQ,EAAE,QAAQ,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;CAC/C,CAAC;AAaF,eAAO,MAAM,iBAAiB,GAAI,SAAS,kBAAkB,KAAG,iBA8F/D,CAAC"}
@@ -1,43 +1,44 @@
1
1
  import { createDirtyTracker as e, createField as t } from "./field-base.js";
2
- import { computed as n, signal as r } from "@vielzeug/ripple";
2
+ import { syncedSignal as n } from "./signals.js";
3
+ import { computed as r } from "@vielzeug/ripple";
3
4
  import { watch as i } from "@vielzeug/ripple/watch";
4
5
  //#region src/core/choice-field.ts
5
6
  var a = (e) => e ? Array.isArray(e) ? e.filter(Boolean) : e.split(",").map((e) => e.trim()).filter(Boolean) : [], o = (o) => {
6
- let s = r([]), c = n(() => !!o.multiple?.value), l = n(() => c.value ? s.value.join(",") : s.value[0] ?? ""), u = (e) => {
7
- let t = c.value ? e : e.slice(0, 1);
7
+ let s = r(() => !!o.multiple?.value), c = (e) => {
8
+ let t = s.value ? e : e.slice(0, 1);
8
9
  return [...new Set(t.filter(Boolean))];
9
- }, d = e(), f = (e) => {
10
- s.value = u(e);
10
+ }, l = n(o.value, o.signal, (e) => c(a(e))), u = r(() => s.value ? l.value.join(",") : l.value[0] ?? ""), d = e(), f = (e) => {
11
+ l.value = c(e);
11
12
  }, p = (e) => {
12
13
  d.markDirty(), f(e);
13
14
  }, m = () => p([]), h = (e) => {
14
- d.markDirty(), s.value = s.value.filter((t) => t !== e);
15
+ d.markDirty(), l.value = l.value.filter((t) => t !== e);
15
16
  }, g = (e) => {
16
- if (c.value) {
17
- s.value.includes(e) || p([...s.value, e]);
17
+ if (s.value) {
18
+ l.value.includes(e) || p([...l.value, e]);
18
19
  return;
19
20
  }
20
21
  p([e]);
21
22
  }, _ = (e) => {
22
- c.value && s.value.includes(e) ? h(e) : g(e);
23
+ s.value && l.value.includes(e) ? h(e) : g(e);
23
24
  }, v = (e) => {
24
25
  f(a(e));
25
- }, y = t(o), b = n(() => o.required?.value && s.value.length === 0 ? { valueMissing: !0 } : null), x = n(() => b.value ? o.requiredMessage?.value || "Please make a selection." : ""), S = i(o.value, v, { immediate: !0 });
26
- if (o.signal.addEventListener("abort", () => S.dispose(), { once: !0 }), o.multiple) {
26
+ }, y = t(o), b = r(() => o.required?.value && l.value.length === 0 ? { valueMissing: !0 } : null), x = r(() => b.value ? o.requiredMessage?.value || "Please make a selection." : "");
27
+ if (o.multiple) {
27
28
  let e = i(o.multiple, () => v(o.value.value));
28
29
  o.signal.addEventListener("abort", () => e.dispose(), { once: !0 });
29
30
  }
30
- let C = s.value, w = () => {
31
- f(d.isDirty ? C : a(o.value.value)), d.clear(), y.triggerValidation("change");
31
+ let S = l.value, C = () => {
32
+ f(d.isDirty ? S : a(o.value.value)), d.clear(), y.triggerValidation("change");
32
33
  };
33
34
  return {
34
35
  ...y,
35
36
  clear: m,
36
- formValue: l,
37
+ formValue: u,
37
38
  removeValue: h,
38
- reset: w,
39
- selectedValue: n(() => s.value[0]),
40
- selectedValues: s,
39
+ reset: C,
40
+ selectedValue: r(() => l.value[0]),
41
+ selectedValues: l,
41
42
  selectValue: g,
42
43
  setValues: p,
43
44
  toggleValue: _,
@@ -1 +1 @@
1
- {"version":3,"file":"choice-field.js","names":[],"sources":["../../src/core/choice-field.ts"],"sourcesContent":["import { computed, type Readable, signal } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple/watch';\n\nimport { createDirtyTracker, createField, type FieldHandle, type FieldOptions } from './field-base';\n\n// ── Choice change event payload ──────────────────────────────────────────────────────────────\n\nexport type ChoiceChangeDetail = {\n labels: string[];\n originalEvent?: Event;\n values: string[];\n};\n\n// ── Choice field ──────────────────────────────────────────────────────────────────────\n\nexport type ChoiceFieldOptions = FieldOptions & {\n multiple?: Readable<boolean | undefined>;\n /** Marks an empty selection invalid — feeds `validity`/`validationMessage` (see below). */\n required?: Readable<boolean | undefined>;\n /** Message for the empty-selection+required case. Defaults to `'Please make a selection.'`. */\n requiredMessage?: Readable<string | undefined>;\n /** `AbortSignal` from the component lifecycle. All internal subscriptions are disposed on abort. */\n signal: AbortSignal;\n /**\n * Current selection value(s). Accepts a comma-separated string\n * (legacy/single-select form serialisation) or a `string[]` array.\n * The field normalises both formats internally via `parseChoiceValues`.\n */\n value: Readable<string | string[] | undefined>;\n};\n\nexport type ChoiceFieldHandle = FieldHandle & {\n clear: () => void;\n formValue: Readable<string>;\n removeValue: (value: string) => void;\n /**\n * Restores the selection to its native \"default\". See `DirtyTracker` for the two-state\n * rationale.\n */\n reset: () => void;\n selectedValue: Readable<string | undefined>;\n selectedValues: Readable<string[]>;\n selectValue: (value: string) => void;\n setValues: (values: string[]) => void;\n /**\n * Toggles `value` in the selection.\n * - **Multiple mode**: adds if absent, removes if present.\n * - **Single mode**: always selects `value` (acts like `selectValue` — cannot\n * deselect; use `clear()` to reset a single-select field).\n */\n toggleValue: (value: string) => void;\n /** Reactive validation message paired with `validity`. Empty string when valid. */\n validationMessage: Readable<string>;\n /**\n * Reactive `ValidityStateFlags` — `{ valueMissing: true }` while `required` and no option is\n * selected, `null` (valid) otherwise. Pass straight to `useField({ validity: choice.validity })`.\n */\n validity: Readable<ValidityStateFlags | null>;\n};\n\nconst parseChoiceValues = (raw: string | string[] | undefined): string[] => {\n if (!raw) return [];\n\n if (Array.isArray(raw)) return raw.filter(Boolean);\n\n return raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n};\n\nexport const createChoiceField = (options: ChoiceFieldOptions): ChoiceFieldHandle => {\n const selectedValues = signal<string[]>([]);\n const isMultiple = computed(() => Boolean(options.multiple?.value));\n const formValue = computed(() =>\n isMultiple.value ? selectedValues.value.join(',') : (selectedValues.value[0] ?? ''),\n );\n\n const normalizeValues = (values: string[]): string[] => {\n const normalized = isMultiple.value ? values : values.slice(0, 1);\n\n return [...new Set(normalized.filter(Boolean))];\n };\n\n const dirtyTracker = createDirtyTracker();\n\n // The actual state setter, shared by every mutation path. Deliberately *not* where the dirty\n // tracker gets marked — `syncFromProp` (below) calls this directly to stay exempt from it,\n // since mirroring an external prop change is never \"the user changed the selection\".\n const applyValues = (values: string[]): void => {\n selectedValues.value = normalizeValues(values);\n };\n\n const setValues = (values: string[]): void => {\n dirtyTracker.markDirty();\n applyValues(values);\n };\n const clear = (): void => setValues([]);\n const removeValue = (value: string): void => {\n dirtyTracker.markDirty();\n selectedValues.value = selectedValues.value.filter((v) => v !== value);\n };\n\n const selectValue = (value: string): void => {\n if (isMultiple.value) {\n if (!selectedValues.value.includes(value)) setValues([...selectedValues.value, value]);\n\n return;\n }\n\n setValues([value]);\n };\n\n const toggleValue = (value: string): void => {\n if (isMultiple.value) {\n if (selectedValues.value.includes(value)) removeValue(value);\n else selectValue(value);\n } else {\n selectValue(value);\n }\n };\n\n const syncFromProp = (nextValue: string | string[] | undefined): void => {\n applyValues(parseChoiceValues(nextValue));\n };\n\n const field = createField(options);\n\n const validity = computed<ValidityStateFlags | null>(() =>\n options.required?.value && selectedValues.value.length === 0 ? { valueMissing: true } : null,\n );\n const validationMessage = computed(() =>\n validity.value ? options.requiredMessage?.value || 'Please make a selection.' : '',\n );\n\n const valueSub = watch(options.value, syncFromProp, { immediate: true });\n\n options.signal.addEventListener('abort', () => valueSub.dispose(), { once: true });\n\n if (options.multiple) {\n const multipleSub = watch(options.multiple, () => syncFromProp(options.value.value));\n\n options.signal.addEventListener('abort', () => multipleSub.dispose(), { once: true });\n }\n\n const initialValues = selectedValues.value;\n const reset = (): void => {\n applyValues(dirtyTracker.isDirty ? initialValues : parseChoiceValues(options.value.value));\n dirtyTracker.clear();\n field.triggerValidation('change');\n };\n\n return {\n ...field,\n clear,\n formValue,\n removeValue,\n reset,\n selectedValue: computed(() => selectedValues.value[0]),\n selectedValues,\n selectValue,\n setValues,\n toggleValue,\n validationMessage,\n validity,\n };\n};\n"],"mappings":";;;;AA4DA,IAAM,KAAqB,MACpB,IAED,MAAM,QAAQ,CAAG,IAAU,EAAI,OAAO,OAAO,IAE1C,EACJ,MAAM,GAAG,CAAC,CACV,KAAK,MAAU,EAAM,KAAK,CAAC,CAAC,CAC5B,OAAO,OAAO,IAPA,CAAC,GAUP,KAAqB,MAAmD;CACnF,IAAM,IAAiB,EAAiB,CAAC,CAAC,GACpC,IAAa,QAAe,EAAQ,EAAQ,UAAU,KAAM,GAC5D,IAAY,QAChB,EAAW,QAAQ,EAAe,MAAM,KAAK,GAAG,IAAK,EAAe,MAAM,MAAM,EAClF,GAEM,KAAmB,MAA+B;EACtD,IAAM,IAAa,EAAW,QAAQ,IAAS,EAAO,MAAM,GAAG,CAAC;EAEhE,OAAO,CAAC,GAAG,IAAI,IAAI,EAAW,OAAO,OAAO,CAAC,CAAC;CAChD,GAEM,IAAe,EAAmB,GAKlC,KAAe,MAA2B;EAC9C,EAAe,QAAQ,EAAgB,CAAM;CAC/C,GAEM,KAAa,MAA2B;EAE5C,AADA,EAAa,UAAU,GACvB,EAAY,CAAM;CACpB,GACM,UAAoB,EAAU,CAAC,CAAC,GAChC,KAAe,MAAwB;EAE3C,AADA,EAAa,UAAU,GACvB,EAAe,QAAQ,EAAe,MAAM,QAAQ,MAAM,MAAM,CAAK;CACvE,GAEM,KAAe,MAAwB;EAC3C,IAAI,EAAW,OAAO;GACpB,AAAK,EAAe,MAAM,SAAS,CAAK,KAAG,EAAU,CAAC,GAAG,EAAe,OAAO,CAAK,CAAC;GAErF;EACF;EAEA,EAAU,CAAC,CAAK,CAAC;CACnB,GAEM,KAAe,MAAwB;EAC3C,AAAI,EAAW,SACT,EAAe,MAAM,SAAS,CAAK,IAAG,EAAY,CAAK,IACtD,EAAY,CAAK;CAI1B,GAEM,KAAgB,MAAmD;EACvE,EAAY,EAAkB,CAAS,CAAC;CAC1C,GAEM,IAAQ,EAAY,CAAO,GAE3B,IAAW,QACf,EAAQ,UAAU,SAAS,EAAe,MAAM,WAAW,IAAI,EAAE,cAAc,GAAK,IAAI,IAC1F,GACM,IAAoB,QACxB,EAAS,QAAQ,EAAQ,iBAAiB,SAAS,6BAA6B,EAClF,GAEM,IAAW,EAAM,EAAQ,OAAO,GAAc,EAAE,WAAW,GAAK,CAAC;CAIvE,IAFA,EAAQ,OAAO,iBAAiB,eAAe,EAAS,QAAQ,GAAG,EAAE,MAAM,GAAK,CAAC,GAE7E,EAAQ,UAAU;EACpB,IAAM,IAAc,EAAM,EAAQ,gBAAgB,EAAa,EAAQ,MAAM,KAAK,CAAC;EAEnF,EAAQ,OAAO,iBAAiB,eAAe,EAAY,QAAQ,GAAG,EAAE,MAAM,GAAK,CAAC;CACtF;CAEA,IAAM,IAAgB,EAAe,OAC/B,UAAoB;EAGxB,AAFA,EAAY,EAAa,UAAU,IAAgB,EAAkB,EAAQ,MAAM,KAAK,CAAC,GACzF,EAAa,MAAM,GACnB,EAAM,kBAAkB,QAAQ;CAClC;CAEA,OAAO;EACL,GAAG;EACH;EACA;EACA;EACA;EACA,eAAe,QAAe,EAAe,MAAM,EAAE;EACrD;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
1
+ {"version":3,"file":"choice-field.js","names":[],"sources":["../../src/core/choice-field.ts"],"sourcesContent":["import { computed, type Readable } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple/watch';\n\nimport { createDirtyTracker, createField, type FieldHandle, type FieldOptions } from './field-base';\nimport { syncedSignal } from './signals';\n\n// ── Choice change event payload ──────────────────────────────────────────────────────────────\n\nexport type ChoiceChangeDetail = {\n labels: string[];\n originalEvent?: Event;\n values: string[];\n};\n\n// ── Choice field ──────────────────────────────────────────────────────────────────────\n\nexport type ChoiceFieldOptions = FieldOptions & {\n multiple?: Readable<boolean | undefined>;\n /** Marks an empty selection invalid — feeds `validity`/`validationMessage` (see below). */\n required?: Readable<boolean | undefined>;\n /** Message for the empty-selection+required case. Defaults to `'Please make a selection.'`. */\n requiredMessage?: Readable<string | undefined>;\n /** `AbortSignal` from the component lifecycle. All internal subscriptions are disposed on abort. */\n signal: AbortSignal;\n /**\n * Current selection value(s). Accepts a comma-separated string\n * (legacy/single-select form serialisation) or a `string[]` array.\n * The field normalises both formats internally via `parseChoiceValues`.\n */\n value: Readable<string | string[] | undefined>;\n};\n\nexport type ChoiceFieldHandle = FieldHandle & {\n clear: () => void;\n formValue: Readable<string>;\n removeValue: (value: string) => void;\n /**\n * Restores the selection to its native \"default\". See `DirtyTracker` for the two-state\n * rationale.\n */\n reset: () => void;\n selectedValue: Readable<string | undefined>;\n selectedValues: Readable<string[]>;\n selectValue: (value: string) => void;\n setValues: (values: string[]) => void;\n /**\n * Toggles `value` in the selection.\n * - **Multiple mode**: adds if absent, removes if present.\n * - **Single mode**: always selects `value` (acts like `selectValue` — cannot\n * deselect; use `clear()` to reset a single-select field).\n */\n toggleValue: (value: string) => void;\n /** Reactive validation message paired with `validity`. Empty string when valid. */\n validationMessage: Readable<string>;\n /**\n * Reactive `ValidityStateFlags` — `{ valueMissing: true }` while `required` and no option is\n * selected, `null` (valid) otherwise. Pass straight to `useField({ validity: choice.validity })`.\n */\n validity: Readable<ValidityStateFlags | null>;\n};\n\nconst parseChoiceValues = (raw: string | string[] | undefined): string[] => {\n if (!raw) return [];\n\n if (Array.isArray(raw)) return raw.filter(Boolean);\n\n return raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n};\n\nexport const createChoiceField = (options: ChoiceFieldOptions): ChoiceFieldHandle => {\n const isMultiple = computed(() => Boolean(options.multiple?.value));\n\n const normalizeValues = (values: string[]): string[] => {\n const normalized = isMultiple.value ? values : values.slice(0, 1);\n\n return [...new Set(normalized.filter(Boolean))];\n };\n\n // Kept in sync with `options.value` via the shared helper (see `checkable.ts`/`text-field.ts`\n // for the same pattern) rather than a hand-rolled signal + watch pair.\n const selectedValues = syncedSignal(options.value, options.signal, (raw) => normalizeValues(parseChoiceValues(raw)));\n const formValue = computed(() =>\n isMultiple.value ? selectedValues.value.join(',') : (selectedValues.value[0] ?? ''),\n );\n\n const dirtyTracker = createDirtyTracker();\n\n // The actual state setter, shared by every mutation path. Deliberately *not* where the dirty\n // tracker gets marked — `syncFromProp` (below) calls this directly to stay exempt from it,\n // since mirroring an external prop change is never \"the user changed the selection\".\n const applyValues = (values: string[]): void => {\n selectedValues.value = normalizeValues(values);\n };\n\n const setValues = (values: string[]): void => {\n dirtyTracker.markDirty();\n applyValues(values);\n };\n const clear = (): void => setValues([]);\n const removeValue = (value: string): void => {\n dirtyTracker.markDirty();\n selectedValues.value = selectedValues.value.filter((v) => v !== value);\n };\n\n const selectValue = (value: string): void => {\n if (isMultiple.value) {\n if (!selectedValues.value.includes(value)) setValues([...selectedValues.value, value]);\n\n return;\n }\n\n setValues([value]);\n };\n\n const toggleValue = (value: string): void => {\n if (isMultiple.value) {\n if (selectedValues.value.includes(value)) removeValue(value);\n else selectValue(value);\n } else {\n selectValue(value);\n }\n };\n\n const syncFromProp = (nextValue: string | string[] | undefined): void => {\n applyValues(parseChoiceValues(nextValue));\n };\n\n const field = createField(options);\n\n const validity = computed<ValidityStateFlags | null>(() =>\n options.required?.value && selectedValues.value.length === 0 ? { valueMissing: true } : null,\n );\n const validationMessage = computed(() =>\n validity.value ? options.requiredMessage?.value || 'Please make a selection.' : '',\n );\n\n if (options.multiple) {\n const multipleSub = watch(options.multiple, () => syncFromProp(options.value.value));\n\n options.signal.addEventListener('abort', () => multipleSub.dispose(), { once: true });\n }\n\n const initialValues = selectedValues.value;\n const reset = (): void => {\n applyValues(dirtyTracker.isDirty ? initialValues : parseChoiceValues(options.value.value));\n dirtyTracker.clear();\n field.triggerValidation('change');\n };\n\n return {\n ...field,\n clear,\n formValue,\n removeValue,\n reset,\n selectedValue: computed(() => selectedValues.value[0]),\n selectedValues,\n selectValue,\n setValues,\n toggleValue,\n validationMessage,\n validity,\n };\n};\n"],"mappings":";;;;;AA6DA,IAAM,KAAqB,MACpB,IAED,MAAM,QAAQ,CAAG,IAAU,EAAI,OAAO,OAAO,IAE1C,EACJ,MAAM,GAAG,CAAC,CACV,KAAK,MAAU,EAAM,KAAK,CAAC,CAAC,CAC5B,OAAO,OAAO,IAPA,CAAC,GAUP,KAAqB,MAAmD;CACnF,IAAM,IAAa,QAAe,EAAQ,EAAQ,UAAU,KAAM,GAE5D,KAAmB,MAA+B;EACtD,IAAM,IAAa,EAAW,QAAQ,IAAS,EAAO,MAAM,GAAG,CAAC;EAEhE,OAAO,CAAC,GAAG,IAAI,IAAI,EAAW,OAAO,OAAO,CAAC,CAAC;CAChD,GAIM,IAAiB,EAAa,EAAQ,OAAO,EAAQ,SAAS,MAAQ,EAAgB,EAAkB,CAAG,CAAC,CAAC,GAC7G,IAAY,QAChB,EAAW,QAAQ,EAAe,MAAM,KAAK,GAAG,IAAK,EAAe,MAAM,MAAM,EAClF,GAEM,IAAe,EAAmB,GAKlC,KAAe,MAA2B;EAC9C,EAAe,QAAQ,EAAgB,CAAM;CAC/C,GAEM,KAAa,MAA2B;EAE5C,AADA,EAAa,UAAU,GACvB,EAAY,CAAM;CACpB,GACM,UAAoB,EAAU,CAAC,CAAC,GAChC,KAAe,MAAwB;EAE3C,AADA,EAAa,UAAU,GACvB,EAAe,QAAQ,EAAe,MAAM,QAAQ,MAAM,MAAM,CAAK;CACvE,GAEM,KAAe,MAAwB;EAC3C,IAAI,EAAW,OAAO;GACpB,AAAK,EAAe,MAAM,SAAS,CAAK,KAAG,EAAU,CAAC,GAAG,EAAe,OAAO,CAAK,CAAC;GAErF;EACF;EAEA,EAAU,CAAC,CAAK,CAAC;CACnB,GAEM,KAAe,MAAwB;EAC3C,AAAI,EAAW,SACT,EAAe,MAAM,SAAS,CAAK,IAAG,EAAY,CAAK,IACtD,EAAY,CAAK;CAI1B,GAEM,KAAgB,MAAmD;EACvE,EAAY,EAAkB,CAAS,CAAC;CAC1C,GAEM,IAAQ,EAAY,CAAO,GAE3B,IAAW,QACf,EAAQ,UAAU,SAAS,EAAe,MAAM,WAAW,IAAI,EAAE,cAAc,GAAK,IAAI,IAC1F,GACM,IAAoB,QACxB,EAAS,QAAQ,EAAQ,iBAAiB,SAAS,6BAA6B,EAClF;CAEA,IAAI,EAAQ,UAAU;EACpB,IAAM,IAAc,EAAM,EAAQ,gBAAgB,EAAa,EAAQ,MAAM,KAAK,CAAC;EAEnF,EAAQ,OAAO,iBAAiB,eAAe,EAAY,QAAQ,GAAG,EAAE,MAAM,GAAK,CAAC;CACtF;CAEA,IAAM,IAAgB,EAAe,OAC/B,UAAoB;EAGxB,AAFA,EAAY,EAAa,UAAU,IAAgB,EAAkB,EAAQ,MAAM,KAAK,CAAC,GACzF,EAAa,MAAM,GACnB,EAAM,kBAAkB,QAAQ;CAClC;CAEA,OAAO;EACL,GAAG;EACH;EACA;EACA;EACA;EACA,eAAe,QAAe,EAAe,MAAM,EAAE;EACrD;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
@@ -1,2 +1,2 @@
1
- function e(e){let t=null,n=null,r=()=>{n!==null&&(cancelAnimationFrame(n),n=null)};return e.signal?.addEventListener(`abort`,r,{once:!0}),{applyInitialFocus(){r();let t=e.getInitialFocusSelector();if(t){let r=e.host.shadowRoot??e.host,i=null;try{i=r.querySelector(t)}catch{return}i&&(n=requestAnimationFrame(()=>{n=null,i.focus()}))}},cancelInitialFocus:r,captureReturnFocus(){t=document.activeElement},restoreFocus(){e.getReturnFocus()!==!1&&t&&(t.focus(),t=null)}}}exports.createFocusManager=e;
1
+ function e(e){let t=null,n=null,r=!1,i=()=>{n!==null&&(cancelAnimationFrame(n),n=null)},a=()=>{r||(r=!0,i(),t=null)};return e.signal?.addEventListener(`abort`,a,{once:!0}),{applyInitialFocus(){i();let t=e.getInitialFocusSelector();if(t){let r=e.host.shadowRoot??e.host,i=null;try{i=r.querySelector(t)}catch{return}i&&(n=requestAnimationFrame(()=>{n=null,i.focus()}))}},cancelInitialFocus:i,captureReturnFocus(){t=document.activeElement},dispose:a,get disposed(){return r},restoreFocus(){e.getReturnFocus()!==!1&&t&&(t.focus(),t=null)},[Symbol.dispose]:a}}exports.createFocusManager=e;
2
2
  //# sourceMappingURL=focus.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"focus.cjs","names":[],"sources":["../../src/core/focus.ts"],"sourcesContent":["// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type FocusManagerOptions = {\n /**\n * Returns the CSS selector for the element that should receive focus on open.\n *\n * **Security note:** this value is passed directly to `querySelector`. It must\n * come from trusted developer-controlled configuration, never from raw user input.\n */\n getInitialFocusSelector: () => string | undefined;\n /**\n * Returns whether focus should be restored to the previously focused element\n * on close. `undefined` or `true` means restore; `false` means skip.\n */\n getReturnFocus: () => boolean | undefined;\n /** Host element used for `querySelector` when resolving the initial focus target. */\n host: HTMLElement;\n /**\n * `AbortSignal` from the component lifecycle. Cancels a pending `applyInitialFocus()`\n * animation frame automatically on abort — prevents a stray `.focus()` call landing on an\n * element that's been disconnected in the meantime (e.g. the dialog closes and unmounts\n * before the deferred focus frame runs).\n */\n signal?: AbortSignal;\n};\n\nexport type FocusManager = {\n /** Move focus to the element matching `getInitialFocusSelector` (deferred one frame). */\n applyInitialFocus: () => void;\n /** Cancel a pending `applyInitialFocus` rAF, if any. */\n cancelInitialFocus: () => void;\n /** Capture the currently focused element so it can be restored later. */\n captureReturnFocus: () => void;\n /** Restore focus to the element captured by `captureReturnFocus`. */\n restoreFocus: () => void;\n};\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Encapsulates the three-step focus lifecycle used by dialogs and drawers:\n * 1. Capture the element that triggered the open.\n * 2. Move focus inside the overlay (optionally to a specific element).\n * 3. Restore focus when the overlay closes.\n */\nexport function createFocusManager(options: FocusManagerOptions): FocusManager {\n let returnFocusEl: HTMLElement | null = null;\n let rafHandle: ReturnType<typeof requestAnimationFrame> | null = null;\n\n const cancelInitialFocus = (): void => {\n if (rafHandle !== null) {\n cancelAnimationFrame(rafHandle);\n rafHandle = null;\n }\n };\n\n options.signal?.addEventListener('abort', cancelInitialFocus, { once: true });\n\n return {\n applyInitialFocus() {\n cancelInitialFocus();\n\n const selector = options.getInitialFocusSelector();\n\n if (selector) {\n // Query the shadow root first (all refine components render into Shadow DOM),\n // falling back to the host's light-DOM tree for non-Shadow contexts.\n const root = options.host.shadowRoot ?? options.host;\n\n let target: HTMLElement | null = null;\n\n try {\n target = root.querySelector<HTMLElement>(selector);\n } catch {\n // Malformed selector (SyntaxError) — skip initial focus rather than throw.\n return;\n }\n\n if (target) {\n rafHandle = requestAnimationFrame(() => {\n rafHandle = null;\n target.focus();\n });\n }\n }\n },\n\n cancelInitialFocus,\n\n captureReturnFocus() {\n returnFocusEl = document.activeElement as HTMLElement;\n },\n\n restoreFocus() {\n if (options.getReturnFocus() !== false && returnFocusEl) {\n returnFocusEl.focus();\n returnFocusEl = null;\n }\n },\n };\n}\n"],"mappings":"AA6CA,SAAgB,EAAmB,EAA4C,CAC7E,IAAI,EAAoC,KACpC,EAA6D,KAE3D,MAAiC,CACjC,IAAc,OAChB,qBAAqB,CAAS,EAC9B,EAAY,KAEhB,EAIA,OAFA,EAAQ,QAAQ,iBAAiB,QAAS,EAAoB,CAAE,KAAM,EAAK,CAAC,EAErE,CACL,mBAAoB,CAClB,EAAmB,EAEnB,IAAM,EAAW,EAAQ,wBAAwB,EAEjD,GAAI,EAAU,CAGZ,IAAM,EAAO,EAAQ,KAAK,YAAc,EAAQ,KAE5C,EAA6B,KAEjC,GAAI,CACF,EAAS,EAAK,cAA2B,CAAQ,CACnD,MAAQ,CAEN,MACF,CAEI,IACF,EAAY,0BAA4B,CACtC,EAAY,KACZ,EAAO,MAAM,CACf,CAAC,EAEL,CACF,EAEA,qBAEA,oBAAqB,CACnB,EAAgB,SAAS,aAC3B,EAEA,cAAe,CACT,EAAQ,eAAe,IAAM,IAAS,IACxC,EAAc,MAAM,EACpB,EAAgB,KAEpB,CACF,CACF"}
1
+ {"version":3,"file":"focus.cjs","names":[],"sources":["../../src/core/focus.ts"],"sourcesContent":["// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type FocusManagerOptions = {\n /**\n * Returns the CSS selector for the element that should receive focus on open.\n *\n * **Security note:** this value is passed directly to `querySelector`. It must\n * come from trusted developer-controlled configuration, never from raw user input.\n */\n getInitialFocusSelector: () => string | undefined;\n /**\n * Returns whether focus should be restored to the previously focused element\n * on close. `undefined` or `true` means restore; `false` means skip.\n */\n getReturnFocus: () => boolean | undefined;\n /** Host element used for `querySelector` when resolving the initial focus target. */\n host: HTMLElement;\n /**\n * `AbortSignal` from the component lifecycle. Cancels a pending `applyInitialFocus()`\n * animation frame automatically on abort — prevents a stray `.focus()` call landing on an\n * element that's been disconnected in the meantime (e.g. the dialog closes and unmounts\n * before the deferred focus frame runs).\n */\n signal?: AbortSignal;\n};\n\nexport type FocusManager = {\n [Symbol.dispose](): void;\n /** Move focus to the element matching `getInitialFocusSelector` (deferred one frame). */\n applyInitialFocus: () => void;\n /** Cancel a pending `applyInitialFocus` rAF, if any. */\n cancelInitialFocus: () => void;\n /** Capture the currently focused element so it can be restored later. */\n captureReturnFocus: () => void;\n /** Cancels any pending initial-focus frame and clears captured return-focus state. */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n /** Restore focus to the element captured by `captureReturnFocus`. */\n restoreFocus: () => void;\n};\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Encapsulates the three-step focus lifecycle used by dialogs and drawers:\n * 1. Capture the element that triggered the open.\n * 2. Move focus inside the overlay (optionally to a specific element).\n * 3. Restore focus when the overlay closes.\n */\nexport function createFocusManager(options: FocusManagerOptions): FocusManager {\n let returnFocusEl: HTMLElement | null = null;\n let rafHandle: ReturnType<typeof requestAnimationFrame> | null = null;\n let disposed = false;\n\n const cancelInitialFocus = (): void => {\n if (rafHandle !== null) {\n cancelAnimationFrame(rafHandle);\n rafHandle = null;\n }\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n cancelInitialFocus();\n returnFocusEl = null;\n };\n\n options.signal?.addEventListener('abort', dispose, { once: true });\n\n return {\n applyInitialFocus() {\n cancelInitialFocus();\n\n const selector = options.getInitialFocusSelector();\n\n if (selector) {\n // Query the shadow root first (all refine components render into Shadow DOM),\n // falling back to the host's light-DOM tree for non-Shadow contexts.\n const root = options.host.shadowRoot ?? options.host;\n\n let target: HTMLElement | null = null;\n\n try {\n target = root.querySelector<HTMLElement>(selector);\n } catch {\n // Malformed selector (SyntaxError) — skip initial focus rather than throw.\n return;\n }\n\n if (target) {\n rafHandle = requestAnimationFrame(() => {\n rafHandle = null;\n target.focus();\n });\n }\n }\n },\n cancelInitialFocus,\n\n captureReturnFocus() {\n returnFocusEl = document.activeElement as HTMLElement;\n },\n\n dispose,\n\n get disposed() {\n return disposed;\n },\n\n restoreFocus() {\n if (options.getReturnFocus() !== false && returnFocusEl) {\n returnFocusEl.focus();\n returnFocusEl = null;\n }\n },\n\n [Symbol.dispose]: dispose,\n };\n}\n"],"mappings":"AAkDA,SAAgB,EAAmB,EAA4C,CAC7E,IAAI,EAAoC,KACpC,EAA6D,KAC7D,EAAW,GAET,MAAiC,CACjC,IAAc,OAChB,qBAAqB,CAAS,EAC9B,EAAY,KAEhB,EAEM,MAAsB,CACtB,IAEJ,EAAW,GACX,EAAmB,EACnB,EAAgB,KAClB,EAIA,OAFA,EAAQ,QAAQ,iBAAiB,QAAS,EAAS,CAAE,KAAM,EAAK,CAAC,EAE1D,CACL,mBAAoB,CAClB,EAAmB,EAEnB,IAAM,EAAW,EAAQ,wBAAwB,EAEjD,GAAI,EAAU,CAGZ,IAAM,EAAO,EAAQ,KAAK,YAAc,EAAQ,KAE5C,EAA6B,KAEjC,GAAI,CACF,EAAS,EAAK,cAA2B,CAAQ,CACnD,MAAQ,CAEN,MACF,CAEI,IACF,EAAY,0BAA4B,CACtC,EAAY,KACZ,EAAO,MAAM,CACf,CAAC,EAEL,CACF,EACA,qBAEA,oBAAqB,CACnB,EAAgB,SAAS,aAC3B,EAEA,UAEA,IAAI,UAAW,CACb,OAAO,CACT,EAEA,cAAe,CACT,EAAQ,eAAe,IAAM,IAAS,IACxC,EAAc,MAAM,EACpB,EAAgB,KAEpB,GAEC,OAAO,SAAU,CACpB,CACF"}
@@ -22,12 +22,17 @@ export type FocusManagerOptions = {
22
22
  signal?: AbortSignal;
23
23
  };
24
24
  export type FocusManager = {
25
+ [Symbol.dispose](): void;
25
26
  /** Move focus to the element matching `getInitialFocusSelector` (deferred one frame). */
26
27
  applyInitialFocus: () => void;
27
28
  /** Cancel a pending `applyInitialFocus` rAF, if any. */
28
29
  cancelInitialFocus: () => void;
29
30
  /** Capture the currently focused element so it can be restored later. */
30
31
  captureReturnFocus: () => void;
32
+ /** Cancels any pending initial-focus frame and clears captured return-focus state. */
33
+ dispose(): void;
34
+ /** `true` after `dispose()` has been called. */
35
+ readonly disposed: boolean;
31
36
  /** Restore focus to the element captured by `captureReturnFocus`. */
32
37
  restoreFocus: () => void;
33
38
  };
@@ -1 +1 @@
1
- {"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../src/core/focus.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;;OAKG;IACH,uBAAuB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAClD;;;OAGG;IACH,cAAc,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IAC1C,qFAAqF;IACrF,IAAI,EAAE,WAAW,CAAC;IAClB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,yFAAyF;IACzF,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,wDAAwD;IACxD,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,yEAAyE;IACzE,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,qEAAqE;IACrE,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC;AAIF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAuD7E"}
1
+ {"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../src/core/focus.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;;OAKG;IACH,uBAAuB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAClD;;;OAGG;IACH,cAAc,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IAC1C,qFAAqF;IACrF,IAAI,EAAE,WAAW,CAAC;IAClB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IACzB,yFAAyF;IACzF,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,wDAAwD;IACxD,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,yEAAyE;IACzE,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,sFAAsF;IACtF,OAAO,IAAI,IAAI,CAAC;IAChB,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,qEAAqE;IACrE,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC;AAIF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAuE7E"}
@@ -1,11 +1,13 @@
1
1
  //#region src/core/focus.ts
2
2
  function e(e) {
3
- let t = null, n = null, r = () => {
3
+ let t = null, n = null, r = !1, i = () => {
4
4
  n !== null && (cancelAnimationFrame(n), n = null);
5
+ }, a = () => {
6
+ r || (r = !0, i(), t = null);
5
7
  };
6
- return e.signal?.addEventListener("abort", r, { once: !0 }), {
8
+ return e.signal?.addEventListener("abort", a, { once: !0 }), {
7
9
  applyInitialFocus() {
8
- r();
10
+ i();
9
11
  let t = e.getInitialFocusSelector();
10
12
  if (t) {
11
13
  let r = e.host.shadowRoot ?? e.host, i = null;
@@ -19,13 +21,18 @@ function e(e) {
19
21
  }));
20
22
  }
21
23
  },
22
- cancelInitialFocus: r,
24
+ cancelInitialFocus: i,
23
25
  captureReturnFocus() {
24
26
  t = document.activeElement;
25
27
  },
28
+ dispose: a,
29
+ get disposed() {
30
+ return r;
31
+ },
26
32
  restoreFocus() {
27
33
  e.getReturnFocus() !== !1 && t && (t.focus(), t = null);
28
- }
34
+ },
35
+ [Symbol.dispose]: a
29
36
  };
30
37
  }
31
38
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"focus.js","names":[],"sources":["../../src/core/focus.ts"],"sourcesContent":["// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type FocusManagerOptions = {\n /**\n * Returns the CSS selector for the element that should receive focus on open.\n *\n * **Security note:** this value is passed directly to `querySelector`. It must\n * come from trusted developer-controlled configuration, never from raw user input.\n */\n getInitialFocusSelector: () => string | undefined;\n /**\n * Returns whether focus should be restored to the previously focused element\n * on close. `undefined` or `true` means restore; `false` means skip.\n */\n getReturnFocus: () => boolean | undefined;\n /** Host element used for `querySelector` when resolving the initial focus target. */\n host: HTMLElement;\n /**\n * `AbortSignal` from the component lifecycle. Cancels a pending `applyInitialFocus()`\n * animation frame automatically on abort — prevents a stray `.focus()` call landing on an\n * element that's been disconnected in the meantime (e.g. the dialog closes and unmounts\n * before the deferred focus frame runs).\n */\n signal?: AbortSignal;\n};\n\nexport type FocusManager = {\n /** Move focus to the element matching `getInitialFocusSelector` (deferred one frame). */\n applyInitialFocus: () => void;\n /** Cancel a pending `applyInitialFocus` rAF, if any. */\n cancelInitialFocus: () => void;\n /** Capture the currently focused element so it can be restored later. */\n captureReturnFocus: () => void;\n /** Restore focus to the element captured by `captureReturnFocus`. */\n restoreFocus: () => void;\n};\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Encapsulates the three-step focus lifecycle used by dialogs and drawers:\n * 1. Capture the element that triggered the open.\n * 2. Move focus inside the overlay (optionally to a specific element).\n * 3. Restore focus when the overlay closes.\n */\nexport function createFocusManager(options: FocusManagerOptions): FocusManager {\n let returnFocusEl: HTMLElement | null = null;\n let rafHandle: ReturnType<typeof requestAnimationFrame> | null = null;\n\n const cancelInitialFocus = (): void => {\n if (rafHandle !== null) {\n cancelAnimationFrame(rafHandle);\n rafHandle = null;\n }\n };\n\n options.signal?.addEventListener('abort', cancelInitialFocus, { once: true });\n\n return {\n applyInitialFocus() {\n cancelInitialFocus();\n\n const selector = options.getInitialFocusSelector();\n\n if (selector) {\n // Query the shadow root first (all refine components render into Shadow DOM),\n // falling back to the host's light-DOM tree for non-Shadow contexts.\n const root = options.host.shadowRoot ?? options.host;\n\n let target: HTMLElement | null = null;\n\n try {\n target = root.querySelector<HTMLElement>(selector);\n } catch {\n // Malformed selector (SyntaxError) — skip initial focus rather than throw.\n return;\n }\n\n if (target) {\n rafHandle = requestAnimationFrame(() => {\n rafHandle = null;\n target.focus();\n });\n }\n }\n },\n\n cancelInitialFocus,\n\n captureReturnFocus() {\n returnFocusEl = document.activeElement as HTMLElement;\n },\n\n restoreFocus() {\n if (options.getReturnFocus() !== false && returnFocusEl) {\n returnFocusEl.focus();\n returnFocusEl = null;\n }\n },\n };\n}\n"],"mappings":";AA6CA,SAAgB,EAAmB,GAA4C;CAC7E,IAAI,IAAoC,MACpC,IAA6D,MAE3D,UAAiC;EACrC,AAAI,MAAc,SAChB,qBAAqB,CAAS,GAC9B,IAAY;CAEhB;CAIA,OAFA,EAAQ,QAAQ,iBAAiB,SAAS,GAAoB,EAAE,MAAM,GAAK,CAAC,GAErE;EACL,oBAAoB;GAClB,EAAmB;GAEnB,IAAM,IAAW,EAAQ,wBAAwB;GAEjD,IAAI,GAAU;IAGZ,IAAM,IAAO,EAAQ,KAAK,cAAc,EAAQ,MAE5C,IAA6B;IAEjC,IAAI;KACF,IAAS,EAAK,cAA2B,CAAQ;IACnD,QAAQ;KAEN;IACF;IAEA,AAAI,MACF,IAAY,4BAA4B;KAEtC,AADA,IAAY,MACZ,EAAO,MAAM;IACf,CAAC;GAEL;EACF;EAEA;EAEA,qBAAqB;GACnB,IAAgB,SAAS;EAC3B;EAEA,eAAe;GACb,AAAI,EAAQ,eAAe,MAAM,MAAS,MACxC,EAAc,MAAM,GACpB,IAAgB;EAEpB;CACF;AACF"}
1
+ {"version":3,"file":"focus.js","names":[],"sources":["../../src/core/focus.ts"],"sourcesContent":["// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type FocusManagerOptions = {\n /**\n * Returns the CSS selector for the element that should receive focus on open.\n *\n * **Security note:** this value is passed directly to `querySelector`. It must\n * come from trusted developer-controlled configuration, never from raw user input.\n */\n getInitialFocusSelector: () => string | undefined;\n /**\n * Returns whether focus should be restored to the previously focused element\n * on close. `undefined` or `true` means restore; `false` means skip.\n */\n getReturnFocus: () => boolean | undefined;\n /** Host element used for `querySelector` when resolving the initial focus target. */\n host: HTMLElement;\n /**\n * `AbortSignal` from the component lifecycle. Cancels a pending `applyInitialFocus()`\n * animation frame automatically on abort — prevents a stray `.focus()` call landing on an\n * element that's been disconnected in the meantime (e.g. the dialog closes and unmounts\n * before the deferred focus frame runs).\n */\n signal?: AbortSignal;\n};\n\nexport type FocusManager = {\n [Symbol.dispose](): void;\n /** Move focus to the element matching `getInitialFocusSelector` (deferred one frame). */\n applyInitialFocus: () => void;\n /** Cancel a pending `applyInitialFocus` rAF, if any. */\n cancelInitialFocus: () => void;\n /** Capture the currently focused element so it can be restored later. */\n captureReturnFocus: () => void;\n /** Cancels any pending initial-focus frame and clears captured return-focus state. */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n /** Restore focus to the element captured by `captureReturnFocus`. */\n restoreFocus: () => void;\n};\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Encapsulates the three-step focus lifecycle used by dialogs and drawers:\n * 1. Capture the element that triggered the open.\n * 2. Move focus inside the overlay (optionally to a specific element).\n * 3. Restore focus when the overlay closes.\n */\nexport function createFocusManager(options: FocusManagerOptions): FocusManager {\n let returnFocusEl: HTMLElement | null = null;\n let rafHandle: ReturnType<typeof requestAnimationFrame> | null = null;\n let disposed = false;\n\n const cancelInitialFocus = (): void => {\n if (rafHandle !== null) {\n cancelAnimationFrame(rafHandle);\n rafHandle = null;\n }\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n cancelInitialFocus();\n returnFocusEl = null;\n };\n\n options.signal?.addEventListener('abort', dispose, { once: true });\n\n return {\n applyInitialFocus() {\n cancelInitialFocus();\n\n const selector = options.getInitialFocusSelector();\n\n if (selector) {\n // Query the shadow root first (all refine components render into Shadow DOM),\n // falling back to the host's light-DOM tree for non-Shadow contexts.\n const root = options.host.shadowRoot ?? options.host;\n\n let target: HTMLElement | null = null;\n\n try {\n target = root.querySelector<HTMLElement>(selector);\n } catch {\n // Malformed selector (SyntaxError) — skip initial focus rather than throw.\n return;\n }\n\n if (target) {\n rafHandle = requestAnimationFrame(() => {\n rafHandle = null;\n target.focus();\n });\n }\n }\n },\n cancelInitialFocus,\n\n captureReturnFocus() {\n returnFocusEl = document.activeElement as HTMLElement;\n },\n\n dispose,\n\n get disposed() {\n return disposed;\n },\n\n restoreFocus() {\n if (options.getReturnFocus() !== false && returnFocusEl) {\n returnFocusEl.focus();\n returnFocusEl = null;\n }\n },\n\n [Symbol.dispose]: dispose,\n };\n}\n"],"mappings":";AAkDA,SAAgB,EAAmB,GAA4C;CAC7E,IAAI,IAAoC,MACpC,IAA6D,MAC7D,IAAW,IAET,UAAiC;EACrC,AAAI,MAAc,SAChB,qBAAqB,CAAS,GAC9B,IAAY;CAEhB,GAEM,UAAsB;EACtB,MAEJ,IAAW,IACX,EAAmB,GACnB,IAAgB;CAClB;CAIA,OAFA,EAAQ,QAAQ,iBAAiB,SAAS,GAAS,EAAE,MAAM,GAAK,CAAC,GAE1D;EACL,oBAAoB;GAClB,EAAmB;GAEnB,IAAM,IAAW,EAAQ,wBAAwB;GAEjD,IAAI,GAAU;IAGZ,IAAM,IAAO,EAAQ,KAAK,cAAc,EAAQ,MAE5C,IAA6B;IAEjC,IAAI;KACF,IAAS,EAAK,cAA2B,CAAQ;IACnD,QAAQ;KAEN;IACF;IAEA,AAAI,MACF,IAAY,4BAA4B;KAEtC,AADA,IAAY,MACZ,EAAO,MAAM;IACf,CAAC;GAEL;EACF;EACA;EAEA,qBAAqB;GACnB,IAAgB,SAAS;EAC3B;EAEA;EAEA,IAAI,WAAW;GACb,OAAO;EACT;EAEA,eAAe;GACb,AAAI,EAAQ,eAAe,MAAM,MAAS,MACxC,EAAc,MAAM,GACpB,IAAgB;EAEpB;GAEC,OAAO,UAAU;CACpB;AACF"}
@@ -8,13 +8,13 @@ export { lifecycleSignal } from './ore';
8
8
  export { createAutoResize, type AutoResizeControl, type AutoResizeOptions } from './auto-resize';
9
9
  export { bindRefCallback, type RefCallback } from './ref-callback';
10
10
  export { setAriaReflection, type AriaReflectionProperty } from './aria-reflection';
11
+ export { createFocusManager, type FocusManager, type FocusManagerOptions } from './focus';
11
12
  export { counterClassName, createAssistiveState, createDirtyTracker, createErrorHelperState, createField, createLabelState, type AssistiveStateHandle, type AssistiveStateOptions, type ControlValidationMode, type CounterOptions, type CounterState, type DirtyTracker, type ErrorHelperOptions, type ErrorHelperState, type FieldHandle, type FieldOptions, type LabelPlacement, type LabelStateHandle, type LabelStateOptions, type ValidationTrigger, } from './field-base';
12
13
  export { createTextField, type TextFieldDetach, type TextFieldHandle, type TextFieldOptions } from './text-field';
13
14
  export { createChoiceField, type ChoiceChangeDetail, type ChoiceFieldHandle, type ChoiceFieldOptions, } from './choice-field';
14
15
  export { createCheckable, type CheckableChangePayload, type CheckableHandle, type CheckableOptions } from './checkable';
15
16
  export { createComposerControl, type ComposerControl, type ComposerControlOptions, type SendShortcut, } from './composer';
16
- export { type DialogCloseReason, type DropdownCloseReason, type OverlayCloseDetail, type OverlayOpenChangeDetail, type OverlayOpenDetail, type OverlayOpenReason, } from './overlay';
17
- export { createPaginatedList, type PaginatedListHandle, type PaginatedListOptions } from './paginated-list';
17
+ export { createOutsidePointerDismissal, restoreTriggerFocus, type DialogCloseReason, type DropdownCloseReason, type OutsidePointerDismissalOptions, type OverlayCloseDetail, type OverlayOpenChangeDetail, type OverlayOpenDetail, type OverlayOpenReason, } from './overlay';
18
18
  export { type ListKeyAction, type ListNavigationAction } from './nav';
19
19
  export { createSpinnerControl, type SpinnerControl, type SpinnerControlOptions } from './spinner';
20
20
  export { createSliderControl, type SliderControl, type SliderControlOptions } from './slider';
@@ -26,7 +26,7 @@ export { toFiniteNumber, toFiniteNumberOr, toPositiveStep } from './numbers';
26
26
  export { createDropdownPositioner, type DropdownPositionerOptions, type OverlayPositioner } from './positioner';
27
27
  export { createInteraction, dispatchKeyboardAction, type Interaction, type InteractionOptions, type KeyboardDispatchOptions, type PressTrigger, } from './keyboard';
28
28
  export { createListControl, type ListControl, type ListNavigationOptions } from './nav';
29
- export { createTypeahead, type Typeahead, type TypeaheadOptions } from './typeahead';
29
+ export { createListboxDropdown, type ListboxDropdown, type ListboxDropdownOptions, type ListboxDropdownPlacementOptions, } from './option-list';
30
30
  export { elementDirection } from './direction';
31
31
  export { parseStringTriggers } from './parse';
32
32
  export { syncedSignal } from './signals';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("../errors.cjs"),t=require("./positioner.cjs"),n=require("./nav.cjs"),r=require("./overlay.cjs");let i=require("@vielzeug/ripple");var a=a=>{if(typeof a.getBoundary!=`function`)throw new e.RefineConfigError(`createListboxDropdown: getBoundary is required`);if(typeof a.getPanel!=`function`)throw new e.RefineConfigError(`createListboxDropdown: getPanel is required`);if(typeof a.getReference!=`function`)throw new e.RefineConfigError(`createListboxDropdown: getReference is required`);let o=(0,i.signal)(!1),s=(0,i.computed)(()=>String(o.value)),c=null,l=t.createDropdownPositioner({...a.positioning,getFloating:a.getPanel,getReference:a.getReference}),u=()=>{a.getFocusedOptionElement?.()?.scrollIntoView({block:`nearest`})},d=n.createListControl({disabled:(0,i.computed)(()=>!o.value),getItemLabel:a.getItemLabel,getItems:a.getItems,isItemDisabled:a.isItemDisabled,keys:a.keys,loop:a.loop??!0,onNavigate:(e,t,n)=>{u(),t>=0&&a.onNavigate?.(e,t,n)},orientation:a.orientation,signal:a.signal}),f=(0,i.computed)(()=>{let e=d.focusedIndex.value;return a.getOptionId&&o.value&&e>=0?a.getOptionId(e):null}),p=()=>typeof a.restoreFocus==`function`?a.restoreFocus():a.restoreFocus??!0,m=(e=`programmatic`,t=!0)=>{o.value&&(o.value=!1,d.reset(),c?.(),c=null,t&&p()&&a.getTrigger&&r.restoreFocus(a.getTrigger),a.onClose?.(e))},h=(e=`programmatic`)=>{a.isDisabled?.()||o.value||(o.value=!0,l.update(),c=l.startAutoUpdate?.()??null,a.onOpen?.(e))};return r.createOutsidePointerDismissal({getTargets:()=>[a.getBoundary(),a.getPanel()],isActive:()=>o.value,onDismiss:()=>m(`outsideClick`),signal:a.signal}),a.signal.addEventListener(`abort`,()=>{o.value&&(o.value=!1,d.reset(),c?.(),c=null)},{once:!0}),{ariaActiveDescendant:f,ariaExpanded:s,close:m,focusedIndex:d.focusedIndex,getActiveItem:d.getActiveItem,handleKeydown:e=>o.value?e.key===`Escape`?(e.preventDefault(),m(`escape`),!0):d.handleKeydown(e):!1,isOpen:o,navigate:d.navigate,open:h,scrollFocusedIntoView:u,set:d.set,toggle:(e=`click`,t=`trigger`)=>{o.value?m(t):h(e)},updatePosition:l.update}};exports.createListboxDropdown=a;
1
+ const e=require("../errors.cjs"),t=require("./overlay.cjs"),n=require("./positioner.cjs"),r=require("./nav.cjs");let i=require("@vielzeug/ripple");var a=a=>{if(typeof a.getBoundary!=`function`)throw new e.RefineConfigError(`createListboxDropdown: getBoundary is required`);if(typeof a.getPanel!=`function`)throw new e.RefineConfigError(`createListboxDropdown: getPanel is required`);if(typeof a.getReference!=`function`)throw new e.RefineConfigError(`createListboxDropdown: getReference is required`);let o=(0,i.signal)(!1),s=(0,i.computed)(()=>String(o.value)),c=null,l=n.createDropdownPositioner({...a.positioning,getFloating:a.getPanel,getReference:a.getReference}),u=()=>{a.getFocusedOptionElement?.()?.scrollIntoView({block:`nearest`})},d=r.createListControl({disabled:(0,i.computed)(()=>!o.value),getItemLabel:a.getItemLabel,getItems:a.getItems,isItemDisabled:a.isItemDisabled,keys:a.keys,loop:a.loop??!0,onNavigate:(e,t,n)=>{u(),t>=0&&a.onNavigate?.(e,t,n)},orientation:a.orientation,signal:a.signal}),f=(0,i.computed)(()=>{let e=d.focusedIndex.value;return a.getOptionId&&o.value&&e>=0?a.getOptionId(e):null}),p=()=>typeof a.restoreFocus==`function`?a.restoreFocus():a.restoreFocus??!0,m=(e=`programmatic`,n=!0)=>{o.value&&(o.value=!1,d.reset(),c?.(),c=null,n&&p()&&a.getTrigger&&t.restoreTriggerFocus(a.getTrigger),a.onClose?.(e))},h=(e=`programmatic`)=>{a.isDisabled?.()||o.value||(o.value=!0,l.update(),c=l.startAutoUpdate?.()??null,a.onOpen?.(e))},g=(e=`click`,t=`trigger`)=>{o.value?m(t):h(e)};t.createOutsidePointerDismissal({getTargets:()=>[a.getBoundary(),a.getPanel()],isActive:()=>o.value,onDismiss:()=>m(`outsideClick`),signal:a.signal});let _=!1,v=()=>{_||(_=!0,o.value&&(o.value=!1,d.reset(),c?.(),c=null))};return a.signal.addEventListener(`abort`,v,{once:!0}),{ariaActiveDescendant:f,ariaExpanded:s,close:m,dispose:v,get disposed(){return _},focusedIndex:d.focusedIndex,getActiveItem:d.getActiveItem,handleKeydown:e=>o.value?e.key===`Escape`?(e.preventDefault(),m(`escape`),!0):d.handleKeydown(e):!1,isOpen:o,navigate:d.navigate,open:h,scrollFocusedIntoView:u,set:d.set,[Symbol.dispose]:v,toggle:g,updatePosition:l.update}};exports.createListboxDropdown=a;
2
2
  //# sourceMappingURL=option-list.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"option-list.cjs","names":[],"sources":["../../src/core/option-list.ts"],"sourcesContent":["import { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport { RefineConfigError } from '../errors';\nimport { createListControl, type ListKeyAction, type ListNavigationAction } from './nav';\nimport {\n createOutsidePointerDismissal,\n restoreFocus,\n type DropdownCloseReason,\n type OverlayOpenReason,\n} from './overlay';\nimport { createDropdownPositioner, type DropdownPositionerOptions } from './positioner';\n\nexport type ListboxItem = object;\n\n/** Placement-only options for the listbox dropdown positioner. */\nexport type ListboxDropdownPlacementOptions = Omit<DropdownPositionerOptions, 'getFloating' | 'getReference'>;\n\nexport type ListboxDropdownOptions<T extends ListboxItem> = {\n getBoundary: () => HTMLElement | null;\n getFocusedOptionElement?: () => HTMLElement | null;\n getItemLabel?: (item: T, index: number) => string;\n getItems: () => T[];\n getOptionId?: (index: number) => string;\n getPanel: () => HTMLElement | null;\n getReference: () => HTMLElement | null;\n getTrigger?: () => HTMLElement | null;\n isDisabled?: () => boolean;\n isItemDisabled?: (item: T, index: number) => boolean;\n keys?: Partial<Record<ListNavigationAction, string[]>>;\n loop?: boolean;\n onClose?: (reason: DropdownCloseReason) => void;\n onNavigate?: (action: ListKeyAction, index: number, event?: KeyboardEvent) => void;\n onOpen?: (reason: OverlayOpenReason) => void;\n orientation?: 'both' | 'horizontal' | 'vertical';\n positioning?: ListboxDropdownPlacementOptions;\n restoreFocus?: boolean | (() => boolean);\n signal: AbortSignal;\n};\n\nexport type ListboxDropdown<T extends ListboxItem> = {\n readonly ariaActiveDescendant: Readable<string | null>;\n readonly ariaExpanded: Readable<string>;\n close(reason?: DropdownCloseReason): void;\n readonly focusedIndex: Readable<number>;\n getActiveItem(): T | undefined;\n handleKeydown(event: KeyboardEvent): boolean;\n readonly isOpen: Readable<boolean>;\n navigate(action: ListNavigationAction): number;\n open(reason?: OverlayOpenReason): void;\n scrollFocusedIntoView(): void;\n set(index: number): number;\n toggle(openReason?: OverlayOpenReason, closeReason?: DropdownCloseReason): void;\n updatePosition(): void;\n};\n\n/**\n * Internal listbox dropdown behavior for select and combobox. It owns only\n * listbox interactions; menu and other overlay families keep their own logic.\n */\nexport const createListboxDropdown = <T extends ListboxItem>(\n options: ListboxDropdownOptions<T>,\n): ListboxDropdown<T> => {\n if (typeof options.getBoundary !== 'function') {\n throw new RefineConfigError('createListboxDropdown: getBoundary is required');\n }\n\n if (typeof options.getPanel !== 'function') {\n throw new RefineConfigError('createListboxDropdown: getPanel is required');\n }\n\n if (typeof options.getReference !== 'function') {\n throw new RefineConfigError('createListboxDropdown: getReference is required');\n }\n\n const isOpen = signal(false);\n const ariaExpanded = computed(() => String(isOpen.value));\n let stopPositioning: (() => void) | null = null;\n\n const positioner = createDropdownPositioner({\n ...options.positioning,\n getFloating: options.getPanel,\n getReference: options.getReference,\n });\n\n const scrollFocusedIntoView = (): void => {\n options.getFocusedOptionElement?.()?.scrollIntoView({ block: 'nearest' });\n };\n\n const list = createListControl<T>({\n disabled: computed(() => !isOpen.value),\n getItemLabel: options.getItemLabel,\n getItems: options.getItems,\n isItemDisabled: options.isItemDisabled,\n keys: options.keys,\n loop: options.loop ?? true,\n onNavigate: (action, index, event) => {\n scrollFocusedIntoView();\n\n if (index >= 0) options.onNavigate?.(action, index, event);\n },\n orientation: options.orientation,\n signal: options.signal,\n });\n\n const ariaActiveDescendant = computed<string | null>(() => {\n const index = list.focusedIndex.value;\n\n return options.getOptionId && isOpen.value && index >= 0 ? options.getOptionId(index) : null;\n });\n\n const shouldRestoreFocus = (): boolean => {\n return typeof options.restoreFocus === 'function' ? options.restoreFocus() : (options.restoreFocus ?? true);\n };\n\n const close = (reason: DropdownCloseReason = 'programmatic', shouldRestore = true): void => {\n if (!isOpen.value) return;\n\n isOpen.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n\n if (shouldRestore && shouldRestoreFocus() && options.getTrigger) restoreFocus(options.getTrigger);\n\n options.onClose?.(reason);\n };\n\n const open = (reason: OverlayOpenReason = 'programmatic'): void => {\n if (options.isDisabled?.() || isOpen.value) return;\n\n isOpen.value = true;\n positioner.update();\n stopPositioning = positioner.startAutoUpdate?.() ?? null;\n options.onOpen?.(reason);\n };\n\n const toggle = (openReason: OverlayOpenReason = 'click', closeReason: DropdownCloseReason = 'trigger'): void => {\n if (isOpen.value) close(closeReason);\n else open(openReason);\n };\n\n createOutsidePointerDismissal({\n getTargets: () => [options.getBoundary(), options.getPanel()],\n isActive: () => isOpen.value,\n onDismiss: () => close('outsideClick'),\n signal: options.signal,\n });\n\n options.signal.addEventListener(\n 'abort',\n () => {\n if (!isOpen.value) return;\n\n isOpen.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n },\n { once: true },\n );\n\n const handleKeydown = (event: KeyboardEvent): boolean => {\n if (!isOpen.value) return false;\n\n if (event.key === 'Escape') {\n event.preventDefault();\n close('escape');\n\n return true;\n }\n\n return list.handleKeydown(event);\n };\n\n return {\n ariaActiveDescendant,\n ariaExpanded,\n close,\n focusedIndex: list.focusedIndex,\n getActiveItem: list.getActiveItem,\n handleKeydown,\n isOpen,\n navigate: list.navigate,\n open,\n scrollFocusedIntoView,\n set: list.set,\n toggle,\n updatePosition: positioner.update,\n };\n};\n"],"mappings":"mJA2DA,IAAa,EACX,GACuB,CACvB,GAAI,OAAO,EAAQ,aAAgB,WACjC,MAAM,IAAI,EAAA,kBAAkB,gDAAgD,EAG9E,GAAI,OAAO,EAAQ,UAAa,WAC9B,MAAM,IAAI,EAAA,kBAAkB,6CAA6C,EAG3E,GAAI,OAAO,EAAQ,cAAiB,WAClC,MAAM,IAAI,EAAA,kBAAkB,iDAAiD,EAG/E,IAAM,GAAA,EAAS,EAAA,OAAA,CAAO,EAAK,EACrB,GAAA,EAAe,EAAA,SAAA,KAAe,OAAO,EAAO,KAAK,CAAC,EACpD,EAAuC,KAErC,EAAa,EAAA,yBAAyB,CAC1C,GAAG,EAAQ,YACX,YAAa,EAAQ,SACrB,aAAc,EAAQ,YACxB,CAAC,EAEK,MAAoC,CACxC,EAAQ,0BAA0B,CAAC,EAAE,eAAe,CAAE,MAAO,SAAU,CAAC,CAC1E,EAEM,EAAO,EAAA,kBAAqB,CAChC,UAAA,EAAU,EAAA,SAAA,KAAe,CAAC,EAAO,KAAK,EACtC,aAAc,EAAQ,aACtB,SAAU,EAAQ,SAClB,eAAgB,EAAQ,eACxB,KAAM,EAAQ,KACd,KAAM,EAAQ,MAAQ,GACtB,YAAa,EAAQ,EAAO,IAAU,CACpC,EAAsB,EAElB,GAAS,GAAG,EAAQ,aAAa,EAAQ,EAAO,CAAK,CAC3D,EACA,YAAa,EAAQ,YACrB,OAAQ,EAAQ,MAClB,CAAC,EAEK,GAAA,EAAuB,EAAA,SAAA,KAA8B,CACzD,IAAM,EAAQ,EAAK,aAAa,MAEhC,OAAO,EAAQ,aAAe,EAAO,OAAS,GAAS,EAAI,EAAQ,YAAY,CAAK,EAAI,IAC1F,CAAC,EAEK,MACG,OAAO,EAAQ,cAAiB,WAAa,EAAQ,aAAa,EAAK,EAAQ,cAAgB,GAGlG,GAAS,EAA8B,eAAgB,EAAgB,KAAe,CACrF,EAAO,QAEZ,EAAO,MAAQ,GACf,EAAK,MAAM,EACX,IAAkB,EAClB,EAAkB,KAEd,GAAiB,EAAmB,GAAK,EAAQ,YAAY,EAAA,aAAa,EAAQ,UAAU,EAEhG,EAAQ,UAAU,CAAM,EAC1B,EAEM,GAAQ,EAA4B,iBAAyB,CAC7D,EAAQ,aAAa,GAAK,EAAO,QAErC,EAAO,MAAQ,GACf,EAAW,OAAO,EAClB,EAAkB,EAAW,kBAAkB,GAAK,KACpD,EAAQ,SAAS,CAAM,EACzB,EAwCA,OAjCA,EAAA,8BAA8B,CAC5B,eAAkB,CAAC,EAAQ,YAAY,EAAG,EAAQ,SAAS,CAAC,EAC5D,aAAgB,EAAO,MACvB,cAAiB,EAAM,cAAc,EACrC,OAAQ,EAAQ,MAClB,CAAC,EAED,EAAQ,OAAO,iBACb,YACM,CACC,EAAO,QAEZ,EAAO,MAAQ,GACf,EAAK,MAAM,EACX,IAAkB,EAClB,EAAkB,KACpB,EACA,CAAE,KAAM,EAAK,CACf,EAeO,CACL,uBACA,eACA,QACA,aAAc,EAAK,aACnB,cAAe,EAAK,cACpB,cAnBqB,GAChB,EAAO,MAER,EAAM,MAAQ,UAChB,EAAM,eAAe,EACrB,EAAM,QAAQ,EAEP,IAGF,EAAK,cAAc,CAAK,EATL,GAmB1B,SACA,SAAU,EAAK,SACf,OACA,wBACA,IAAK,EAAK,IACV,QAlDc,EAAgC,QAAS,EAAmC,YAAoB,CAC1G,EAAO,MAAO,EAAM,CAAW,EAC9B,EAAK,CAAU,CACtB,EAgDE,eAAgB,EAAW,MAC7B,CACF"}
1
+ {"version":3,"file":"option-list.cjs","names":[],"sources":["../../src/core/option-list.ts"],"sourcesContent":["import { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport { RefineConfigError } from '../errors';\nimport { createListControl, type ListKeyAction, type ListNavigationAction } from './nav';\nimport {\n createOutsidePointerDismissal,\n restoreTriggerFocus,\n type DropdownCloseReason,\n type OverlayOpenReason,\n} from './overlay';\nimport { createDropdownPositioner, type DropdownPositionerOptions } from './positioner';\n\nexport type ListboxItem = object;\n\n/** Placement-only options for the listbox dropdown positioner. */\nexport type ListboxDropdownPlacementOptions = Omit<DropdownPositionerOptions, 'getFloating' | 'getReference'>;\n\nexport type ListboxDropdownOptions<T extends ListboxItem> = {\n getBoundary: () => HTMLElement | null;\n getFocusedOptionElement?: () => HTMLElement | null;\n getItemLabel?: (item: T, index: number) => string;\n getItems: () => T[];\n getOptionId?: (index: number) => string;\n getPanel: () => HTMLElement | null;\n getReference: () => HTMLElement | null;\n getTrigger?: () => HTMLElement | null;\n isDisabled?: () => boolean;\n isItemDisabled?: (item: T, index: number) => boolean;\n keys?: Partial<Record<ListNavigationAction, string[]>>;\n loop?: boolean;\n onClose?: (reason: DropdownCloseReason) => void;\n onNavigate?: (action: ListKeyAction, index: number, event?: KeyboardEvent) => void;\n onOpen?: (reason: OverlayOpenReason) => void;\n orientation?: 'both' | 'horizontal' | 'vertical';\n positioning?: ListboxDropdownPlacementOptions;\n restoreFocus?: boolean | (() => boolean);\n signal: AbortSignal;\n};\n\nexport type ListboxDropdown<T extends ListboxItem> = {\n [Symbol.dispose](): void;\n readonly ariaActiveDescendant: Readable<string | null>;\n readonly ariaExpanded: Readable<string>;\n close(reason?: DropdownCloseReason): void;\n /** Closes the dropdown (without restoring focus) and disposes list navigation state. */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n readonly focusedIndex: Readable<number>;\n getActiveItem(): T | undefined;\n handleKeydown(event: KeyboardEvent): boolean;\n readonly isOpen: Readable<boolean>;\n navigate(action: ListNavigationAction): number;\n open(reason?: OverlayOpenReason): void;\n scrollFocusedIntoView(): void;\n set(index: number): number;\n toggle(openReason?: OverlayOpenReason, closeReason?: DropdownCloseReason): void;\n updatePosition(): void;\n};\n\n/**\n * Internal listbox dropdown behavior for select and combobox. It owns only\n * listbox interactions; menu and other overlay families keep their own logic.\n */\nexport const createListboxDropdown = <T extends ListboxItem>(\n options: ListboxDropdownOptions<T>,\n): ListboxDropdown<T> => {\n if (typeof options.getBoundary !== 'function') {\n throw new RefineConfigError('createListboxDropdown: getBoundary is required');\n }\n\n if (typeof options.getPanel !== 'function') {\n throw new RefineConfigError('createListboxDropdown: getPanel is required');\n }\n\n if (typeof options.getReference !== 'function') {\n throw new RefineConfigError('createListboxDropdown: getReference is required');\n }\n\n const isOpen = signal(false);\n const ariaExpanded = computed(() => String(isOpen.value));\n let stopPositioning: (() => void) | null = null;\n\n const positioner = createDropdownPositioner({\n ...options.positioning,\n getFloating: options.getPanel,\n getReference: options.getReference,\n });\n\n const scrollFocusedIntoView = (): void => {\n options.getFocusedOptionElement?.()?.scrollIntoView({ block: 'nearest' });\n };\n\n const list = createListControl<T>({\n disabled: computed(() => !isOpen.value),\n getItemLabel: options.getItemLabel,\n getItems: options.getItems,\n isItemDisabled: options.isItemDisabled,\n keys: options.keys,\n loop: options.loop ?? true,\n onNavigate: (action, index, event) => {\n scrollFocusedIntoView();\n\n if (index >= 0) options.onNavigate?.(action, index, event);\n },\n orientation: options.orientation,\n signal: options.signal,\n });\n\n const ariaActiveDescendant = computed<string | null>(() => {\n const index = list.focusedIndex.value;\n\n return options.getOptionId && isOpen.value && index >= 0 ? options.getOptionId(index) : null;\n });\n\n const shouldRestoreFocus = (): boolean => {\n return typeof options.restoreFocus === 'function' ? options.restoreFocus() : (options.restoreFocus ?? true);\n };\n\n const close = (reason: DropdownCloseReason = 'programmatic', shouldRestore = true): void => {\n if (!isOpen.value) return;\n\n isOpen.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n\n if (shouldRestore && shouldRestoreFocus() && options.getTrigger) restoreTriggerFocus(options.getTrigger);\n\n options.onClose?.(reason);\n };\n\n const open = (reason: OverlayOpenReason = 'programmatic'): void => {\n if (options.isDisabled?.() || isOpen.value) return;\n\n isOpen.value = true;\n positioner.update();\n stopPositioning = positioner.startAutoUpdate?.() ?? null;\n options.onOpen?.(reason);\n };\n\n const toggle = (openReason: OverlayOpenReason = 'click', closeReason: DropdownCloseReason = 'trigger'): void => {\n if (isOpen.value) close(closeReason);\n else open(openReason);\n };\n\n createOutsidePointerDismissal({\n getTargets: () => [options.getBoundary(), options.getPanel()],\n isActive: () => isOpen.value,\n onDismiss: () => close('outsideClick'),\n signal: options.signal,\n });\n\n let disposed = false;\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n\n if (isOpen.value) {\n isOpen.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n }\n };\n\n options.signal.addEventListener('abort', dispose, { once: true });\n\n const handleKeydown = (event: KeyboardEvent): boolean => {\n if (!isOpen.value) return false;\n\n if (event.key === 'Escape') {\n event.preventDefault();\n close('escape');\n\n return true;\n }\n\n return list.handleKeydown(event);\n };\n\n return {\n ariaActiveDescendant,\n ariaExpanded,\n close,\n dispose,\n get disposed() {\n return disposed;\n },\n focusedIndex: list.focusedIndex,\n getActiveItem: list.getActiveItem,\n handleKeydown,\n isOpen,\n navigate: list.navigate,\n open,\n scrollFocusedIntoView,\n set: list.set,\n [Symbol.dispose]: dispose,\n toggle,\n updatePosition: positioner.update,\n };\n};\n"],"mappings":"mJAgEA,IAAa,EACX,GACuB,CACvB,GAAI,OAAO,EAAQ,aAAgB,WACjC,MAAM,IAAI,EAAA,kBAAkB,gDAAgD,EAG9E,GAAI,OAAO,EAAQ,UAAa,WAC9B,MAAM,IAAI,EAAA,kBAAkB,6CAA6C,EAG3E,GAAI,OAAO,EAAQ,cAAiB,WAClC,MAAM,IAAI,EAAA,kBAAkB,iDAAiD,EAG/E,IAAM,GAAA,EAAS,EAAA,OAAA,CAAO,EAAK,EACrB,GAAA,EAAe,EAAA,SAAA,KAAe,OAAO,EAAO,KAAK,CAAC,EACpD,EAAuC,KAErC,EAAa,EAAA,yBAAyB,CAC1C,GAAG,EAAQ,YACX,YAAa,EAAQ,SACrB,aAAc,EAAQ,YACxB,CAAC,EAEK,MAAoC,CACxC,EAAQ,0BAA0B,CAAC,EAAE,eAAe,CAAE,MAAO,SAAU,CAAC,CAC1E,EAEM,EAAO,EAAA,kBAAqB,CAChC,UAAA,EAAU,EAAA,SAAA,KAAe,CAAC,EAAO,KAAK,EACtC,aAAc,EAAQ,aACtB,SAAU,EAAQ,SAClB,eAAgB,EAAQ,eACxB,KAAM,EAAQ,KACd,KAAM,EAAQ,MAAQ,GACtB,YAAa,EAAQ,EAAO,IAAU,CACpC,EAAsB,EAElB,GAAS,GAAG,EAAQ,aAAa,EAAQ,EAAO,CAAK,CAC3D,EACA,YAAa,EAAQ,YACrB,OAAQ,EAAQ,MAClB,CAAC,EAEK,GAAA,EAAuB,EAAA,SAAA,KAA8B,CACzD,IAAM,EAAQ,EAAK,aAAa,MAEhC,OAAO,EAAQ,aAAe,EAAO,OAAS,GAAS,EAAI,EAAQ,YAAY,CAAK,EAAI,IAC1F,CAAC,EAEK,MACG,OAAO,EAAQ,cAAiB,WAAa,EAAQ,aAAa,EAAK,EAAQ,cAAgB,GAGlG,GAAS,EAA8B,eAAgB,EAAgB,KAAe,CACrF,EAAO,QAEZ,EAAO,MAAQ,GACf,EAAK,MAAM,EACX,IAAkB,EAClB,EAAkB,KAEd,GAAiB,EAAmB,GAAK,EAAQ,YAAY,EAAA,oBAAoB,EAAQ,UAAU,EAEvG,EAAQ,UAAU,CAAM,EAC1B,EAEM,GAAQ,EAA4B,iBAAyB,CAC7D,EAAQ,aAAa,GAAK,EAAO,QAErC,EAAO,MAAQ,GACf,EAAW,OAAO,EAClB,EAAkB,EAAW,kBAAkB,GAAK,KACpD,EAAQ,SAAS,CAAM,EACzB,EAEM,GAAU,EAAgC,QAAS,EAAmC,YAAoB,CAC1G,EAAO,MAAO,EAAM,CAAW,EAC9B,EAAK,CAAU,CACtB,EAEA,EAAA,8BAA8B,CAC5B,eAAkB,CAAC,EAAQ,YAAY,EAAG,EAAQ,SAAS,CAAC,EAC5D,aAAgB,EAAO,MACvB,cAAiB,EAAM,cAAc,EACrC,OAAQ,EAAQ,MAClB,CAAC,EAED,IAAI,EAAW,GAET,MAAsB,CACtB,IAEJ,EAAW,GAEP,EAAO,QACT,EAAO,MAAQ,GACf,EAAK,MAAM,EACX,IAAkB,EAClB,EAAkB,MAEtB,EAiBA,OAfA,EAAQ,OAAO,iBAAiB,QAAS,EAAS,CAAE,KAAM,EAAK,CAAC,EAezD,CACL,uBACA,eACA,QACA,UACA,IAAI,UAAW,CACb,OAAO,CACT,EACA,aAAc,EAAK,aACnB,cAAe,EAAK,cACpB,cAvBqB,GAChB,EAAO,MAER,EAAM,MAAQ,UAChB,EAAM,eAAe,EACrB,EAAM,QAAQ,EAEP,IAGF,EAAK,cAAc,CAAK,EATL,GAuB1B,SACA,SAAU,EAAK,SACf,OACA,wBACA,IAAK,EAAK,KACT,OAAO,SAAU,EAClB,SACA,eAAgB,EAAW,MAC7B,CACF"}
@@ -27,9 +27,14 @@ export type ListboxDropdownOptions<T extends ListboxItem> = {
27
27
  signal: AbortSignal;
28
28
  };
29
29
  export type ListboxDropdown<T extends ListboxItem> = {
30
+ [Symbol.dispose](): void;
30
31
  readonly ariaActiveDescendant: Readable<string | null>;
31
32
  readonly ariaExpanded: Readable<string>;
32
33
  close(reason?: DropdownCloseReason): void;
34
+ /** Closes the dropdown (without restoring focus) and disposes list navigation state. */
35
+ dispose(): void;
36
+ /** `true` after `dispose()` has been called. */
37
+ readonly disposed: boolean;
33
38
  readonly focusedIndex: Readable<number>;
34
39
  getActiveItem(): T | undefined;
35
40
  handleKeydown(event: KeyboardEvent): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"option-list.d.ts","sourceRoot":"","sources":["../../src/core/option-list.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"option-list.d.ts","sourceRoot":"","sources":["../../src/core/option-list.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,20 @@
1
1
  import { RefineConfigError as e } from "../errors.js";
2
- import { createDropdownPositioner as t } from "./positioner.js";
3
- import { createListControl as n } from "./nav.js";
4
- import { createOutsidePointerDismissal as r, restoreFocus as i } from "./overlay.js";
2
+ import { createOutsidePointerDismissal as t, restoreTriggerFocus as n } from "./overlay.js";
3
+ import { createDropdownPositioner as r } from "./positioner.js";
4
+ import { createListControl as i } from "./nav.js";
5
5
  import { computed as a, signal as o } from "@vielzeug/ripple";
6
6
  //#region src/core/option-list.ts
7
7
  var s = (s) => {
8
8
  if (typeof s.getBoundary != "function") throw new e("createListboxDropdown: getBoundary is required");
9
9
  if (typeof s.getPanel != "function") throw new e("createListboxDropdown: getPanel is required");
10
10
  if (typeof s.getReference != "function") throw new e("createListboxDropdown: getReference is required");
11
- let c = o(!1), l = a(() => String(c.value)), u = null, d = t({
11
+ let c = o(!1), l = a(() => String(c.value)), u = null, d = r({
12
12
  ...s.positioning,
13
13
  getFloating: s.getPanel,
14
14
  getReference: s.getReference
15
15
  }), f = () => {
16
16
  s.getFocusedOptionElement?.()?.scrollIntoView({ block: "nearest" });
17
- }, p = n({
17
+ }, p = i({
18
18
  disabled: a(() => !c.value),
19
19
  getItemLabel: s.getItemLabel,
20
20
  getItems: s.getItems,
@@ -30,21 +30,29 @@ var s = (s) => {
30
30
  let e = p.focusedIndex.value;
31
31
  return s.getOptionId && c.value && e >= 0 ? s.getOptionId(e) : null;
32
32
  }), h = () => typeof s.restoreFocus == "function" ? s.restoreFocus() : s.restoreFocus ?? !0, g = (e = "programmatic", t = !0) => {
33
- c.value && (c.value = !1, p.reset(), u?.(), u = null, t && h() && s.getTrigger && i(s.getTrigger), s.onClose?.(e));
33
+ c.value && (c.value = !1, p.reset(), u?.(), u = null, t && h() && s.getTrigger && n(s.getTrigger), s.onClose?.(e));
34
34
  }, _ = (e = "programmatic") => {
35
35
  s.isDisabled?.() || c.value || (c.value = !0, d.update(), u = d.startAutoUpdate?.() ?? null, s.onOpen?.(e));
36
+ }, v = (e = "click", t = "trigger") => {
37
+ c.value ? g(t) : _(e);
36
38
  };
37
- return r({
39
+ t({
38
40
  getTargets: () => [s.getBoundary(), s.getPanel()],
39
41
  isActive: () => c.value,
40
42
  onDismiss: () => g("outsideClick"),
41
43
  signal: s.signal
42
- }), s.signal.addEventListener("abort", () => {
43
- c.value && (c.value = !1, p.reset(), u?.(), u = null);
44
- }, { once: !0 }), {
44
+ });
45
+ let y = !1, b = () => {
46
+ y || (y = !0, c.value && (c.value = !1, p.reset(), u?.(), u = null));
47
+ };
48
+ return s.signal.addEventListener("abort", b, { once: !0 }), {
45
49
  ariaActiveDescendant: m,
46
50
  ariaExpanded: l,
47
51
  close: g,
52
+ dispose: b,
53
+ get disposed() {
54
+ return y;
55
+ },
48
56
  focusedIndex: p.focusedIndex,
49
57
  getActiveItem: p.getActiveItem,
50
58
  handleKeydown: (e) => c.value ? e.key === "Escape" ? (e.preventDefault(), g("escape"), !0) : p.handleKeydown(e) : !1,
@@ -53,9 +61,8 @@ var s = (s) => {
53
61
  open: _,
54
62
  scrollFocusedIntoView: f,
55
63
  set: p.set,
56
- toggle: (e = "click", t = "trigger") => {
57
- c.value ? g(t) : _(e);
58
- },
64
+ [Symbol.dispose]: b,
65
+ toggle: v,
59
66
  updatePosition: d.update
60
67
  };
61
68
  };