@raintonic/formaui 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +7 -7
  2. package/README.md +145 -145
  3. package/fesm2022/raintonic-formaui-cdk-drag-drop.mjs.map +1 -1
  4. package/fesm2022/raintonic-formaui-cdk-form-field.mjs.map +1 -1
  5. package/fesm2022/raintonic-formaui-cdk-overlay.mjs +0 -26
  6. package/fesm2022/raintonic-formaui-cdk-overlay.mjs.map +1 -1
  7. package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs +2 -2
  8. package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs.map +1 -1
  9. package/fesm2022/raintonic-formaui-components-accordion.mjs +2 -2
  10. package/fesm2022/raintonic-formaui-components-accordion.mjs.map +1 -1
  11. package/fesm2022/raintonic-formaui-components-alert.mjs.map +1 -1
  12. package/fesm2022/raintonic-formaui-components-autocomplete.mjs.map +1 -1
  13. package/fesm2022/raintonic-formaui-components-avatar.mjs.map +1 -1
  14. package/fesm2022/raintonic-formaui-components-badge.mjs +2 -2
  15. package/fesm2022/raintonic-formaui-components-badge.mjs.map +1 -1
  16. package/fesm2022/raintonic-formaui-components-big-menu.mjs +2 -2
  17. package/fesm2022/raintonic-formaui-components-big-menu.mjs.map +1 -1
  18. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs +4 -4
  19. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs.map +1 -1
  20. package/fesm2022/raintonic-formaui-components-button-group.mjs.map +1 -1
  21. package/fesm2022/raintonic-formaui-components-button.mjs.map +1 -1
  22. package/fesm2022/raintonic-formaui-components-card.mjs.map +1 -1
  23. package/fesm2022/raintonic-formaui-components-checkbox.mjs +2 -2
  24. package/fesm2022/raintonic-formaui-components-checkbox.mjs.map +1 -1
  25. package/fesm2022/raintonic-formaui-components-data-table.mjs.map +1 -1
  26. package/fesm2022/raintonic-formaui-components-date-picker.mjs +4 -4
  27. package/fesm2022/raintonic-formaui-components-date-picker.mjs.map +1 -1
  28. package/fesm2022/raintonic-formaui-components-divider.mjs +2 -2
  29. package/fesm2022/raintonic-formaui-components-divider.mjs.map +1 -1
  30. package/fesm2022/raintonic-formaui-components-drawer.mjs +2 -2
  31. package/fesm2022/raintonic-formaui-components-drawer.mjs.map +1 -1
  32. package/fesm2022/raintonic-formaui-components-dynamic-form.mjs.map +1 -1
  33. package/fesm2022/raintonic-formaui-components-empty-state.mjs +2 -2
  34. package/fesm2022/raintonic-formaui-components-empty-state.mjs.map +1 -1
  35. package/fesm2022/raintonic-formaui-components-file-upload.mjs +2 -2
  36. package/fesm2022/raintonic-formaui-components-file-upload.mjs.map +1 -1
  37. package/fesm2022/raintonic-formaui-components-form-field.mjs.map +1 -1
  38. package/fesm2022/raintonic-formaui-components-icon.mjs.map +1 -1
  39. package/fesm2022/raintonic-formaui-components-input.mjs.map +1 -1
  40. package/fesm2022/raintonic-formaui-components-list.mjs +4 -4
  41. package/fesm2022/raintonic-formaui-components-list.mjs.map +1 -1
  42. package/fesm2022/raintonic-formaui-components-menu.mjs.map +1 -1
  43. package/fesm2022/raintonic-formaui-components-number-input.mjs +2 -2
  44. package/fesm2022/raintonic-formaui-components-number-input.mjs.map +1 -1
  45. package/fesm2022/raintonic-formaui-components-paginator.mjs +2 -2
  46. package/fesm2022/raintonic-formaui-components-paginator.mjs.map +1 -1
  47. package/fesm2022/raintonic-formaui-components-password-input.mjs +2 -2
  48. package/fesm2022/raintonic-formaui-components-password-input.mjs.map +1 -1
  49. package/fesm2022/raintonic-formaui-components-popover.mjs +2 -2
  50. package/fesm2022/raintonic-formaui-components-popover.mjs.map +1 -1
  51. package/fesm2022/raintonic-formaui-components-progressbar.mjs.map +1 -1
  52. package/fesm2022/raintonic-formaui-components-radio.mjs +4 -4
  53. package/fesm2022/raintonic-formaui-components-radio.mjs.map +1 -1
  54. package/fesm2022/raintonic-formaui-components-select.mjs +24 -24
  55. package/fesm2022/raintonic-formaui-components-select.mjs.map +1 -1
  56. package/fesm2022/raintonic-formaui-components-side-panel.mjs +2 -2
  57. package/fesm2022/raintonic-formaui-components-side-panel.mjs.map +1 -1
  58. package/fesm2022/raintonic-formaui-components-sidebar.mjs +2 -2
  59. package/fesm2022/raintonic-formaui-components-sidebar.mjs.map +1 -1
  60. package/fesm2022/raintonic-formaui-components-skeleton.mjs +2 -2
  61. package/fesm2022/raintonic-formaui-components-skeleton.mjs.map +1 -1
  62. package/fesm2022/raintonic-formaui-components-slider.mjs +2 -2
  63. package/fesm2022/raintonic-formaui-components-slider.mjs.map +1 -1
  64. package/fesm2022/raintonic-formaui-components-spinner.mjs +2 -2
  65. package/fesm2022/raintonic-formaui-components-spinner.mjs.map +1 -1
  66. package/fesm2022/raintonic-formaui-components-stepper.mjs +2 -2
  67. package/fesm2022/raintonic-formaui-components-stepper.mjs.map +1 -1
  68. package/fesm2022/raintonic-formaui-components-tab.mjs +10 -10
  69. package/fesm2022/raintonic-formaui-components-tab.mjs.map +1 -1
  70. package/fesm2022/raintonic-formaui-components-tag.mjs +2 -2
  71. package/fesm2022/raintonic-formaui-components-tag.mjs.map +1 -1
  72. package/fesm2022/raintonic-formaui-components-time-picker.mjs +4 -4
  73. package/fesm2022/raintonic-formaui-components-time-picker.mjs.map +1 -1
  74. package/fesm2022/raintonic-formaui-components-toggle.mjs.map +1 -1
  75. package/fesm2022/raintonic-formaui-components-toolbar.mjs.map +1 -1
  76. package/fesm2022/raintonic-formaui-components-tooltip.mjs.map +1 -1
  77. package/fesm2022/raintonic-formaui-components-tree-select.mjs +2 -2
  78. package/fesm2022/raintonic-formaui-components-tree-select.mjs.map +1 -1
  79. package/fesm2022/raintonic-formaui-components-tree-table.mjs +2 -2
  80. package/fesm2022/raintonic-formaui-components-tree-table.mjs.map +1 -1
  81. package/fesm2022/raintonic-formaui-components-tree.mjs +4 -4
  82. package/fesm2022/raintonic-formaui-components-tree.mjs.map +1 -1
  83. package/fesm2022/raintonic-formaui-core.mjs.map +1 -1
  84. package/fesm2022/raintonic-formaui-services-dialog.mjs +36 -36
  85. package/fesm2022/raintonic-formaui-services-dialog.mjs.map +1 -1
  86. package/fesm2022/raintonic-formaui-services-notification.mjs +2 -2
  87. package/fesm2022/raintonic-formaui-services-notification.mjs.map +1 -1
  88. package/fesm2022/raintonic-formaui-services-theme.mjs.map +1 -1
  89. package/fesm2022/raintonic-formaui-test-utils.mjs.map +1 -1
  90. package/fesm2022/raintonic-formaui.mjs.map +1 -1
  91. package/llms-full.txt +3 -97
  92. package/llms.txt +3 -3
  93. package/package.json +1 -1
  94. package/styles/index.scss +3 -3
  95. package/styles/partials/components/_button.scss +367 -0
  96. package/styles/partials/components/_dialog.scss +180 -0
  97. package/styles/partials/components/_overlay.scss +87 -0
  98. package/types/raintonic-formaui-cdk-overlay.d.ts +0 -1
  99. package/types/raintonic-formaui-cdk-overlay.d.ts.map +1 -1
@@ -159,7 +159,7 @@ class FuiDrawerComponent {
159
159
  return Array.from(panel.querySelectorAll(selectors)).filter((el) => el.offsetParent !== null);
160
160
  }
161
161
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDrawerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
162
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiDrawerComponent, isStandalone: true, selector: "fui-drawer", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, opened: { classPropertyName: "opened", publicName: "opened", isSignal: true, isRequired: false, transformFunction: null }, hasBackdrop: { classPropertyName: "hasBackdrop", publicName: "hasBackdrop", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdropClick: { classPropertyName: "closeOnBackdropClick", publicName: "closeOnBackdropClick", isSignal: true, isRequired: false, transformFunction: null }, closeOnEsc: { classPropertyName: "closeOnEsc", publicName: "closeOnEsc", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "ariaLabelledBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedChange: "openedChange", closed: "closed" }, host: { listeners: { "document:keydown": "onKeydown($event)" }, properties: { "class.fui-drawer--open": "_opened()", "class.fui-drawer--left": "position() === \"left\"", "class.fui-drawer--right": "position() === \"right\"", "class.fui-drawer--top": "position() === \"top\"", "class.fui-drawer--bottom": "position() === \"bottom\"", "class.fui-drawer--overlay": "mode() === \"overlay\"", "class.fui-drawer--push": "mode() === \"push\"", "attr.role": "\"dialog\"", "attr.aria-modal": "_opened() ? \"true\" : null", "attr.aria-label": "ariaLabel() || (!ariaLabelledBy() ? title() : null)", "attr.aria-labelledby": "ariaLabelledBy()" }, classAttribute: "fui-drawer" }, viewQueries: [{ propertyName: "drawerPanel", first: true, predicate: ["drawerPanel"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (_opened() && hasBackdrop()) {\n <div class=\"fui-drawer__backdrop\" (click)=\"closeOnBackdropClick() ? close() : null\" aria-hidden=\"true\"></div>\n}\n\n<div class=\"fui-drawer__panel\" [style.--_drawer-size]=\"_sizeValue()\" #drawerPanel tabindex=\"-1\">\n @if (title() || showCloseButton()) {\n <div class=\"fui-drawer__header\">\n @if (title()) {\n <h2 class=\"fui-drawer__title\">{{ title() }}</h2>\n }\n @if (showCloseButton()) {\n <button type=\"button\" class=\"fui-drawer__close\" (click)=\"close()\" aria-label=\"Close drawer\">\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\n </button>\n }\n </div>\n }\n\n <div class=\"fui-drawer__content\">\n <ng-content></ng-content>\n </div>\n\n <div class=\"fui-drawer__footer\">\n <ng-content select=\"[drawerFooter]\"></ng-content>\n </div>\n</div>\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}.fui-drawer{--fui-drawer-z-index: var(--fui-z-index-modal, 1050);--fui-drawer-bg: var(--fui-surface-00);--fui-drawer-border-color: var(--fui-border-color);--fui-drawer-shadow: -4px 0 24px var(--fui-black-10);--fui-drawer-backdrop-color: var(--fui-black-30);--fui-drawer-header-padding: var(--fui-spacing-04) var(--fui-spacing-05);--fui-drawer-content-padding: var(--fui-spacing-05);--fui-drawer-footer-padding: var(--fui-spacing-04) var(--fui-spacing-05);position:fixed;inset:0;pointer-events:none;z-index:var(--fui-drawer-z-index);overflow:hidden;visibility:hidden;transition:visibility 0s linear var(--fui-duration-moderate-01)}.fui-drawer--open{pointer-events:auto;visibility:visible;transition-delay:0s}.fui-drawer__backdrop{position:fixed;inset:0;background-color:var(--fui-drawer-backdrop-color);z-index:1;opacity:0;transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-drawer--open .fui-drawer__backdrop{opacity:1}.fui-drawer__panel{position:fixed;display:flex;flex-direction:column;background-color:var(--fui-drawer-bg);z-index:2;pointer-events:auto;transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms}.fui-drawer--right .fui-drawer__panel{top:0;right:0;bottom:0;width:var(--_drawer-size, 480px);max-width:100%;border-left:1px solid var(--fui-drawer-border-color);box-shadow:var(--fui-drawer-shadow);transform:translate(100%)}.fui-drawer--right.fui-drawer--open .fui-drawer__panel{transform:translate(0)}.fui-drawer--left .fui-drawer__panel{top:0;left:0;bottom:0;width:var(--_drawer-size, 480px);max-width:100%;border-right:1px solid var(--fui-drawer-border-color);box-shadow:4px 0 24px var(--fui-black-10);transform:translate(-100%)}.fui-drawer--left.fui-drawer--open .fui-drawer__panel{transform:translate(0)}.fui-drawer--top .fui-drawer__panel{top:0;left:0;right:0;height:var(--_drawer-size, 480px);max-height:100%;border-bottom:1px solid var(--fui-drawer-border-color);box-shadow:0 4px 24px var(--fui-black-10);transform:translateY(-100%)}.fui-drawer--top.fui-drawer--open .fui-drawer__panel{transform:translateY(0)}.fui-drawer--bottom .fui-drawer__panel{bottom:0;left:0;right:0;height:var(--_drawer-size, 480px);max-height:100%;border-top:1px solid var(--fui-drawer-border-color);box-shadow:0 -4px 24px var(--fui-black-10);transform:translateY(100%)}.fui-drawer--bottom.fui-drawer--open .fui-drawer__panel{transform:translateY(0)}.fui-drawer__header{display:flex;align-items:center;justify-content:space-between;padding:var(--fui-drawer-header-padding);border-bottom:1px solid var(--fui-drawer-border-color);flex-shrink:0}.fui-drawer__title{font-size:var(--fui-font-size-03);font-weight:var(--fui-font-weight-semibold);color:var(--fui-text-primary);margin:0}.fui-drawer__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;border-radius:var(--fui-border-radius-sm);color:var(--fui-text-secondary);cursor:pointer;transition:background-color var(--fui-duration-moderate-01) var(--fui-ease-standard),color var(--fui-duration-moderate-01) var(--fui-ease-standard)}.fui-drawer__close:hover{background-color:var(--fui-surface-02);color:var(--fui-text-primary)}.fui-drawer__close:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-drawer__content{flex:1;overflow-y:auto;padding:var(--fui-drawer-content-padding)}.fui-drawer__footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--fui-spacing-03);padding:var(--fui-drawer-footer-padding);border-top:1px solid var(--fui-drawer-border-color);flex-shrink:0}.fui-drawer__footer:empty{display:none}@media(prefers-reduced-motion:reduce){.fui-drawer__backdrop,.fui-drawer__panel,.fui-drawer__close{transition:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
162
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiDrawerComponent, isStandalone: true, selector: "fui-drawer", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, opened: { classPropertyName: "opened", publicName: "opened", isSignal: true, isRequired: false, transformFunction: null }, hasBackdrop: { classPropertyName: "hasBackdrop", publicName: "hasBackdrop", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdropClick: { classPropertyName: "closeOnBackdropClick", publicName: "closeOnBackdropClick", isSignal: true, isRequired: false, transformFunction: null }, closeOnEsc: { classPropertyName: "closeOnEsc", publicName: "closeOnEsc", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "ariaLabelledBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedChange: "openedChange", closed: "closed" }, host: { listeners: { "document:keydown": "onKeydown($event)" }, properties: { "class.fui-drawer--open": "_opened()", "class.fui-drawer--left": "position() === \"left\"", "class.fui-drawer--right": "position() === \"right\"", "class.fui-drawer--top": "position() === \"top\"", "class.fui-drawer--bottom": "position() === \"bottom\"", "class.fui-drawer--overlay": "mode() === \"overlay\"", "class.fui-drawer--push": "mode() === \"push\"", "attr.role": "\"dialog\"", "attr.aria-modal": "_opened() ? \"true\" : null", "attr.aria-label": "ariaLabel() || (!ariaLabelledBy() ? title() : null)", "attr.aria-labelledby": "ariaLabelledBy()" }, classAttribute: "fui-drawer" }, viewQueries: [{ propertyName: "drawerPanel", first: true, predicate: ["drawerPanel"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (_opened() && hasBackdrop()) {\r\n <div class=\"fui-drawer__backdrop\" (click)=\"closeOnBackdropClick() ? close() : null\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"fui-drawer__panel\" [style.--_drawer-size]=\"_sizeValue()\" #drawerPanel tabindex=\"-1\">\r\n @if (title() || showCloseButton()) {\r\n <div class=\"fui-drawer__header\">\r\n @if (title()) {\r\n <h2 class=\"fui-drawer__title\">{{ title() }}</h2>\r\n }\r\n @if (showCloseButton()) {\r\n <button type=\"button\" class=\"fui-drawer__close\" (click)=\"close()\" aria-label=\"Close drawer\">\r\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"fui-drawer__content\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <div class=\"fui-drawer__footer\">\r\n <ng-content select=\"[drawerFooter]\"></ng-content>\r\n </div>\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}.fui-drawer{--fui-drawer-z-index: var(--fui-z-index-modal, 1050);--fui-drawer-bg: var(--fui-surface-00);--fui-drawer-border-color: var(--fui-border-color);--fui-drawer-shadow: -4px 0 24px var(--fui-black-10);--fui-drawer-backdrop-color: var(--fui-black-30);--fui-drawer-header-padding: var(--fui-spacing-04) var(--fui-spacing-05);--fui-drawer-content-padding: var(--fui-spacing-05);--fui-drawer-footer-padding: var(--fui-spacing-04) var(--fui-spacing-05);position:fixed;inset:0;pointer-events:none;z-index:var(--fui-drawer-z-index);overflow:hidden;visibility:hidden;transition:visibility 0s linear var(--fui-duration-moderate-01)}.fui-drawer--open{pointer-events:auto;visibility:visible;transition-delay:0s}.fui-drawer__backdrop{position:fixed;inset:0;background-color:var(--fui-drawer-backdrop-color);z-index:1;opacity:0;transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-drawer--open .fui-drawer__backdrop{opacity:1}.fui-drawer__panel{position:fixed;display:flex;flex-direction:column;background-color:var(--fui-drawer-bg);z-index:2;pointer-events:auto;transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms}.fui-drawer--right .fui-drawer__panel{top:0;right:0;bottom:0;width:var(--_drawer-size, 480px);max-width:100%;border-left:1px solid var(--fui-drawer-border-color);box-shadow:var(--fui-drawer-shadow);transform:translate(100%)}.fui-drawer--right.fui-drawer--open .fui-drawer__panel{transform:translate(0)}.fui-drawer--left .fui-drawer__panel{top:0;left:0;bottom:0;width:var(--_drawer-size, 480px);max-width:100%;border-right:1px solid var(--fui-drawer-border-color);box-shadow:4px 0 24px var(--fui-black-10);transform:translate(-100%)}.fui-drawer--left.fui-drawer--open .fui-drawer__panel{transform:translate(0)}.fui-drawer--top .fui-drawer__panel{top:0;left:0;right:0;height:var(--_drawer-size, 480px);max-height:100%;border-bottom:1px solid var(--fui-drawer-border-color);box-shadow:0 4px 24px var(--fui-black-10);transform:translateY(-100%)}.fui-drawer--top.fui-drawer--open .fui-drawer__panel{transform:translateY(0)}.fui-drawer--bottom .fui-drawer__panel{bottom:0;left:0;right:0;height:var(--_drawer-size, 480px);max-height:100%;border-top:1px solid var(--fui-drawer-border-color);box-shadow:0 -4px 24px var(--fui-black-10);transform:translateY(100%)}.fui-drawer--bottom.fui-drawer--open .fui-drawer__panel{transform:translateY(0)}.fui-drawer__header{display:flex;align-items:center;justify-content:space-between;padding:var(--fui-drawer-header-padding);border-bottom:1px solid var(--fui-drawer-border-color);flex-shrink:0}.fui-drawer__title{font-size:var(--fui-font-size-03);font-weight:var(--fui-font-weight-semibold);color:var(--fui-text-primary);margin:0}.fui-drawer__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;border-radius:var(--fui-border-radius-sm);color:var(--fui-text-secondary);cursor:pointer;transition:background-color var(--fui-duration-moderate-01) var(--fui-ease-standard),color var(--fui-duration-moderate-01) var(--fui-ease-standard)}.fui-drawer__close:hover{background-color:var(--fui-surface-02);color:var(--fui-text-primary)}.fui-drawer__close:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-drawer__content{flex:1;overflow-y:auto;padding:var(--fui-drawer-content-padding)}.fui-drawer__footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--fui-spacing-03);padding:var(--fui-drawer-footer-padding);border-top:1px solid var(--fui-drawer-border-color);flex-shrink:0}.fui-drawer__footer:empty{display:none}@media(prefers-reduced-motion:reduce){.fui-drawer__backdrop,.fui-drawer__panel,.fui-drawer__close{transition:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
163
163
  }
164
164
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDrawerComponent, decorators: [{
165
165
  type: Component,
@@ -176,7 +176,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
176
176
  '[attr.aria-modal]': '_opened() ? "true" : null',
177
177
  '[attr.aria-label]': 'ariaLabel() || (!ariaLabelledBy() ? title() : null)',
178
178
  '[attr.aria-labelledby]': 'ariaLabelledBy()',
179
- }, template: "@if (_opened() && hasBackdrop()) {\n <div class=\"fui-drawer__backdrop\" (click)=\"closeOnBackdropClick() ? close() : null\" aria-hidden=\"true\"></div>\n}\n\n<div class=\"fui-drawer__panel\" [style.--_drawer-size]=\"_sizeValue()\" #drawerPanel tabindex=\"-1\">\n @if (title() || showCloseButton()) {\n <div class=\"fui-drawer__header\">\n @if (title()) {\n <h2 class=\"fui-drawer__title\">{{ title() }}</h2>\n }\n @if (showCloseButton()) {\n <button type=\"button\" class=\"fui-drawer__close\" (click)=\"close()\" aria-label=\"Close drawer\">\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\n </button>\n }\n </div>\n }\n\n <div class=\"fui-drawer__content\">\n <ng-content></ng-content>\n </div>\n\n <div class=\"fui-drawer__footer\">\n <ng-content select=\"[drawerFooter]\"></ng-content>\n </div>\n</div>\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}.fui-drawer{--fui-drawer-z-index: var(--fui-z-index-modal, 1050);--fui-drawer-bg: var(--fui-surface-00);--fui-drawer-border-color: var(--fui-border-color);--fui-drawer-shadow: -4px 0 24px var(--fui-black-10);--fui-drawer-backdrop-color: var(--fui-black-30);--fui-drawer-header-padding: var(--fui-spacing-04) var(--fui-spacing-05);--fui-drawer-content-padding: var(--fui-spacing-05);--fui-drawer-footer-padding: var(--fui-spacing-04) var(--fui-spacing-05);position:fixed;inset:0;pointer-events:none;z-index:var(--fui-drawer-z-index);overflow:hidden;visibility:hidden;transition:visibility 0s linear var(--fui-duration-moderate-01)}.fui-drawer--open{pointer-events:auto;visibility:visible;transition-delay:0s}.fui-drawer__backdrop{position:fixed;inset:0;background-color:var(--fui-drawer-backdrop-color);z-index:1;opacity:0;transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-drawer--open .fui-drawer__backdrop{opacity:1}.fui-drawer__panel{position:fixed;display:flex;flex-direction:column;background-color:var(--fui-drawer-bg);z-index:2;pointer-events:auto;transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms}.fui-drawer--right .fui-drawer__panel{top:0;right:0;bottom:0;width:var(--_drawer-size, 480px);max-width:100%;border-left:1px solid var(--fui-drawer-border-color);box-shadow:var(--fui-drawer-shadow);transform:translate(100%)}.fui-drawer--right.fui-drawer--open .fui-drawer__panel{transform:translate(0)}.fui-drawer--left .fui-drawer__panel{top:0;left:0;bottom:0;width:var(--_drawer-size, 480px);max-width:100%;border-right:1px solid var(--fui-drawer-border-color);box-shadow:4px 0 24px var(--fui-black-10);transform:translate(-100%)}.fui-drawer--left.fui-drawer--open .fui-drawer__panel{transform:translate(0)}.fui-drawer--top .fui-drawer__panel{top:0;left:0;right:0;height:var(--_drawer-size, 480px);max-height:100%;border-bottom:1px solid var(--fui-drawer-border-color);box-shadow:0 4px 24px var(--fui-black-10);transform:translateY(-100%)}.fui-drawer--top.fui-drawer--open .fui-drawer__panel{transform:translateY(0)}.fui-drawer--bottom .fui-drawer__panel{bottom:0;left:0;right:0;height:var(--_drawer-size, 480px);max-height:100%;border-top:1px solid var(--fui-drawer-border-color);box-shadow:0 -4px 24px var(--fui-black-10);transform:translateY(100%)}.fui-drawer--bottom.fui-drawer--open .fui-drawer__panel{transform:translateY(0)}.fui-drawer__header{display:flex;align-items:center;justify-content:space-between;padding:var(--fui-drawer-header-padding);border-bottom:1px solid var(--fui-drawer-border-color);flex-shrink:0}.fui-drawer__title{font-size:var(--fui-font-size-03);font-weight:var(--fui-font-weight-semibold);color:var(--fui-text-primary);margin:0}.fui-drawer__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;border-radius:var(--fui-border-radius-sm);color:var(--fui-text-secondary);cursor:pointer;transition:background-color var(--fui-duration-moderate-01) var(--fui-ease-standard),color var(--fui-duration-moderate-01) var(--fui-ease-standard)}.fui-drawer__close:hover{background-color:var(--fui-surface-02);color:var(--fui-text-primary)}.fui-drawer__close:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-drawer__content{flex:1;overflow-y:auto;padding:var(--fui-drawer-content-padding)}.fui-drawer__footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--fui-spacing-03);padding:var(--fui-drawer-footer-padding);border-top:1px solid var(--fui-drawer-border-color);flex-shrink:0}.fui-drawer__footer:empty{display:none}@media(prefers-reduced-motion:reduce){.fui-drawer__backdrop,.fui-drawer__panel,.fui-drawer__close{transition:none}}\n"] }]
179
+ }, template: "@if (_opened() && hasBackdrop()) {\r\n <div class=\"fui-drawer__backdrop\" (click)=\"closeOnBackdropClick() ? close() : null\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"fui-drawer__panel\" [style.--_drawer-size]=\"_sizeValue()\" #drawerPanel tabindex=\"-1\">\r\n @if (title() || showCloseButton()) {\r\n <div class=\"fui-drawer__header\">\r\n @if (title()) {\r\n <h2 class=\"fui-drawer__title\">{{ title() }}</h2>\r\n }\r\n @if (showCloseButton()) {\r\n <button type=\"button\" class=\"fui-drawer__close\" (click)=\"close()\" aria-label=\"Close drawer\">\r\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"fui-drawer__content\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <div class=\"fui-drawer__footer\">\r\n <ng-content select=\"[drawerFooter]\"></ng-content>\r\n </div>\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}.fui-drawer{--fui-drawer-z-index: var(--fui-z-index-modal, 1050);--fui-drawer-bg: var(--fui-surface-00);--fui-drawer-border-color: var(--fui-border-color);--fui-drawer-shadow: -4px 0 24px var(--fui-black-10);--fui-drawer-backdrop-color: var(--fui-black-30);--fui-drawer-header-padding: var(--fui-spacing-04) var(--fui-spacing-05);--fui-drawer-content-padding: var(--fui-spacing-05);--fui-drawer-footer-padding: var(--fui-spacing-04) var(--fui-spacing-05);position:fixed;inset:0;pointer-events:none;z-index:var(--fui-drawer-z-index);overflow:hidden;visibility:hidden;transition:visibility 0s linear var(--fui-duration-moderate-01)}.fui-drawer--open{pointer-events:auto;visibility:visible;transition-delay:0s}.fui-drawer__backdrop{position:fixed;inset:0;background-color:var(--fui-drawer-backdrop-color);z-index:1;opacity:0;transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-drawer--open .fui-drawer__backdrop{opacity:1}.fui-drawer__panel{position:fixed;display:flex;flex-direction:column;background-color:var(--fui-drawer-bg);z-index:2;pointer-events:auto;transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms}.fui-drawer--right .fui-drawer__panel{top:0;right:0;bottom:0;width:var(--_drawer-size, 480px);max-width:100%;border-left:1px solid var(--fui-drawer-border-color);box-shadow:var(--fui-drawer-shadow);transform:translate(100%)}.fui-drawer--right.fui-drawer--open .fui-drawer__panel{transform:translate(0)}.fui-drawer--left .fui-drawer__panel{top:0;left:0;bottom:0;width:var(--_drawer-size, 480px);max-width:100%;border-right:1px solid var(--fui-drawer-border-color);box-shadow:4px 0 24px var(--fui-black-10);transform:translate(-100%)}.fui-drawer--left.fui-drawer--open .fui-drawer__panel{transform:translate(0)}.fui-drawer--top .fui-drawer__panel{top:0;left:0;right:0;height:var(--_drawer-size, 480px);max-height:100%;border-bottom:1px solid var(--fui-drawer-border-color);box-shadow:0 4px 24px var(--fui-black-10);transform:translateY(-100%)}.fui-drawer--top.fui-drawer--open .fui-drawer__panel{transform:translateY(0)}.fui-drawer--bottom .fui-drawer__panel{bottom:0;left:0;right:0;height:var(--_drawer-size, 480px);max-height:100%;border-top:1px solid var(--fui-drawer-border-color);box-shadow:0 -4px 24px var(--fui-black-10);transform:translateY(100%)}.fui-drawer--bottom.fui-drawer--open .fui-drawer__panel{transform:translateY(0)}.fui-drawer__header{display:flex;align-items:center;justify-content:space-between;padding:var(--fui-drawer-header-padding);border-bottom:1px solid var(--fui-drawer-border-color);flex-shrink:0}.fui-drawer__title{font-size:var(--fui-font-size-03);font-weight:var(--fui-font-weight-semibold);color:var(--fui-text-primary);margin:0}.fui-drawer__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;border-radius:var(--fui-border-radius-sm);color:var(--fui-text-secondary);cursor:pointer;transition:background-color var(--fui-duration-moderate-01) var(--fui-ease-standard),color var(--fui-duration-moderate-01) var(--fui-ease-standard)}.fui-drawer__close:hover{background-color:var(--fui-surface-02);color:var(--fui-text-primary)}.fui-drawer__close:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-drawer__content{flex:1;overflow-y:auto;padding:var(--fui-drawer-content-padding)}.fui-drawer__footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--fui-spacing-03);padding:var(--fui-drawer-footer-padding);border-top:1px solid var(--fui-drawer-border-color);flex-shrink:0}.fui-drawer__footer:empty{display:none}@media(prefers-reduced-motion:reduce){.fui-drawer__backdrop,.fui-drawer__panel,.fui-drawer__close{transition:none}}\n"] }]
180
180
  }], ctorParameters: () => [], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], opened: [{ type: i0.Input, args: [{ isSignal: true, alias: "opened", required: false }] }], hasBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasBackdrop", required: false }] }], closeOnBackdropClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnBackdropClick", required: false }] }], closeOnEsc: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEsc", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], showCloseButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCloseButton", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledBy", required: false }] }], openedChange: [{ type: i0.Output, args: ["openedChange"] }], closed: [{ type: i0.Output, args: ["closed"] }], drawerPanel: [{ type: i0.ViewChild, args: ['drawerPanel', { isSignal: true }] }], onKeydown: [{
181
181
  type: HostListener,
182
182
  args: ['document:keydown', ['$event']]
@@ -1 +1 @@
1
- {"version":3,"file":"raintonic-formaui-components-drawer.mjs","sources":["../../../lib/components/drawer/drawer.types.ts","../../../lib/components/drawer/drawer.component.ts","../../../lib/components/drawer/drawer.component.html","../../../lib/components/drawer/raintonic-formaui-components-drawer.ts"],"sourcesContent":["export type DrawerPosition = 'left' | 'right' | 'top' | 'bottom';\nexport type DrawerMode = 'overlay' | 'push';\nexport type DrawerSize = 'sm' | 'md' | 'lg' | 'full';\n\nexport const DRAWER_SIZES: Record<DrawerSize, string> = {\n sm: '320px',\n md: '480px',\n lg: '640px',\n full: '100%',\n};\n","import {\n Component,\n ChangeDetectionStrategy,\n ViewEncapsulation,\n input,\n output,\n signal,\n computed,\n effect,\n booleanAttribute,\n HostListener,\n ElementRef,\n inject,\n viewChild,\n Signal,\n WritableSignal,\n} from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\nimport { DrawerPosition, DrawerMode, DrawerSize, DRAWER_SIZES } from './drawer.types';\n\n@Component({\n selector: 'fui-drawer',\n standalone: true,\n imports: [FuiIconComponent],\n templateUrl: './drawer.component.html',\n styleUrls: ['./drawer.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'fui-drawer',\n '[class.fui-drawer--open]': '_opened()',\n '[class.fui-drawer--left]': 'position() === \"left\"',\n '[class.fui-drawer--right]': 'position() === \"right\"',\n '[class.fui-drawer--top]': 'position() === \"top\"',\n '[class.fui-drawer--bottom]': 'position() === \"bottom\"',\n '[class.fui-drawer--overlay]': 'mode() === \"overlay\"',\n '[class.fui-drawer--push]': 'mode() === \"push\"',\n '[attr.role]': '\"dialog\"',\n '[attr.aria-modal]': '_opened() ? \"true\" : null',\n '[attr.aria-label]': 'ariaLabel() || (!ariaLabelledBy() ? title() : null)',\n '[attr.aria-labelledby]': 'ariaLabelledBy()',\n },\n})\nexport class FuiDrawerComponent {\n private readonly _document = inject(DOCUMENT);\n\n // Inputs\n readonly position = input<DrawerPosition>('right');\n readonly mode = input<DrawerMode>('overlay');\n readonly size = input('md');\n readonly opened = input<boolean, unknown>(false, { transform: booleanAttribute });\n readonly hasBackdrop = input<boolean, unknown>(true, { transform: booleanAttribute });\n readonly closeOnBackdropClick = input<boolean, unknown>(true, { transform: booleanAttribute });\n readonly closeOnEsc = input<boolean, unknown>(true, { transform: booleanAttribute });\n readonly title = input('');\n readonly showCloseButton = input<boolean, unknown>(true, { transform: booleanAttribute });\n\n /** ARIA label for the drawer, used when no visible title is present */\n readonly ariaLabel = input<string | null>(null);\n\n /** ID of an element that labels the drawer */\n readonly ariaLabelledBy = input<string | null>(null);\n\n // Outputs\n readonly openedChange = output<boolean>();\n readonly closed = output();\n\n // Internal state\n readonly _opened: WritableSignal<boolean> = signal(false);\n readonly _animating: WritableSignal<boolean> = signal(false);\n\n // Track the last input value to avoid effect re-triggering on programmatic changes\n private _lastInputValue = false;\n\n // Focus management\n private _previouslyFocusedElement: HTMLElement | null = null;\n\n // ViewChild\n readonly drawerPanel: Signal<ElementRef<HTMLElement> | undefined> = viewChild<ElementRef<HTMLElement>>('drawerPanel');\n\n // Computed\n readonly _sizeValue: Signal<string> = computed(() => {\n const size = this.size();\n return DRAWER_SIZES[size as DrawerSize] ?? size;\n });\n\n readonly _isHorizontal: Signal<boolean> = computed(() => {\n const pos = this.position();\n return pos === 'left' || pos === 'right';\n });\n\n constructor() {\n // Sync opened input with internal state — only react when the input actually changes\n effect(() => {\n const inputValue = this.opened();\n if (inputValue !== this._lastInputValue) {\n this._lastInputValue = inputValue;\n if (inputValue) {\n this._openInternal();\n } else {\n this._closeInternal();\n }\n }\n });\n }\n\n @HostListener('document:keydown', ['$event'])\n onKeydown(event: KeyboardEvent): void {\n if (!this._opened()) return;\n\n if (event.key === 'Escape' && this.closeOnEsc()) {\n this.close();\n return;\n }\n\n // Focus trap cycling\n if (event.key === 'Tab') {\n const focusableElements = this._getAllFocusableElements();\n if (focusableElements.length === 0) {\n event.preventDefault();\n return;\n }\n\n const firstFocusable = focusableElements[0];\n const lastFocusable = focusableElements[focusableElements.length - 1];\n const activeElement = this._document.activeElement;\n\n if (event.shiftKey) {\n if (activeElement === firstFocusable) {\n event.preventDefault();\n lastFocusable.focus();\n }\n } else {\n if (activeElement === lastFocusable) {\n event.preventDefault();\n firstFocusable.focus();\n }\n }\n }\n }\n\n open(): void {\n if (!this._opened()) {\n this._openInternal();\n this.openedChange.emit(true);\n }\n }\n\n close(): void {\n if (this._opened()) {\n this._closeInternal();\n this.openedChange.emit(false);\n this.closed.emit();\n }\n }\n\n toggle(): void {\n if (this._opened()) {\n this.close();\n } else {\n this.open();\n }\n }\n\n private _openInternal(): void {\n this._previouslyFocusedElement = document.activeElement as HTMLElement;\n this._opened.set(true);\n\n // Focus the panel after it renders\n setTimeout(() => {\n this._focusFirstTabbable();\n });\n }\n\n private _closeInternal(): void {\n this._opened.set(false);\n\n // Restore focus\n if (this._previouslyFocusedElement) {\n this._previouslyFocusedElement.focus();\n this._previouslyFocusedElement = null;\n }\n }\n\n private _focusFirstTabbable(): void {\n const panel = this.drawerPanel()?.nativeElement;\n if (!panel) return;\n\n const focusable = this._getAllFocusableElements();\n\n if (focusable.length > 0) {\n focusable[0].focus();\n } else {\n panel.setAttribute('tabindex', '-1');\n panel.focus();\n }\n }\n\n private _getAllFocusableElements(): HTMLElement[] {\n const panel = this.drawerPanel()?.nativeElement;\n if (!panel) return [];\n\n const selectors = [\n 'a[href]',\n 'button:not([disabled])',\n 'textarea:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]',\n ].join(',');\n\n return Array.from(panel.querySelectorAll<HTMLElement>(selectors)).filter((el) => el.offsetParent !== null);\n }\n}\n","@if (_opened() && hasBackdrop()) {\n <div class=\"fui-drawer__backdrop\" (click)=\"closeOnBackdropClick() ? close() : null\" aria-hidden=\"true\"></div>\n}\n\n<div class=\"fui-drawer__panel\" [style.--_drawer-size]=\"_sizeValue()\" #drawerPanel tabindex=\"-1\">\n @if (title() || showCloseButton()) {\n <div class=\"fui-drawer__header\">\n @if (title()) {\n <h2 class=\"fui-drawer__title\">{{ title() }}</h2>\n }\n @if (showCloseButton()) {\n <button type=\"button\" class=\"fui-drawer__close\" (click)=\"close()\" aria-label=\"Close drawer\">\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\n </button>\n }\n </div>\n }\n\n <div class=\"fui-drawer__content\">\n <ng-content></ng-content>\n </div>\n\n <div class=\"fui-drawer__footer\">\n <ng-content select=\"[drawerFooter]\"></ng-content>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"raintonic-formaui-components-drawer.mjs","sources":["../../../lib/components/drawer/drawer.types.ts","../../../lib/components/drawer/drawer.component.ts","../../../lib/components/drawer/drawer.component.html","../../../lib/components/drawer/raintonic-formaui-components-drawer.ts"],"sourcesContent":["export type DrawerPosition = 'left' | 'right' | 'top' | 'bottom';\r\nexport type DrawerMode = 'overlay' | 'push';\r\nexport type DrawerSize = 'sm' | 'md' | 'lg' | 'full';\r\n\r\nexport const DRAWER_SIZES: Record<DrawerSize, string> = {\r\n sm: '320px',\r\n md: '480px',\r\n lg: '640px',\r\n full: '100%',\r\n};\r\n","import {\r\n Component,\r\n ChangeDetectionStrategy,\r\n ViewEncapsulation,\r\n input,\r\n output,\r\n signal,\r\n computed,\r\n effect,\r\n booleanAttribute,\r\n HostListener,\r\n ElementRef,\r\n inject,\r\n viewChild,\r\n Signal,\r\n WritableSignal,\r\n} from '@angular/core';\r\nimport { DOCUMENT } from '@angular/common';\r\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\r\nimport { DrawerPosition, DrawerMode, DrawerSize, DRAWER_SIZES } from './drawer.types';\r\n\r\n@Component({\r\n selector: 'fui-drawer',\r\n standalone: true,\r\n imports: [FuiIconComponent],\r\n templateUrl: './drawer.component.html',\r\n styleUrls: ['./drawer.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n host: {\r\n class: 'fui-drawer',\r\n '[class.fui-drawer--open]': '_opened()',\r\n '[class.fui-drawer--left]': 'position() === \"left\"',\r\n '[class.fui-drawer--right]': 'position() === \"right\"',\r\n '[class.fui-drawer--top]': 'position() === \"top\"',\r\n '[class.fui-drawer--bottom]': 'position() === \"bottom\"',\r\n '[class.fui-drawer--overlay]': 'mode() === \"overlay\"',\r\n '[class.fui-drawer--push]': 'mode() === \"push\"',\r\n '[attr.role]': '\"dialog\"',\r\n '[attr.aria-modal]': '_opened() ? \"true\" : null',\r\n '[attr.aria-label]': 'ariaLabel() || (!ariaLabelledBy() ? title() : null)',\r\n '[attr.aria-labelledby]': 'ariaLabelledBy()',\r\n },\r\n})\r\nexport class FuiDrawerComponent {\r\n private readonly _document = inject(DOCUMENT);\r\n\r\n // Inputs\r\n readonly position = input<DrawerPosition>('right');\r\n readonly mode = input<DrawerMode>('overlay');\r\n readonly size = input('md');\r\n readonly opened = input<boolean, unknown>(false, { transform: booleanAttribute });\r\n readonly hasBackdrop = input<boolean, unknown>(true, { transform: booleanAttribute });\r\n readonly closeOnBackdropClick = input<boolean, unknown>(true, { transform: booleanAttribute });\r\n readonly closeOnEsc = input<boolean, unknown>(true, { transform: booleanAttribute });\r\n readonly title = input('');\r\n readonly showCloseButton = input<boolean, unknown>(true, { transform: booleanAttribute });\r\n\r\n /** ARIA label for the drawer, used when no visible title is present */\r\n readonly ariaLabel = input<string | null>(null);\r\n\r\n /** ID of an element that labels the drawer */\r\n readonly ariaLabelledBy = input<string | null>(null);\r\n\r\n // Outputs\r\n readonly openedChange = output<boolean>();\r\n readonly closed = output();\r\n\r\n // Internal state\r\n readonly _opened: WritableSignal<boolean> = signal(false);\r\n readonly _animating: WritableSignal<boolean> = signal(false);\r\n\r\n // Track the last input value to avoid effect re-triggering on programmatic changes\r\n private _lastInputValue = false;\r\n\r\n // Focus management\r\n private _previouslyFocusedElement: HTMLElement | null = null;\r\n\r\n // ViewChild\r\n readonly drawerPanel: Signal<ElementRef<HTMLElement> | undefined> = viewChild<ElementRef<HTMLElement>>('drawerPanel');\r\n\r\n // Computed\r\n readonly _sizeValue: Signal<string> = computed(() => {\r\n const size = this.size();\r\n return DRAWER_SIZES[size as DrawerSize] ?? size;\r\n });\r\n\r\n readonly _isHorizontal: Signal<boolean> = computed(() => {\r\n const pos = this.position();\r\n return pos === 'left' || pos === 'right';\r\n });\r\n\r\n constructor() {\r\n // Sync opened input with internal state — only react when the input actually changes\r\n effect(() => {\r\n const inputValue = this.opened();\r\n if (inputValue !== this._lastInputValue) {\r\n this._lastInputValue = inputValue;\r\n if (inputValue) {\r\n this._openInternal();\r\n } else {\r\n this._closeInternal();\r\n }\r\n }\r\n });\r\n }\r\n\r\n @HostListener('document:keydown', ['$event'])\r\n onKeydown(event: KeyboardEvent): void {\r\n if (!this._opened()) return;\r\n\r\n if (event.key === 'Escape' && this.closeOnEsc()) {\r\n this.close();\r\n return;\r\n }\r\n\r\n // Focus trap cycling\r\n if (event.key === 'Tab') {\r\n const focusableElements = this._getAllFocusableElements();\r\n if (focusableElements.length === 0) {\r\n event.preventDefault();\r\n return;\r\n }\r\n\r\n const firstFocusable = focusableElements[0];\r\n const lastFocusable = focusableElements[focusableElements.length - 1];\r\n const activeElement = this._document.activeElement;\r\n\r\n if (event.shiftKey) {\r\n if (activeElement === firstFocusable) {\r\n event.preventDefault();\r\n lastFocusable.focus();\r\n }\r\n } else {\r\n if (activeElement === lastFocusable) {\r\n event.preventDefault();\r\n firstFocusable.focus();\r\n }\r\n }\r\n }\r\n }\r\n\r\n open(): void {\r\n if (!this._opened()) {\r\n this._openInternal();\r\n this.openedChange.emit(true);\r\n }\r\n }\r\n\r\n close(): void {\r\n if (this._opened()) {\r\n this._closeInternal();\r\n this.openedChange.emit(false);\r\n this.closed.emit();\r\n }\r\n }\r\n\r\n toggle(): void {\r\n if (this._opened()) {\r\n this.close();\r\n } else {\r\n this.open();\r\n }\r\n }\r\n\r\n private _openInternal(): void {\r\n this._previouslyFocusedElement = document.activeElement as HTMLElement;\r\n this._opened.set(true);\r\n\r\n // Focus the panel after it renders\r\n setTimeout(() => {\r\n this._focusFirstTabbable();\r\n });\r\n }\r\n\r\n private _closeInternal(): void {\r\n this._opened.set(false);\r\n\r\n // Restore focus\r\n if (this._previouslyFocusedElement) {\r\n this._previouslyFocusedElement.focus();\r\n this._previouslyFocusedElement = null;\r\n }\r\n }\r\n\r\n private _focusFirstTabbable(): void {\r\n const panel = this.drawerPanel()?.nativeElement;\r\n if (!panel) return;\r\n\r\n const focusable = this._getAllFocusableElements();\r\n\r\n if (focusable.length > 0) {\r\n focusable[0].focus();\r\n } else {\r\n panel.setAttribute('tabindex', '-1');\r\n panel.focus();\r\n }\r\n }\r\n\r\n private _getAllFocusableElements(): HTMLElement[] {\r\n const panel = this.drawerPanel()?.nativeElement;\r\n if (!panel) return [];\r\n\r\n const selectors = [\r\n 'a[href]',\r\n 'button:not([disabled])',\r\n 'textarea:not([disabled])',\r\n 'input:not([disabled])',\r\n 'select:not([disabled])',\r\n '[tabindex]:not([tabindex=\"-1\"])',\r\n '[contenteditable=\"true\"]',\r\n ].join(',');\r\n\r\n return Array.from(panel.querySelectorAll<HTMLElement>(selectors)).filter((el) => el.offsetParent !== null);\r\n }\r\n}\r\n","@if (_opened() && hasBackdrop()) {\r\n <div class=\"fui-drawer__backdrop\" (click)=\"closeOnBackdropClick() ? close() : null\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"fui-drawer__panel\" [style.--_drawer-size]=\"_sizeValue()\" #drawerPanel tabindex=\"-1\">\r\n @if (title() || showCloseButton()) {\r\n <div class=\"fui-drawer__header\">\r\n @if (title()) {\r\n <h2 class=\"fui-drawer__title\">{{ title() }}</h2>\r\n }\r\n @if (showCloseButton()) {\r\n <button type=\"button\" class=\"fui-drawer__close\" (click)=\"close()\" aria-label=\"Close drawer\">\r\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"fui-drawer__content\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <div class=\"fui-drawer__footer\">\r\n <ng-content select=\"[drawerFooter]\"></ng-content>\r\n </div>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"raintonic-formaui-components-dynamic-form.mjs","sources":["../../../lib/components/dynamic-form/dynamic-form-renderer.component.ts","../../../lib/components/dynamic-form/dynamic-form-renderer.component.html","../../../lib/components/dynamic-form/raintonic-formaui-components-dynamic-form.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n input,\n InputSignal,\n output,\n OutputEmitterRef,\n ViewEncapsulation,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';\n\nimport {\n FuiFormFieldComponent,\n FuiLabelComponent,\n FuiErrorComponent,\n FuiHintComponent,\n FuiPrefixDirective,\n FuiSuffixDirective,\n} from '@raintonic/formaui/components/form-field';\nimport { FuiInputDirective } from '@raintonic/formaui/components/input';\nimport { FuiSelectComponent, FuiOptionComponent } from '@raintonic/formaui/components/select';\nimport { FuiAutocompleteComponent } from '@raintonic/formaui/components/autocomplete';\nimport { FuiCheckboxComponent } from '@raintonic/formaui/components/checkbox';\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\n\nimport {\n DynamicFormConfig,\n DynamicFormField,\n DynamicFormRow,\n DynamicFormAutocompleteEvent,\n DynamicFormFileEvent,\n} from './dynamic-form.types';\n\n/**\n * # DynamicFormRenderer Component\n *\n * A component that automatically renders forms based on a JSON configuration.\n * It takes a FormGroup and a configuration object that specifies the form structure.\n *\n * ## Features\n * - Supports multiple field types: input, select, autocomplete, textarea, file, checkbox\n * - Flexible row-based layout with configurable column spans\n * - Section grouping with customizable titles\n * - Empty area/spacer support for layout control\n * - Full integration with Angular reactive forms\n * - Responsive design with mobile-first approach\n *\n * ## Usage\n *\n * ### Basic Form\n * ```typescript\n * @Component({\n * template: `\n * <fui-dynamic-form-renderer\n * [formGroup]=\"myForm\"\n * [config]=\"formConfig\"\n * ></fui-dynamic-form-renderer>\n * `\n * })\n * export class MyComponent {\n * myForm = new FormGroup({\n * firstName: new FormControl(''),\n * lastName: new FormControl(''),\n * email: new FormControl(''),\n * });\n *\n * formConfig: DynamicFormConfig = {\n * sections: [{\n * title: { text: 'Personal Information', importance: 'h3' },\n * rows: [\n * {\n * fields: [\n * { key: 'firstName', type: 'input', label: 'First Name', colSpan: 6 },\n * { key: 'lastName', type: 'input', label: 'Last Name', colSpan: 6 },\n * ]\n * },\n * {\n * fields: [\n * { key: 'email', type: 'input', inputType: 'email', label: 'Email', colSpan: 12 },\n * ]\n * }\n * ]\n * }]\n * };\n * }\n * ```\n *\n * ### With Validation Errors\n * ```typescript\n * formConfig: DynamicFormConfig = {\n * sections: [{\n * rows: [{\n * fields: [{\n * key: 'email',\n * type: 'input',\n * inputType: 'email',\n * label: 'Email',\n * errors: {\n * required: 'Email is required',\n * email: 'Please enter a valid email'\n * }\n * }]\n * }]\n * }]\n * };\n * ```\n *\n * ### With Select and Autocomplete\n * ```typescript\n * formConfig: DynamicFormConfig = {\n * sections: [{\n * rows: [{\n * fields: [\n * {\n * key: 'country',\n * type: 'select',\n * label: 'Country',\n * options: [\n * { value: 'us', label: 'United States' },\n * { value: 'ca', label: 'Canada' },\n * ],\n * colSpan: 6\n * },\n * {\n * key: 'city',\n * type: 'autocomplete',\n * label: 'City',\n * options: [\n * { value: 'nyc', label: 'New York' },\n * { value: 'la', label: 'Los Angeles' },\n * ],\n * showAddButton: true,\n * colSpan: 6\n * }\n * ]\n * }]\n * }]\n * };\n * ```\n */\n@Component({\n selector: 'fui-dynamic-form-renderer',\n standalone: true,\n imports: [\n CommonModule,\n ReactiveFormsModule,\n FuiFormFieldComponent,\n FuiLabelComponent,\n FuiErrorComponent,\n FuiHintComponent,\n FuiPrefixDirective,\n FuiSuffixDirective,\n FuiInputDirective,\n FuiSelectComponent,\n FuiOptionComponent,\n FuiAutocompleteComponent,\n FuiCheckboxComponent,\n FuiIconComponent,\n ],\n templateUrl: './dynamic-form-renderer.component.html',\n styleUrls: ['./dynamic-form-renderer.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'fui-dynamic-form-renderer',\n },\n})\nexport class FuiDynamicFormRendererComponent {\n /**\n * The FormGroup instance to bind the form to\n */\n readonly formGroup: InputSignal<FormGroup> = input.required<FormGroup>();\n\n /**\n * The configuration object that defines the form structure\n */\n readonly config: InputSignal<DynamicFormConfig> = input.required<DynamicFormConfig>();\n\n /**\n * Emitted when an autocomplete action (add/refresh) is triggered\n */\n readonly autocompleteAction: OutputEmitterRef<DynamicFormAutocompleteEvent> = output<DynamicFormAutocompleteEvent>();\n\n /**\n * Emitted when a file input changes\n */\n readonly fileChange: OutputEmitterRef<DynamicFormFileEvent> = output<DynamicFormFileEvent>();\n\n /**\n * Default comparison function for select components\n */\n readonly defaultCompareWith = (o1: unknown, o2: unknown): boolean => o1 === o2;\n\n /**\n * Gets a FormControl from the FormGroup by key\n * @param key The control name/key\n * @returns The FormControl instance\n */\n getControl(key: string): FormControl {\n const control = this.formGroup().get(key);\n if (!control) {\n // Control not found - return empty control to prevent errors\n return new FormControl(); // Return empty control to prevent errors\n }\n return control as FormControl;\n }\n\n /**\n * Converts error object entries to array for iteration\n * @param errors The errors object from field config\n * @returns Array of key-value pairs\n */\n getErrorEntries(errors: Record<string, string>): { key: string; value: string }[] {\n return Object.entries(errors).map(([key, value]) => ({ key, value }));\n }\n\n /**\n * Gets CSS align-items value from row align setting\n * @param align The row alignment setting\n * @returns CSS align-items value\n */\n getAlignItems(align?: DynamicFormRow['align']): string {\n switch (align) {\n case 'start':\n return 'flex-start';\n case 'center':\n return 'center';\n case 'end':\n return 'flex-end';\n case 'stretch':\n return 'stretch';\n default:\n return 'flex-start';\n }\n }\n\n /**\n * Gets CSS justify-content value from row justify setting\n * @param justify The row justification setting\n * @returns CSS justify-content value\n */\n getJustifyContent(justify?: DynamicFormRow['justify']): string {\n switch (justify) {\n case 'start':\n return 'flex-start';\n case 'center':\n return 'center';\n case 'end':\n return 'flex-end';\n case 'between':\n return 'space-between';\n case 'around':\n return 'space-around';\n case 'evenly':\n return 'space-evenly';\n default:\n return 'flex-start';\n }\n }\n\n /**\n * Handles autocomplete add/refresh button clicks\n * @param fieldKey The field key that triggered the action\n * @param action The action type ('add' or 'refresh')\n */\n onAutocompleteAction(fieldKey: string, action: 'add' | 'refresh'): void {\n this.autocompleteAction.emit({ fieldKey, action });\n }\n\n /**\n * Handles file input changes\n * @param event The input change event\n * @param fieldKey The field key\n */\n onFileChange(event: Event, fieldKey: string): void {\n const input = event.target as HTMLInputElement;\n this.fileChange.emit({ fieldKey, files: input.files });\n\n // Also update the form control if it exists\n const control = this.formGroup().get(fieldKey);\n if (control) {\n control.setValue(input.files);\n control.markAsTouched();\n }\n }\n\n /**\n * Type guard to check if a field is not a spacer\n * @param field The field configuration\n * @returns Whether the field has a key\n */\n isFieldWithKey(field: DynamicFormField): field is Exclude<DynamicFormField, { type: 'spacer' }> {\n return field.type !== 'spacer' || !!field.key;\n }\n}\n","<div class=\"fui-dynamic-form\" [class]=\"config().className\">\r\n @for (section of config().sections; track $index) {\r\n <div\r\n class=\"fui-dynamic-form__section\"\r\n [class]=\"section.className\"\r\n [style.--section-row-gap]=\"section.rowGap ? 'var(--fui-spacing-' + section.rowGap + ')' : null\"\r\n >\r\n @if (section.title) {\r\n <div class=\"fui-dynamic-form__title-wrapper\" [class]=\"section.title.className\">\r\n @switch (section.title.importance) {\r\n @case ('h1') {\r\n <h1 class=\"fui-dynamic-form__title fui-display-xl fui-font-semibold\">\r\n {{ section.title.text }}\r\n </h1>\r\n }\r\n @case ('h2') {\r\n <h2 class=\"fui-dynamic-form__title fui-display-lg fui-font-semibold\">\r\n {{ section.title.text }}\r\n </h2>\r\n }\r\n @case ('h3') {\r\n <h3 class=\"fui-dynamic-form__title fui-display-md fui-font-semibold\">\r\n {{ section.title.text }}\r\n </h3>\r\n }\r\n @case ('h4') {\r\n <h4 class=\"fui-dynamic-form__title fui-display-sm fui-font-semibold\">\r\n {{ section.title.text }}\r\n </h4>\r\n }\r\n @case ('h5') {\r\n <h5 class=\"fui-dynamic-form__title fui-display-xs fui-font-medium\">\r\n {{ section.title.text }}\r\n </h5>\r\n }\r\n @case ('h6') {\r\n <h6 class=\"fui-dynamic-form__title fui-text-xl fui-font-medium\">{{ section.title.text }}</h6>\r\n }\r\n }\r\n @if (section.title.description) {\r\n <p class=\"fui-dynamic-form__description fui-text-md\">{{ section.title.description }}</p>\r\n }\r\n </div>\r\n }\r\n\r\n @for (row of section.rows; track $index) {\r\n <div\r\n class=\"fui-dynamic-form__row\"\r\n [class]=\"row.className\"\r\n [style.--row-gap]=\"row.gap ? 'var(--fui-spacing-' + row.gap + ')' : null\"\r\n [style.align-items]=\"getAlignItems(row.align)\"\r\n [style.justify-content]=\"getJustifyContent(row.justify)\"\r\n >\r\n @for (field of row.fields; track field.key ?? $index) {\r\n <div class=\"fui-dynamic-form__field\" [class]=\"field.className\" [style.--field-col-span]=\"field.colSpan\">\r\n @switch (field.type) {\r\n @case ('input') {\r\n <ng-container *ngTemplateOutlet=\"inputTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('textarea') {\r\n <ng-container *ngTemplateOutlet=\"textareaTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('select') {\r\n <ng-container *ngTemplateOutlet=\"selectTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('autocomplete') {\r\n <ng-container *ngTemplateOutlet=\"autocompleteTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('checkbox') {\r\n <ng-container *ngTemplateOutlet=\"checkboxTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('file') {\r\n <ng-container *ngTemplateOutlet=\"fileTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('spacer') {\r\n <div class=\"fui-dynamic-form__spacer\"></div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n\r\n<!-- Input Template -->\r\n<ng-template #inputTemplate let-field>\r\n <fui-form-field>\r\n @if (field.label && !field.hideLabel) {\r\n <fui-label>{{ field.label }}</fui-label>\r\n }\r\n @if (field.prefixIcon) {\r\n <fui-icon fuiPrefix [name]=\"field.prefixIcon\"></fui-icon>\r\n }\r\n <input\r\n fuiInput\r\n [type]=\"field.inputType || 'text'\"\r\n [formControl]=\"getControl(field.key)\"\r\n [placeholder]=\"field.placeholder || ''\"\r\n [readonly]=\"field.readonly || false\"\r\n [maxlength]=\"field.maxLength\"\r\n [minlength]=\"field.minLength\"\r\n [pattern]=\"field.pattern\"\r\n [min]=\"field.min\"\r\n [max]=\"field.max\"\r\n [step]=\"field.step\"\r\n />\r\n @if (field.suffixIcon) {\r\n <fui-icon fuiSuffix [name]=\"field.suffixIcon\"></fui-icon>\r\n }\r\n @if (field.hint) {\r\n <fui-hint>{{ field.hint }}</fui-hint>\r\n }\r\n <ng-container *ngTemplateOutlet=\"errorsTemplate; context: { $implicit: field }\"></ng-container>\r\n </fui-form-field>\r\n</ng-template>\r\n\r\n<!-- Textarea Template -->\r\n<ng-template #textareaTemplate let-field>\r\n <fui-form-field>\r\n @if (field.label && !field.hideLabel) {\r\n <fui-label>{{ field.label }}</fui-label>\r\n }\r\n <textarea\r\n fuiInput\r\n [formControl]=\"getControl(field.key)\"\r\n [placeholder]=\"field.placeholder || ''\"\r\n [readonly]=\"field.readonly || false\"\r\n [rows]=\"field.rows || 3\"\r\n [maxlength]=\"field.maxLength\"\r\n [minlength]=\"field.minLength\"\r\n ></textarea>\r\n @if (field.hint) {\r\n <fui-hint>{{ field.hint }}</fui-hint>\r\n }\r\n <ng-container *ngTemplateOutlet=\"errorsTemplate; context: { $implicit: field }\"></ng-container>\r\n </fui-form-field>\r\n</ng-template>\r\n\r\n<!-- Select Template -->\r\n<ng-template #selectTemplate let-field>\r\n <fui-form-field>\r\n @if (field.label && !field.hideLabel) {\r\n <fui-label>{{ field.label }}</fui-label>\r\n }\r\n @if (field.prefixIcon) {\r\n <fui-icon fuiPrefix [name]=\"field.prefixIcon\"></fui-icon>\r\n }\r\n <fui-select\r\n [formControl]=\"getControl(field.key)\"\r\n [placeholder]=\"field.placeholder || ''\"\r\n [multiple]=\"field.multiple || false\"\r\n [compareWith]=\"field.compareWith || defaultCompareWith\"\r\n >\r\n @for (option of field.options; track option.value) {\r\n <fui-option [value]=\"option.value\" [disabled]=\"option.disabled || false\">\r\n {{ option.label }}\r\n </fui-option>\r\n }\r\n </fui-select>\r\n @if (field.hint) {\r\n <fui-hint>{{ field.hint }}</fui-hint>\r\n }\r\n <ng-container *ngTemplateOutlet=\"errorsTemplate; context: { $implicit: field }\"></ng-container>\r\n </fui-form-field>\r\n</ng-template>\r\n\r\n<!-- Autocomplete Template -->\r\n<ng-template #autocompleteTemplate let-field>\r\n <fui-form-field>\r\n @if (field.label && !field.hideLabel) {\r\n <fui-label>{{ field.label }}</fui-label>\r\n }\r\n <fui-autocomplete\r\n [formControl]=\"getControl(field.key)\"\r\n [placeholder]=\"field.placeholder || ''\"\r\n [showAddButton]=\"field.showAddButton || false\"\r\n [showRefreshButton]=\"field.showRefreshButton || false\"\r\n [addButtonLabel]=\"field.addButtonLabel || 'Add New'\"\r\n [refreshButtonLabel]=\"field.refreshButtonLabel || 'Refresh'\"\r\n [noOptionsText]=\"field.noOptionsText || 'No options found'\"\r\n [searchPlaceholder]=\"field.searchPlaceholder || 'Search...'\"\r\n (addNew)=\"onAutocompleteAction(field.key, 'add')\"\r\n (refresh)=\"onAutocompleteAction(field.key, 'refresh')\"\r\n ></fui-autocomplete>\r\n @if (field.hint) {\r\n <fui-hint>{{ field.hint }}</fui-hint>\r\n }\r\n <ng-container *ngTemplateOutlet=\"errorsTemplate; context: { $implicit: field }\"></ng-container>\r\n </fui-form-field>\r\n</ng-template>\r\n\r\n<!-- Checkbox Template -->\r\n<ng-template #checkboxTemplate let-field>\r\n <div class=\"fui-dynamic-form__checkbox-wrapper\">\r\n <fui-checkbox [formControl]=\"getControl(field.key)\" [labelPosition]=\"field.labelPosition || 'after'\">\r\n {{ field.label }}\r\n </fui-checkbox>\r\n @if (field.hint) {\r\n <div class=\"fui-dynamic-form__checkbox-hint fui-text-sm\">{{ field.hint }}</div>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<!-- File Template -->\r\n<ng-template #fileTemplate let-field>\r\n <div class=\"fui-dynamic-form__file-field\">\r\n @if (field.label && !field.hideLabel) {\r\n <label class=\"fui-dynamic-form__file-label fui-text-sm\">{{ field.label }}</label>\r\n }\r\n <input\r\n type=\"file\"\r\n class=\"fui-dynamic-form__file-input\"\r\n [accept]=\"field.fileConfig?.accept\"\r\n [multiple]=\"field.fileConfig?.multiple || false\"\r\n [disabled]=\"field.disabled || false\"\r\n (change)=\"onFileChange($event, field.key)\"\r\n />\r\n @if (field.hint) {\r\n <div class=\"fui-dynamic-form__file-hint fui-text-sm\">{{ field.hint }}</div>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<!-- Errors Template -->\r\n<ng-template #errorsTemplate let-field>\r\n @if (field.errors && getControl(field.key)) {\r\n @for (errorEntry of getErrorEntries(field.errors); track errorEntry.key) {\r\n @if (getControl(field.key).hasError(errorEntry.key)) {\r\n <fui-error>{{ errorEntry.value }}</fui-error>\r\n }\r\n }\r\n }\r\n</ng-template>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"raintonic-formaui-components-dynamic-form.mjs","sources":["../../../lib/components/dynamic-form/dynamic-form-renderer.component.ts","../../../lib/components/dynamic-form/dynamic-form-renderer.component.html","../../../lib/components/dynamic-form/raintonic-formaui-components-dynamic-form.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n input,\r\n InputSignal,\r\n output,\r\n OutputEmitterRef,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';\r\n\r\nimport {\r\n FuiFormFieldComponent,\r\n FuiLabelComponent,\r\n FuiErrorComponent,\r\n FuiHintComponent,\r\n FuiPrefixDirective,\r\n FuiSuffixDirective,\r\n} from '@raintonic/formaui/components/form-field';\r\nimport { FuiInputDirective } from '@raintonic/formaui/components/input';\r\nimport { FuiSelectComponent, FuiOptionComponent } from '@raintonic/formaui/components/select';\r\nimport { FuiAutocompleteComponent } from '@raintonic/formaui/components/autocomplete';\r\nimport { FuiCheckboxComponent } from '@raintonic/formaui/components/checkbox';\r\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\r\n\r\nimport {\r\n DynamicFormConfig,\r\n DynamicFormField,\r\n DynamicFormRow,\r\n DynamicFormAutocompleteEvent,\r\n DynamicFormFileEvent,\r\n} from './dynamic-form.types';\r\n\r\n/**\r\n * # DynamicFormRenderer Component\r\n *\r\n * A component that automatically renders forms based on a JSON configuration.\r\n * It takes a FormGroup and a configuration object that specifies the form structure.\r\n *\r\n * ## Features\r\n * - Supports multiple field types: input, select, autocomplete, textarea, file, checkbox\r\n * - Flexible row-based layout with configurable column spans\r\n * - Section grouping with customizable titles\r\n * - Empty area/spacer support for layout control\r\n * - Full integration with Angular reactive forms\r\n * - Responsive design with mobile-first approach\r\n *\r\n * ## Usage\r\n *\r\n * ### Basic Form\r\n * ```typescript\r\n * @Component({\r\n * template: `\r\n * <fui-dynamic-form-renderer\r\n * [formGroup]=\"myForm\"\r\n * [config]=\"formConfig\"\r\n * ></fui-dynamic-form-renderer>\r\n * `\r\n * })\r\n * export class MyComponent {\r\n * myForm = new FormGroup({\r\n * firstName: new FormControl(''),\r\n * lastName: new FormControl(''),\r\n * email: new FormControl(''),\r\n * });\r\n *\r\n * formConfig: DynamicFormConfig = {\r\n * sections: [{\r\n * title: { text: 'Personal Information', importance: 'h3' },\r\n * rows: [\r\n * {\r\n * fields: [\r\n * { key: 'firstName', type: 'input', label: 'First Name', colSpan: 6 },\r\n * { key: 'lastName', type: 'input', label: 'Last Name', colSpan: 6 },\r\n * ]\r\n * },\r\n * {\r\n * fields: [\r\n * { key: 'email', type: 'input', inputType: 'email', label: 'Email', colSpan: 12 },\r\n * ]\r\n * }\r\n * ]\r\n * }]\r\n * };\r\n * }\r\n * ```\r\n *\r\n * ### With Validation Errors\r\n * ```typescript\r\n * formConfig: DynamicFormConfig = {\r\n * sections: [{\r\n * rows: [{\r\n * fields: [{\r\n * key: 'email',\r\n * type: 'input',\r\n * inputType: 'email',\r\n * label: 'Email',\r\n * errors: {\r\n * required: 'Email is required',\r\n * email: 'Please enter a valid email'\r\n * }\r\n * }]\r\n * }]\r\n * }]\r\n * };\r\n * ```\r\n *\r\n * ### With Select and Autocomplete\r\n * ```typescript\r\n * formConfig: DynamicFormConfig = {\r\n * sections: [{\r\n * rows: [{\r\n * fields: [\r\n * {\r\n * key: 'country',\r\n * type: 'select',\r\n * label: 'Country',\r\n * options: [\r\n * { value: 'us', label: 'United States' },\r\n * { value: 'ca', label: 'Canada' },\r\n * ],\r\n * colSpan: 6\r\n * },\r\n * {\r\n * key: 'city',\r\n * type: 'autocomplete',\r\n * label: 'City',\r\n * options: [\r\n * { value: 'nyc', label: 'New York' },\r\n * { value: 'la', label: 'Los Angeles' },\r\n * ],\r\n * showAddButton: true,\r\n * colSpan: 6\r\n * }\r\n * ]\r\n * }]\r\n * }]\r\n * };\r\n * ```\r\n */\r\n@Component({\r\n selector: 'fui-dynamic-form-renderer',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n ReactiveFormsModule,\r\n FuiFormFieldComponent,\r\n FuiLabelComponent,\r\n FuiErrorComponent,\r\n FuiHintComponent,\r\n FuiPrefixDirective,\r\n FuiSuffixDirective,\r\n FuiInputDirective,\r\n FuiSelectComponent,\r\n FuiOptionComponent,\r\n FuiAutocompleteComponent,\r\n FuiCheckboxComponent,\r\n FuiIconComponent,\r\n ],\r\n templateUrl: './dynamic-form-renderer.component.html',\r\n styleUrls: ['./dynamic-form-renderer.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n host: {\r\n class: 'fui-dynamic-form-renderer',\r\n },\r\n})\r\nexport class FuiDynamicFormRendererComponent {\r\n /**\r\n * The FormGroup instance to bind the form to\r\n */\r\n readonly formGroup: InputSignal<FormGroup> = input.required<FormGroup>();\r\n\r\n /**\r\n * The configuration object that defines the form structure\r\n */\r\n readonly config: InputSignal<DynamicFormConfig> = input.required<DynamicFormConfig>();\r\n\r\n /**\r\n * Emitted when an autocomplete action (add/refresh) is triggered\r\n */\r\n readonly autocompleteAction: OutputEmitterRef<DynamicFormAutocompleteEvent> = output<DynamicFormAutocompleteEvent>();\r\n\r\n /**\r\n * Emitted when a file input changes\r\n */\r\n readonly fileChange: OutputEmitterRef<DynamicFormFileEvent> = output<DynamicFormFileEvent>();\r\n\r\n /**\r\n * Default comparison function for select components\r\n */\r\n readonly defaultCompareWith = (o1: unknown, o2: unknown): boolean => o1 === o2;\r\n\r\n /**\r\n * Gets a FormControl from the FormGroup by key\r\n * @param key The control name/key\r\n * @returns The FormControl instance\r\n */\r\n getControl(key: string): FormControl {\r\n const control = this.formGroup().get(key);\r\n if (!control) {\r\n // Control not found - return empty control to prevent errors\r\n return new FormControl(); // Return empty control to prevent errors\r\n }\r\n return control as FormControl;\r\n }\r\n\r\n /**\r\n * Converts error object entries to array for iteration\r\n * @param errors The errors object from field config\r\n * @returns Array of key-value pairs\r\n */\r\n getErrorEntries(errors: Record<string, string>): { key: string; value: string }[] {\r\n return Object.entries(errors).map(([key, value]) => ({ key, value }));\r\n }\r\n\r\n /**\r\n * Gets CSS align-items value from row align setting\r\n * @param align The row alignment setting\r\n * @returns CSS align-items value\r\n */\r\n getAlignItems(align?: DynamicFormRow['align']): string {\r\n switch (align) {\r\n case 'start':\r\n return 'flex-start';\r\n case 'center':\r\n return 'center';\r\n case 'end':\r\n return 'flex-end';\r\n case 'stretch':\r\n return 'stretch';\r\n default:\r\n return 'flex-start';\r\n }\r\n }\r\n\r\n /**\r\n * Gets CSS justify-content value from row justify setting\r\n * @param justify The row justification setting\r\n * @returns CSS justify-content value\r\n */\r\n getJustifyContent(justify?: DynamicFormRow['justify']): string {\r\n switch (justify) {\r\n case 'start':\r\n return 'flex-start';\r\n case 'center':\r\n return 'center';\r\n case 'end':\r\n return 'flex-end';\r\n case 'between':\r\n return 'space-between';\r\n case 'around':\r\n return 'space-around';\r\n case 'evenly':\r\n return 'space-evenly';\r\n default:\r\n return 'flex-start';\r\n }\r\n }\r\n\r\n /**\r\n * Handles autocomplete add/refresh button clicks\r\n * @param fieldKey The field key that triggered the action\r\n * @param action The action type ('add' or 'refresh')\r\n */\r\n onAutocompleteAction(fieldKey: string, action: 'add' | 'refresh'): void {\r\n this.autocompleteAction.emit({ fieldKey, action });\r\n }\r\n\r\n /**\r\n * Handles file input changes\r\n * @param event The input change event\r\n * @param fieldKey The field key\r\n */\r\n onFileChange(event: Event, fieldKey: string): void {\r\n const input = event.target as HTMLInputElement;\r\n this.fileChange.emit({ fieldKey, files: input.files });\r\n\r\n // Also update the form control if it exists\r\n const control = this.formGroup().get(fieldKey);\r\n if (control) {\r\n control.setValue(input.files);\r\n control.markAsTouched();\r\n }\r\n }\r\n\r\n /**\r\n * Type guard to check if a field is not a spacer\r\n * @param field The field configuration\r\n * @returns Whether the field has a key\r\n */\r\n isFieldWithKey(field: DynamicFormField): field is Exclude<DynamicFormField, { type: 'spacer' }> {\r\n return field.type !== 'spacer' || !!field.key;\r\n }\r\n}\r\n","<div class=\"fui-dynamic-form\" [class]=\"config().className\">\r\n @for (section of config().sections; track $index) {\r\n <div\r\n class=\"fui-dynamic-form__section\"\r\n [class]=\"section.className\"\r\n [style.--section-row-gap]=\"section.rowGap ? 'var(--fui-spacing-' + section.rowGap + ')' : null\"\r\n >\r\n @if (section.title) {\r\n <div class=\"fui-dynamic-form__title-wrapper\" [class]=\"section.title.className\">\r\n @switch (section.title.importance) {\r\n @case ('h1') {\r\n <h1 class=\"fui-dynamic-form__title fui-display-xl fui-font-semibold\">\r\n {{ section.title.text }}\r\n </h1>\r\n }\r\n @case ('h2') {\r\n <h2 class=\"fui-dynamic-form__title fui-display-lg fui-font-semibold\">\r\n {{ section.title.text }}\r\n </h2>\r\n }\r\n @case ('h3') {\r\n <h3 class=\"fui-dynamic-form__title fui-display-md fui-font-semibold\">\r\n {{ section.title.text }}\r\n </h3>\r\n }\r\n @case ('h4') {\r\n <h4 class=\"fui-dynamic-form__title fui-display-sm fui-font-semibold\">\r\n {{ section.title.text }}\r\n </h4>\r\n }\r\n @case ('h5') {\r\n <h5 class=\"fui-dynamic-form__title fui-display-xs fui-font-medium\">\r\n {{ section.title.text }}\r\n </h5>\r\n }\r\n @case ('h6') {\r\n <h6 class=\"fui-dynamic-form__title fui-text-xl fui-font-medium\">{{ section.title.text }}</h6>\r\n }\r\n }\r\n @if (section.title.description) {\r\n <p class=\"fui-dynamic-form__description fui-text-md\">{{ section.title.description }}</p>\r\n }\r\n </div>\r\n }\r\n\r\n @for (row of section.rows; track $index) {\r\n <div\r\n class=\"fui-dynamic-form__row\"\r\n [class]=\"row.className\"\r\n [style.--row-gap]=\"row.gap ? 'var(--fui-spacing-' + row.gap + ')' : null\"\r\n [style.align-items]=\"getAlignItems(row.align)\"\r\n [style.justify-content]=\"getJustifyContent(row.justify)\"\r\n >\r\n @for (field of row.fields; track field.key ?? $index) {\r\n <div class=\"fui-dynamic-form__field\" [class]=\"field.className\" [style.--field-col-span]=\"field.colSpan\">\r\n @switch (field.type) {\r\n @case ('input') {\r\n <ng-container *ngTemplateOutlet=\"inputTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('textarea') {\r\n <ng-container *ngTemplateOutlet=\"textareaTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('select') {\r\n <ng-container *ngTemplateOutlet=\"selectTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('autocomplete') {\r\n <ng-container *ngTemplateOutlet=\"autocompleteTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('checkbox') {\r\n <ng-container *ngTemplateOutlet=\"checkboxTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('file') {\r\n <ng-container *ngTemplateOutlet=\"fileTemplate; context: { $implicit: field }\"></ng-container>\r\n }\r\n @case ('spacer') {\r\n <div class=\"fui-dynamic-form__spacer\"></div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n\r\n<!-- Input Template -->\r\n<ng-template #inputTemplate let-field>\r\n <fui-form-field>\r\n @if (field.label && !field.hideLabel) {\r\n <fui-label>{{ field.label }}</fui-label>\r\n }\r\n @if (field.prefixIcon) {\r\n <fui-icon fuiPrefix [name]=\"field.prefixIcon\"></fui-icon>\r\n }\r\n <input\r\n fuiInput\r\n [type]=\"field.inputType || 'text'\"\r\n [formControl]=\"getControl(field.key)\"\r\n [placeholder]=\"field.placeholder || ''\"\r\n [readonly]=\"field.readonly || false\"\r\n [maxlength]=\"field.maxLength\"\r\n [minlength]=\"field.minLength\"\r\n [pattern]=\"field.pattern\"\r\n [min]=\"field.min\"\r\n [max]=\"field.max\"\r\n [step]=\"field.step\"\r\n />\r\n @if (field.suffixIcon) {\r\n <fui-icon fuiSuffix [name]=\"field.suffixIcon\"></fui-icon>\r\n }\r\n @if (field.hint) {\r\n <fui-hint>{{ field.hint }}</fui-hint>\r\n }\r\n <ng-container *ngTemplateOutlet=\"errorsTemplate; context: { $implicit: field }\"></ng-container>\r\n </fui-form-field>\r\n</ng-template>\r\n\r\n<!-- Textarea Template -->\r\n<ng-template #textareaTemplate let-field>\r\n <fui-form-field>\r\n @if (field.label && !field.hideLabel) {\r\n <fui-label>{{ field.label }}</fui-label>\r\n }\r\n <textarea\r\n fuiInput\r\n [formControl]=\"getControl(field.key)\"\r\n [placeholder]=\"field.placeholder || ''\"\r\n [readonly]=\"field.readonly || false\"\r\n [rows]=\"field.rows || 3\"\r\n [maxlength]=\"field.maxLength\"\r\n [minlength]=\"field.minLength\"\r\n ></textarea>\r\n @if (field.hint) {\r\n <fui-hint>{{ field.hint }}</fui-hint>\r\n }\r\n <ng-container *ngTemplateOutlet=\"errorsTemplate; context: { $implicit: field }\"></ng-container>\r\n </fui-form-field>\r\n</ng-template>\r\n\r\n<!-- Select Template -->\r\n<ng-template #selectTemplate let-field>\r\n <fui-form-field>\r\n @if (field.label && !field.hideLabel) {\r\n <fui-label>{{ field.label }}</fui-label>\r\n }\r\n @if (field.prefixIcon) {\r\n <fui-icon fuiPrefix [name]=\"field.prefixIcon\"></fui-icon>\r\n }\r\n <fui-select\r\n [formControl]=\"getControl(field.key)\"\r\n [placeholder]=\"field.placeholder || ''\"\r\n [multiple]=\"field.multiple || false\"\r\n [compareWith]=\"field.compareWith || defaultCompareWith\"\r\n >\r\n @for (option of field.options; track option.value) {\r\n <fui-option [value]=\"option.value\" [disabled]=\"option.disabled || false\">\r\n {{ option.label }}\r\n </fui-option>\r\n }\r\n </fui-select>\r\n @if (field.hint) {\r\n <fui-hint>{{ field.hint }}</fui-hint>\r\n }\r\n <ng-container *ngTemplateOutlet=\"errorsTemplate; context: { $implicit: field }\"></ng-container>\r\n </fui-form-field>\r\n</ng-template>\r\n\r\n<!-- Autocomplete Template -->\r\n<ng-template #autocompleteTemplate let-field>\r\n <fui-form-field>\r\n @if (field.label && !field.hideLabel) {\r\n <fui-label>{{ field.label }}</fui-label>\r\n }\r\n <fui-autocomplete\r\n [formControl]=\"getControl(field.key)\"\r\n [placeholder]=\"field.placeholder || ''\"\r\n [showAddButton]=\"field.showAddButton || false\"\r\n [showRefreshButton]=\"field.showRefreshButton || false\"\r\n [addButtonLabel]=\"field.addButtonLabel || 'Add New'\"\r\n [refreshButtonLabel]=\"field.refreshButtonLabel || 'Refresh'\"\r\n [noOptionsText]=\"field.noOptionsText || 'No options found'\"\r\n [searchPlaceholder]=\"field.searchPlaceholder || 'Search...'\"\r\n (addNew)=\"onAutocompleteAction(field.key, 'add')\"\r\n (refresh)=\"onAutocompleteAction(field.key, 'refresh')\"\r\n ></fui-autocomplete>\r\n @if (field.hint) {\r\n <fui-hint>{{ field.hint }}</fui-hint>\r\n }\r\n <ng-container *ngTemplateOutlet=\"errorsTemplate; context: { $implicit: field }\"></ng-container>\r\n </fui-form-field>\r\n</ng-template>\r\n\r\n<!-- Checkbox Template -->\r\n<ng-template #checkboxTemplate let-field>\r\n <div class=\"fui-dynamic-form__checkbox-wrapper\">\r\n <fui-checkbox [formControl]=\"getControl(field.key)\" [labelPosition]=\"field.labelPosition || 'after'\">\r\n {{ field.label }}\r\n </fui-checkbox>\r\n @if (field.hint) {\r\n <div class=\"fui-dynamic-form__checkbox-hint fui-text-sm\">{{ field.hint }}</div>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<!-- File Template -->\r\n<ng-template #fileTemplate let-field>\r\n <div class=\"fui-dynamic-form__file-field\">\r\n @if (field.label && !field.hideLabel) {\r\n <label class=\"fui-dynamic-form__file-label fui-text-sm\">{{ field.label }}</label>\r\n }\r\n <input\r\n type=\"file\"\r\n class=\"fui-dynamic-form__file-input\"\r\n [accept]=\"field.fileConfig?.accept\"\r\n [multiple]=\"field.fileConfig?.multiple || false\"\r\n [disabled]=\"field.disabled || false\"\r\n (change)=\"onFileChange($event, field.key)\"\r\n />\r\n @if (field.hint) {\r\n <div class=\"fui-dynamic-form__file-hint fui-text-sm\">{{ field.hint }}</div>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<!-- Errors Template -->\r\n<ng-template #errorsTemplate let-field>\r\n @if (field.errors && getControl(field.key)) {\r\n @for (errorEntry of getErrorEntries(field.errors); track errorEntry.key) {\r\n @if (getControl(field.key).hasError(errorEntry.key)) {\r\n <fui-error>{{ errorEntry.value }}</fui-error>\r\n }\r\n }\r\n }\r\n</ng-template>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;;;;;AAkCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0GG;MA4BU,+BAA+B,CAAA;AAC1C;;AAEG;AACM,IAAA,SAAS,GAA2B,KAAK,CAAC,QAAQ,+EAAa;AAExE;;AAEG;AACM,IAAA,MAAM,GAAmC,KAAK,CAAC,QAAQ,4EAAqB;AAErF;;AAEG;IACM,kBAAkB,GAAmD,MAAM,EAAgC;AAEpH;;AAEG;IACM,UAAU,GAA2C,MAAM,EAAwB;AAE5F;;AAEG;IACM,kBAAkB,GAAG,CAAC,EAAW,EAAE,EAAW,KAAc,EAAE,KAAK,EAAE;AAE9E;;;;AAIG;AACH,IAAA,UAAU,CAAC,GAAW,EAAA;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;QACzC,IAAI,CAAC,OAAO,EAAE;;AAEZ,YAAA,OAAO,IAAI,WAAW,EAAE,CAAC;QAC3B;AACA,QAAA,OAAO,OAAsB;IAC/B;AAEA;;;;AAIG;AACH,IAAA,eAAe,CAAC,MAA8B,EAAA;QAC5C,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;IACvE;AAEA;;;;AAIG;AACH,IAAA,aAAa,CAAC,KAA+B,EAAA;QAC3C,QAAQ,KAAK;AACX,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,YAAY;AACrB,YAAA,KAAK,QAAQ;AACX,gBAAA,OAAO,QAAQ;AACjB,YAAA,KAAK,KAAK;AACR,gBAAA,OAAO,UAAU;AACnB,YAAA,KAAK,SAAS;AACZ,gBAAA,OAAO,SAAS;AAClB,YAAA;AACE,gBAAA,OAAO,YAAY;;IAEzB;AAEA;;;;AAIG;AACH,IAAA,iBAAiB,CAAC,OAAmC,EAAA;QACnD,QAAQ,OAAO;AACb,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,YAAY;AACrB,YAAA,KAAK,QAAQ;AACX,gBAAA,OAAO,QAAQ;AACjB,YAAA,KAAK,KAAK;AACR,gBAAA,OAAO,UAAU;AACnB,YAAA,KAAK,SAAS;AACZ,gBAAA,OAAO,eAAe;AACxB,YAAA,KAAK,QAAQ;AACX,gBAAA,OAAO,cAAc;AACvB,YAAA,KAAK,QAAQ;AACX,gBAAA,OAAO,cAAc;AACvB,YAAA;AACE,gBAAA,OAAO,YAAY;;IAEzB;AAEA;;;;AAIG;IACH,oBAAoB,CAAC,QAAgB,EAAE,MAAyB,EAAA;QAC9D,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACpD;AAEA;;;;AAIG;IACH,YAAY,CAAC,KAAY,EAAE,QAAgB,EAAA;AACzC,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,MAA0B;AAC9C,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;;QAGtD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC9C,IAAI,OAAO,EAAE;AACX,YAAA,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC;YAC7B,OAAO,CAAC,aAAa,EAAE;QACzB;IACF;AAEA;;;;AAIG;AACH,IAAA,cAAc,CAAC,KAAuB,EAAA;QACpC,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG;IAC/C;uGA9HW,+BAA+B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA/B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,+BAA+B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,2BAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,UAAA,EAAA,YAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,2BAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECxK5C,4rSA2OA,EAAA,MAAA,EAAA,CAAA,u2MAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,ED1FI,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACZ,mBAAmB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,4EAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,4EAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,sEAAA,EAAA,MAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,aAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACnB,qBAAqB,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,YAAA,EAAA,oBAAA,EAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACrB,iBAAiB,EAAA,QAAA,EAAA,WAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,iBAAiB,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,KAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,gBAAgB,EAAA,QAAA,EAAA,UAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAChB,kBAAkB,EAAA,QAAA,EAAA,aAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,kBAAkB,EAAA,QAAA,EAAA,aAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,iBAAiB,EAAA,QAAA,EAAA,uDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,aAAA,EAAA,UAAA,EAAA,WAAA,EAAA,WAAA,EAAA,SAAA,EAAA,mBAAA,EAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,aAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,aAAA,CAAA,EAAA,OAAA,EAAA,CAAA,aAAA,EAAA,iBAAA,EAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,iBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,wBAAwB,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,aAAA,EAAA,UAAA,EAAA,UAAA,EAAA,eAAA,EAAA,mBAAA,EAAA,gBAAA,EAAA,oBAAA,EAAA,eAAA,EAAA,mBAAA,EAAA,mBAAA,EAAA,aAAA,CAAA,EAAA,OAAA,EAAA,CAAA,aAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,QAAA,EAAA,SAAA,EAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACxB,oBAAoB,wTACpB,gBAAgB,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,QAAA,EAAA,OAAA,EAAA,WAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAUP,+BAA+B,EAAA,UAAA,EAAA,CAAA;kBA3B3C,SAAS;+BACE,2BAA2B,EAAA,UAAA,EACzB,IAAI,EAAA,OAAA,EACP;wBACP,YAAY;wBACZ,mBAAmB;wBACnB,qBAAqB;wBACrB,iBAAiB;wBACjB,iBAAiB;wBACjB,gBAAgB;wBAChB,kBAAkB;wBAClB,kBAAkB;wBAClB,iBAAiB;wBACjB,kBAAkB;wBAClB,kBAAkB;wBAClB,wBAAwB;wBACxB,oBAAoB;wBACpB,gBAAgB;AACjB,qBAAA,EAAA,eAAA,EAGgB,uBAAuB,CAAC,MAAM,iBAChC,iBAAiB,CAAC,IAAI,EAAA,IAAA,EAC/B;AACJ,wBAAA,KAAK,EAAE,2BAA2B;AACnC,qBAAA,EAAA,QAAA,EAAA,4rSAAA,EAAA,MAAA,EAAA,CAAA,u2MAAA,CAAA,EAAA;;;AEtKH;;AAEG;;;;"}
@@ -12,7 +12,7 @@ class FuiEmptyStateComponent {
12
12
  return s === 'sm' ? 'md' : 'lg';
13
13
  }, ...(ngDevMode ? [{ debugName: "iconSize" }] : /* istanbul ignore next */ []));
14
14
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiEmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
15
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiEmptyStateComponent, isStandalone: true, selector: "fui-empty-state", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "status" }, properties: { "class.fui-empty-state--sm": "size() === \"sm\"", "class.fui-empty-state--md": "size() === \"md\"", "class.fui-empty-state--lg": "size() === \"lg\"" }, classAttribute: "fui-empty-state" }, ngImport: i0, template: "<div class=\"fui-empty-state__content\">\n @if (icon()) {\n <div class=\"fui-empty-state__icon\" aria-hidden=\"true\">\n <fui-icon [name]=\"icon()!\" [size]=\"iconSize()\" weight=\"light\" />\n </div>\n }\n @if (title()) {\n <h3 class=\"fui-empty-state__title\">{{ title() }}</h3>\n }\n @if (description()) {\n <p class=\"fui-empty-state__description\">{{ description() }}</p>\n }\n <div class=\"fui-empty-state__actions\">\n <ng-content></ng-content>\n </div>\n</div>\n", styles: [".fui-empty-state{display:flex;align-items:center;justify-content:center;padding:var(--fui-padding-48, 3rem);text-align:center}.fui-empty-state__content{display:flex;flex-direction:column;align-items:center;gap:var(--fui-gap-12, .75rem);max-width:24rem}.fui-empty-state__icon{color:var(--fui-text-disabled);margin-bottom:var(--fui-gap-8, .5rem)}.fui-empty-state__title{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-04);font-weight:var(--fui-font-weight-semibold, 600);color:var(--fui-text-primary);margin:0}.fui-empty-state__description{font-size:var(--fui-font-size-02);color:var(--fui-text-secondary);margin:0;line-height:1.5}.fui-empty-state__actions{margin-top:var(--fui-gap-16, 1rem);display:flex;gap:var(--fui-gap-8, .5rem)}.fui-empty-state--sm{padding:var(--fui-padding-24, 1.5rem)}.fui-empty-state--sm .fui-empty-state__title{font-size:var(--fui-font-size-03)}.fui-empty-state--lg{padding:4.5rem}.fui-empty-state--lg .fui-empty-state__title{font-size:var(--fui-font-size-05)}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
15
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiEmptyStateComponent, isStandalone: true, selector: "fui-empty-state", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "status" }, properties: { "class.fui-empty-state--sm": "size() === \"sm\"", "class.fui-empty-state--md": "size() === \"md\"", "class.fui-empty-state--lg": "size() === \"lg\"" }, classAttribute: "fui-empty-state" }, ngImport: i0, template: "<div class=\"fui-empty-state__content\">\r\n @if (icon()) {\r\n <div class=\"fui-empty-state__icon\" aria-hidden=\"true\">\r\n <fui-icon [name]=\"icon()!\" [size]=\"iconSize()\" weight=\"light\" />\r\n </div>\r\n }\r\n @if (title()) {\r\n <h3 class=\"fui-empty-state__title\">{{ title() }}</h3>\r\n }\r\n @if (description()) {\r\n <p class=\"fui-empty-state__description\">{{ description() }}</p>\r\n }\r\n <div class=\"fui-empty-state__actions\">\r\n <ng-content></ng-content>\r\n </div>\r\n</div>\r\n", styles: [".fui-empty-state{display:flex;align-items:center;justify-content:center;padding:var(--fui-padding-48, 3rem);text-align:center}.fui-empty-state__content{display:flex;flex-direction:column;align-items:center;gap:var(--fui-gap-12, .75rem);max-width:24rem}.fui-empty-state__icon{color:var(--fui-text-disabled);margin-bottom:var(--fui-gap-8, .5rem)}.fui-empty-state__title{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-04);font-weight:var(--fui-font-weight-semibold, 600);color:var(--fui-text-primary);margin:0}.fui-empty-state__description{font-size:var(--fui-font-size-02);color:var(--fui-text-secondary);margin:0;line-height:1.5}.fui-empty-state__actions{margin-top:var(--fui-gap-16, 1rem);display:flex;gap:var(--fui-gap-8, .5rem)}.fui-empty-state--sm{padding:var(--fui-padding-24, 1.5rem)}.fui-empty-state--sm .fui-empty-state__title{font-size:var(--fui-font-size-03)}.fui-empty-state--lg{padding:4.5rem}.fui-empty-state--lg .fui-empty-state__title{font-size:var(--fui-font-size-05)}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
16
16
  }
17
17
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiEmptyStateComponent, decorators: [{
18
18
  type: Component,
@@ -22,7 +22,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
22
22
  '[class.fui-empty-state--md]': 'size() === "md"',
23
23
  '[class.fui-empty-state--lg]': 'size() === "lg"',
24
24
  role: 'status',
25
- }, template: "<div class=\"fui-empty-state__content\">\n @if (icon()) {\n <div class=\"fui-empty-state__icon\" aria-hidden=\"true\">\n <fui-icon [name]=\"icon()!\" [size]=\"iconSize()\" weight=\"light\" />\n </div>\n }\n @if (title()) {\n <h3 class=\"fui-empty-state__title\">{{ title() }}</h3>\n }\n @if (description()) {\n <p class=\"fui-empty-state__description\">{{ description() }}</p>\n }\n <div class=\"fui-empty-state__actions\">\n <ng-content></ng-content>\n </div>\n</div>\n", styles: [".fui-empty-state{display:flex;align-items:center;justify-content:center;padding:var(--fui-padding-48, 3rem);text-align:center}.fui-empty-state__content{display:flex;flex-direction:column;align-items:center;gap:var(--fui-gap-12, .75rem);max-width:24rem}.fui-empty-state__icon{color:var(--fui-text-disabled);margin-bottom:var(--fui-gap-8, .5rem)}.fui-empty-state__title{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-04);font-weight:var(--fui-font-weight-semibold, 600);color:var(--fui-text-primary);margin:0}.fui-empty-state__description{font-size:var(--fui-font-size-02);color:var(--fui-text-secondary);margin:0;line-height:1.5}.fui-empty-state__actions{margin-top:var(--fui-gap-16, 1rem);display:flex;gap:var(--fui-gap-8, .5rem)}.fui-empty-state--sm{padding:var(--fui-padding-24, 1.5rem)}.fui-empty-state--sm .fui-empty-state__title{font-size:var(--fui-font-size-03)}.fui-empty-state--lg{padding:4.5rem}.fui-empty-state--lg .fui-empty-state__title{font-size:var(--fui-font-size-05)}\n"] }]
25
+ }, template: "<div class=\"fui-empty-state__content\">\r\n @if (icon()) {\r\n <div class=\"fui-empty-state__icon\" aria-hidden=\"true\">\r\n <fui-icon [name]=\"icon()!\" [size]=\"iconSize()\" weight=\"light\" />\r\n </div>\r\n }\r\n @if (title()) {\r\n <h3 class=\"fui-empty-state__title\">{{ title() }}</h3>\r\n }\r\n @if (description()) {\r\n <p class=\"fui-empty-state__description\">{{ description() }}</p>\r\n }\r\n <div class=\"fui-empty-state__actions\">\r\n <ng-content></ng-content>\r\n </div>\r\n</div>\r\n", styles: [".fui-empty-state{display:flex;align-items:center;justify-content:center;padding:var(--fui-padding-48, 3rem);text-align:center}.fui-empty-state__content{display:flex;flex-direction:column;align-items:center;gap:var(--fui-gap-12, .75rem);max-width:24rem}.fui-empty-state__icon{color:var(--fui-text-disabled);margin-bottom:var(--fui-gap-8, .5rem)}.fui-empty-state__title{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-04);font-weight:var(--fui-font-weight-semibold, 600);color:var(--fui-text-primary);margin:0}.fui-empty-state__description{font-size:var(--fui-font-size-02);color:var(--fui-text-secondary);margin:0;line-height:1.5}.fui-empty-state__actions{margin-top:var(--fui-gap-16, 1rem);display:flex;gap:var(--fui-gap-8, .5rem)}.fui-empty-state--sm{padding:var(--fui-padding-24, 1.5rem)}.fui-empty-state--sm .fui-empty-state__title{font-size:var(--fui-font-size-03)}.fui-empty-state--lg{padding:4.5rem}.fui-empty-state--lg .fui-empty-state__title{font-size:var(--fui-font-size-05)}\n"] }]
26
26
  }], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
27
27
 
28
28
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"raintonic-formaui-components-empty-state.mjs","sources":["../../../lib/components/empty-state/empty-state.component.ts","../../../lib/components/empty-state/empty-state.component.html","../../../lib/components/empty-state/raintonic-formaui-components-empty-state.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ViewEncapsulation, computed, input } from '@angular/core';\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\n\n@Component({\n selector: 'fui-empty-state',\n standalone: true,\n imports: [FuiIconComponent],\n templateUrl: './empty-state.component.html',\n styleUrls: ['./empty-state.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'fui-empty-state',\n '[class.fui-empty-state--sm]': 'size() === \"sm\"',\n '[class.fui-empty-state--md]': 'size() === \"md\"',\n '[class.fui-empty-state--lg]': 'size() === \"lg\"',\n role: 'status',\n },\n})\nexport class FuiEmptyStateComponent {\n readonly icon = input<string | null>(null);\n readonly title = input<string | null>(null);\n readonly description = input<string | null>(null);\n readonly size = input<'sm' | 'md' | 'lg'>('md');\n\n readonly iconSize = computed(() => {\n const s = this.size();\n return s === 'sm' ? 'md' : 'lg';\n });\n}\n","<div class=\"fui-empty-state__content\">\n @if (icon()) {\n <div class=\"fui-empty-state__icon\" aria-hidden=\"true\">\n <fui-icon [name]=\"icon()!\" [size]=\"iconSize()\" weight=\"light\" />\n </div>\n }\n @if (title()) {\n <h3 class=\"fui-empty-state__title\">{{ title() }}</h3>\n }\n @if (description()) {\n <p class=\"fui-empty-state__description\">{{ description() }}</p>\n }\n <div class=\"fui-empty-state__actions\">\n <ng-content></ng-content>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;MAmBa,sBAAsB,CAAA;AACxB,IAAA,IAAI,GAAG,KAAK,CAAgB,IAAI,2EAAC;AACjC,IAAA,KAAK,GAAG,KAAK,CAAgB,IAAI,4EAAC;AAClC,IAAA,WAAW,GAAG,KAAK,CAAgB,IAAI,kFAAC;AACxC,IAAA,IAAI,GAAG,KAAK,CAAqB,IAAI,2EAAC;AAEtC,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAK;AAChC,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;QACrB,OAAO,CAAC,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI;AACjC,IAAA,CAAC,+EAAC;uGATS,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAtB,sBAAsB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,UAAA,EAAA,EAAA,2BAAA,EAAA,mBAAA,EAAA,2BAAA,EAAA,mBAAA,EAAA,2BAAA,EAAA,mBAAA,EAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECnBnC,ofAgBA,EAAA,MAAA,EAAA,CAAA,k/BAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDVY,gBAAgB,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,QAAA,EAAA,OAAA,EAAA,WAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAaf,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBAhBlC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,EAAA,UAAA,EACf,IAAI,EAAA,OAAA,EACP,CAAC,gBAAgB,CAAC,EAAA,eAAA,EAGV,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,IAAI,EAAA,IAAA,EAC/B;AACJ,wBAAA,KAAK,EAAE,iBAAiB;AACxB,wBAAA,6BAA6B,EAAE,iBAAiB;AAChD,wBAAA,6BAA6B,EAAE,iBAAiB;AAChD,wBAAA,6BAA6B,EAAE,iBAAiB;AAChD,wBAAA,IAAI,EAAE,QAAQ;AACf,qBAAA,EAAA,QAAA,EAAA,ofAAA,EAAA,MAAA,EAAA,CAAA,k/BAAA,CAAA,EAAA;;;AEjBH;;AAEG;;;;"}
1
+ {"version":3,"file":"raintonic-formaui-components-empty-state.mjs","sources":["../../../lib/components/empty-state/empty-state.component.ts","../../../lib/components/empty-state/empty-state.component.html","../../../lib/components/empty-state/raintonic-formaui-components-empty-state.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ViewEncapsulation, computed, input } from '@angular/core';\r\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\r\n\r\n@Component({\r\n selector: 'fui-empty-state',\r\n standalone: true,\r\n imports: [FuiIconComponent],\r\n templateUrl: './empty-state.component.html',\r\n styleUrls: ['./empty-state.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n host: {\r\n class: 'fui-empty-state',\r\n '[class.fui-empty-state--sm]': 'size() === \"sm\"',\r\n '[class.fui-empty-state--md]': 'size() === \"md\"',\r\n '[class.fui-empty-state--lg]': 'size() === \"lg\"',\r\n role: 'status',\r\n },\r\n})\r\nexport class FuiEmptyStateComponent {\r\n readonly icon = input<string | null>(null);\r\n readonly title = input<string | null>(null);\r\n readonly description = input<string | null>(null);\r\n readonly size = input<'sm' | 'md' | 'lg'>('md');\r\n\r\n readonly iconSize = computed(() => {\r\n const s = this.size();\r\n return s === 'sm' ? 'md' : 'lg';\r\n });\r\n}\r\n","<div class=\"fui-empty-state__content\">\r\n @if (icon()) {\r\n <div class=\"fui-empty-state__icon\" aria-hidden=\"true\">\r\n <fui-icon [name]=\"icon()!\" [size]=\"iconSize()\" weight=\"light\" />\r\n </div>\r\n }\r\n @if (title()) {\r\n <h3 class=\"fui-empty-state__title\">{{ title() }}</h3>\r\n }\r\n @if (description()) {\r\n <p class=\"fui-empty-state__description\">{{ description() }}</p>\r\n }\r\n <div class=\"fui-empty-state__actions\">\r\n <ng-content></ng-content>\r\n </div>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;MAmBa,sBAAsB,CAAA;AACxB,IAAA,IAAI,GAAG,KAAK,CAAgB,IAAI,2EAAC;AACjC,IAAA,KAAK,GAAG,KAAK,CAAgB,IAAI,4EAAC;AAClC,IAAA,WAAW,GAAG,KAAK,CAAgB,IAAI,kFAAC;AACxC,IAAA,IAAI,GAAG,KAAK,CAAqB,IAAI,2EAAC;AAEtC,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAK;AAChC,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;QACrB,OAAO,CAAC,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI;AACjC,IAAA,CAAC,+EAAC;uGATS,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAtB,sBAAsB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,UAAA,EAAA,EAAA,2BAAA,EAAA,mBAAA,EAAA,2BAAA,EAAA,mBAAA,EAAA,2BAAA,EAAA,mBAAA,EAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECnBnC,ohBAgBA,EAAA,MAAA,EAAA,CAAA,k/BAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDVY,gBAAgB,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,QAAA,EAAA,OAAA,EAAA,WAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAaf,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBAhBlC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,EAAA,UAAA,EACf,IAAI,EAAA,OAAA,EACP,CAAC,gBAAgB,CAAC,EAAA,eAAA,EAGV,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,IAAI,EAAA,IAAA,EAC/B;AACJ,wBAAA,KAAK,EAAE,iBAAiB;AACxB,wBAAA,6BAA6B,EAAE,iBAAiB;AAChD,wBAAA,6BAA6B,EAAE,iBAAiB;AAChD,wBAAA,6BAA6B,EAAE,iBAAiB;AAChD,wBAAA,IAAI,EAAE,QAAQ;AACf,qBAAA,EAAA,QAAA,EAAA,ohBAAA,EAAA,MAAA,EAAA,CAAA,k/BAAA,CAAA,EAAA;;;AEjBH;;AAEG;;;;"}
@@ -226,7 +226,7 @@ class FuiFileUploadComponent {
226
226
  return URL.createObjectURL(file);
227
227
  }
228
228
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiFileUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
229
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiFileUploadComponent, isStandalone: true, selector: "fui-file-upload", inputs: { accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, maxFiles: { classPropertyName: "maxFiles", publicName: "maxFiles", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showPreview: { classPropertyName: "showPreview", publicName: "showPreview", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filesSelected: "filesSelected", fileRemoved: "fileRemoved", filesDropped: "filesDropped", validationErrors: "validationErrors" }, host: { properties: { "class.fui-file-upload--disabled": "disabled()", "class.fui-file-upload--drag-over": "_isDragOver()", "class.fui-file-upload--has-files": "_files().length > 0" }, classAttribute: "fui-file-upload" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<input\n #fileInput\n type=\"file\"\n class=\"fui-file-upload__native-input\"\n [attr.accept]=\"accept()\"\n [attr.multiple]=\"multiple() ? '' : null\"\n [attr.disabled]=\"disabled() ? '' : null\"\n (change)=\"_onFileInputChange($event)\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n/>\n\n<div\n class=\"fui-file-upload__dropzone\"\n (click)=\"browse()\"\n (dragenter)=\"_onDragEnter($event)\"\n (dragover)=\"_onDragOver($event)\"\n (dragleave)=\"_onDragLeave($event)\"\n (drop)=\"_onDrop($event)\"\n (keydown.enter)=\"browse()\"\n (keydown.space)=\"browse(); $event.preventDefault()\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n role=\"button\"\n [attr.aria-label]=\"'Drop files here or click to browse'\"\n [attr.aria-disabled]=\"disabled()\"\n>\n <fui-icon name=\"upload-simple\" size=\"lg\" class=\"fui-file-upload__icon\"></fui-icon>\n <span class=\"fui-file-upload__text\"> Drag &amp; drop files here or <strong>browse</strong> </span>\n @if (accept()) {\n <span class=\"fui-file-upload__hint\">Accepted: {{ accept() }}</span>\n }\n @if (maxFileSize() > 0) {\n <span class=\"fui-file-upload__hint\">Max size: {{ _formatFileSize(maxFileSize()) }}</span>\n }\n</div>\n\n@if (_files().length > 0) {\n <ul class=\"fui-file-upload__file-list\" role=\"list\">\n @for (fileItem of _files(); track fileItem.name; let i = $index) {\n <li class=\"fui-file-upload__file-item\" [class.fui-file-upload__file-item--error]=\"fileItem.error\">\n @if (showPreview() && fileItem.previewUrl) {\n <img [src]=\"fileItem.previewUrl\" class=\"fui-file-upload__preview\" [alt]=\"fileItem.name\" />\n } @else {\n <fui-icon name=\"file\" size=\"sm\" class=\"fui-file-upload__file-icon\"></fui-icon>\n }\n <div class=\"fui-file-upload__file-info\">\n <span class=\"fui-file-upload__file-name\">{{ fileItem.name }}</span>\n <span class=\"fui-file-upload__file-size\">{{ _formatFileSize(fileItem.size) }}</span>\n @if (fileItem.error) {\n <span class=\"fui-file-upload__file-error\">{{ fileItem.error }}</span>\n }\n </div>\n <button\n type=\"button\"\n class=\"fui-file-upload__remove-btn\"\n (click)=\"removeFile(i); $event.stopPropagation()\"\n [attr.aria-label]=\"'Remove ' + fileItem.name\"\n [disabled]=\"disabled()\"\n >\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\n </button>\n </li>\n }\n </ul>\n}\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}.fui-file-upload{display:block;width:100%}.fui-file-upload__native-input{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.fui-file-upload__dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--fui-gap-8);padding:var(--fui-padding-32, 2rem);border:2px dashed var(--fui-border-color);border-radius:var(--fui-border-radius-md);background-color:var(--fui-surface-bg);cursor:pointer;text-align:center;transition:border-color,background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__dropzone:hover{border-color:var(--fui-primary-60, var(--fui-primary));background-color:var(--fui-primary-10, rgba(124, 58, 237, .04))}.fui-file-upload__dropzone:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-file-upload__icon{color:var(--fui-text-secondary)}.fui-file-upload__text{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);color:var(--fui-text-secondary)}.fui-file-upload__text strong{color:var(--fui-primary);font-weight:var(--fui-font-weight-semibold, 600)}.fui-file-upload__hint{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-text-disabled)}.fui-file-upload__file-list{list-style:none;margin:var(--fui-gap-12, .75rem) 0 0;padding:0;display:flex;flex-direction:column;gap:var(--fui-gap-4)}.fui-file-upload__file-item{display:flex;align-items:center;gap:var(--fui-gap-12, .75rem);padding:var(--fui-padding-8, .5rem) var(--fui-padding-12, .75rem);border:1px solid var(--fui-border-color);border-radius:var(--fui-border-radius-sm);background-color:var(--fui-surface-card, var(--fui-surface-01));transition:border-color,background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__file-item--error{border-color:var(--fui-state-error);background-color:var(--fui-danger-10, rgba(239, 68, 68, .04))}.fui-file-upload__preview{width:48px;height:48px;object-fit:cover;border-radius:var(--fui-border-radius-sm);flex-shrink:0}.fui-file-upload__file-icon{flex-shrink:0;color:var(--fui-text-secondary)}.fui-file-upload__file-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fui-file-upload__file-name{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);font-weight:var(--fui-font-weight-medium, 500);color:var(--fui-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fui-file-upload__file-size{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-text-secondary)}.fui-file-upload__file-error{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-state-error)}.fui-file-upload__remove-btn{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-file-upload__remove-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.5rem;height:1.5rem;border-radius:var(--fui-border-radius-sm);color:var(--fui-text-secondary);opacity:.7;transition:opacity,color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__remove-btn:hover:not(:disabled){opacity:1;color:var(--fui-state-error)}.fui-file-upload__remove-btn:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-file-upload__remove-btn:disabled{opacity:.4;cursor:not-allowed}.fui-file-upload--drag-over .fui-file-upload__dropzone{border-color:var(--fui-primary);border-style:solid;background-color:var(--fui-primary-10, rgba(124, 58, 237, .08))}.fui-file-upload--disabled{opacity:var(--fui-opacity-disabled, .5)}.fui-file-upload--disabled .fui-file-upload__dropzone{cursor:not-allowed;pointer-events:none}.fui-file-upload--disabled .fui-file-upload__remove-btn{cursor:not-allowed}@media(prefers-reduced-motion:reduce){.fui-file-upload__dropzone,.fui-file-upload__file-item,.fui-file-upload__remove-btn{transition:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
229
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiFileUploadComponent, isStandalone: true, selector: "fui-file-upload", inputs: { accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, maxFiles: { classPropertyName: "maxFiles", publicName: "maxFiles", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showPreview: { classPropertyName: "showPreview", publicName: "showPreview", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filesSelected: "filesSelected", fileRemoved: "fileRemoved", filesDropped: "filesDropped", validationErrors: "validationErrors" }, host: { properties: { "class.fui-file-upload--disabled": "disabled()", "class.fui-file-upload--drag-over": "_isDragOver()", "class.fui-file-upload--has-files": "_files().length > 0" }, classAttribute: "fui-file-upload" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<input\r\n #fileInput\r\n type=\"file\"\r\n class=\"fui-file-upload__native-input\"\r\n [attr.accept]=\"accept()\"\r\n [attr.multiple]=\"multiple() ? '' : null\"\r\n [attr.disabled]=\"disabled() ? '' : null\"\r\n (change)=\"_onFileInputChange($event)\"\r\n tabindex=\"-1\"\r\n aria-hidden=\"true\"\r\n/>\r\n\r\n<div\r\n class=\"fui-file-upload__dropzone\"\r\n (click)=\"browse()\"\r\n (dragenter)=\"_onDragEnter($event)\"\r\n (dragover)=\"_onDragOver($event)\"\r\n (dragleave)=\"_onDragLeave($event)\"\r\n (drop)=\"_onDrop($event)\"\r\n (keydown.enter)=\"browse()\"\r\n (keydown.space)=\"browse(); $event.preventDefault()\"\r\n [attr.tabindex]=\"disabled() ? -1 : 0\"\r\n role=\"button\"\r\n [attr.aria-label]=\"'Drop files here or click to browse'\"\r\n [attr.aria-disabled]=\"disabled()\"\r\n>\r\n <fui-icon name=\"upload-simple\" size=\"lg\" class=\"fui-file-upload__icon\"></fui-icon>\r\n <span class=\"fui-file-upload__text\"> Drag &amp; drop files here or <strong>browse</strong> </span>\r\n @if (accept()) {\r\n <span class=\"fui-file-upload__hint\">Accepted: {{ accept() }}</span>\r\n }\r\n @if (maxFileSize() > 0) {\r\n <span class=\"fui-file-upload__hint\">Max size: {{ _formatFileSize(maxFileSize()) }}</span>\r\n }\r\n</div>\r\n\r\n@if (_files().length > 0) {\r\n <ul class=\"fui-file-upload__file-list\" role=\"list\">\r\n @for (fileItem of _files(); track fileItem.name; let i = $index) {\r\n <li class=\"fui-file-upload__file-item\" [class.fui-file-upload__file-item--error]=\"fileItem.error\">\r\n @if (showPreview() && fileItem.previewUrl) {\r\n <img [src]=\"fileItem.previewUrl\" class=\"fui-file-upload__preview\" [alt]=\"fileItem.name\" />\r\n } @else {\r\n <fui-icon name=\"file\" size=\"sm\" class=\"fui-file-upload__file-icon\"></fui-icon>\r\n }\r\n <div class=\"fui-file-upload__file-info\">\r\n <span class=\"fui-file-upload__file-name\">{{ fileItem.name }}</span>\r\n <span class=\"fui-file-upload__file-size\">{{ _formatFileSize(fileItem.size) }}</span>\r\n @if (fileItem.error) {\r\n <span class=\"fui-file-upload__file-error\">{{ fileItem.error }}</span>\r\n }\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"fui-file-upload__remove-btn\"\r\n (click)=\"removeFile(i); $event.stopPropagation()\"\r\n [attr.aria-label]=\"'Remove ' + fileItem.name\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n}\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}.fui-file-upload{display:block;width:100%}.fui-file-upload__native-input{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.fui-file-upload__dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--fui-gap-8);padding:var(--fui-padding-32, 2rem);border:2px dashed var(--fui-border-color);border-radius:var(--fui-border-radius-md);background-color:var(--fui-surface-bg);cursor:pointer;text-align:center;transition:border-color,background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__dropzone:hover{border-color:var(--fui-primary-60, var(--fui-primary));background-color:var(--fui-primary-10, rgba(124, 58, 237, .04))}.fui-file-upload__dropzone:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-file-upload__icon{color:var(--fui-text-secondary)}.fui-file-upload__text{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);color:var(--fui-text-secondary)}.fui-file-upload__text strong{color:var(--fui-primary);font-weight:var(--fui-font-weight-semibold, 600)}.fui-file-upload__hint{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-text-disabled)}.fui-file-upload__file-list{list-style:none;margin:var(--fui-gap-12, .75rem) 0 0;padding:0;display:flex;flex-direction:column;gap:var(--fui-gap-4)}.fui-file-upload__file-item{display:flex;align-items:center;gap:var(--fui-gap-12, .75rem);padding:var(--fui-padding-8, .5rem) var(--fui-padding-12, .75rem);border:1px solid var(--fui-border-color);border-radius:var(--fui-border-radius-sm);background-color:var(--fui-surface-card, var(--fui-surface-01));transition:border-color,background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__file-item--error{border-color:var(--fui-state-error);background-color:var(--fui-danger-10, rgba(239, 68, 68, .04))}.fui-file-upload__preview{width:48px;height:48px;object-fit:cover;border-radius:var(--fui-border-radius-sm);flex-shrink:0}.fui-file-upload__file-icon{flex-shrink:0;color:var(--fui-text-secondary)}.fui-file-upload__file-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fui-file-upload__file-name{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);font-weight:var(--fui-font-weight-medium, 500);color:var(--fui-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fui-file-upload__file-size{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-text-secondary)}.fui-file-upload__file-error{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-state-error)}.fui-file-upload__remove-btn{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-file-upload__remove-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.5rem;height:1.5rem;border-radius:var(--fui-border-radius-sm);color:var(--fui-text-secondary);opacity:.7;transition:opacity,color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__remove-btn:hover:not(:disabled){opacity:1;color:var(--fui-state-error)}.fui-file-upload__remove-btn:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-file-upload__remove-btn:disabled{opacity:.4;cursor:not-allowed}.fui-file-upload--drag-over .fui-file-upload__dropzone{border-color:var(--fui-primary);border-style:solid;background-color:var(--fui-primary-10, rgba(124, 58, 237, .08))}.fui-file-upload--disabled{opacity:var(--fui-opacity-disabled, .5)}.fui-file-upload--disabled .fui-file-upload__dropzone{cursor:not-allowed;pointer-events:none}.fui-file-upload--disabled .fui-file-upload__remove-btn{cursor:not-allowed}@media(prefers-reduced-motion:reduce){.fui-file-upload__dropzone,.fui-file-upload__file-item,.fui-file-upload__remove-btn{transition:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
230
230
  }
231
231
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiFileUploadComponent, decorators: [{
232
232
  type: Component,
@@ -235,7 +235,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
235
235
  '[class.fui-file-upload--disabled]': 'disabled()',
236
236
  '[class.fui-file-upload--drag-over]': '_isDragOver()',
237
237
  '[class.fui-file-upload--has-files]': '_files().length > 0',
238
- }, template: "<input\n #fileInput\n type=\"file\"\n class=\"fui-file-upload__native-input\"\n [attr.accept]=\"accept()\"\n [attr.multiple]=\"multiple() ? '' : null\"\n [attr.disabled]=\"disabled() ? '' : null\"\n (change)=\"_onFileInputChange($event)\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n/>\n\n<div\n class=\"fui-file-upload__dropzone\"\n (click)=\"browse()\"\n (dragenter)=\"_onDragEnter($event)\"\n (dragover)=\"_onDragOver($event)\"\n (dragleave)=\"_onDragLeave($event)\"\n (drop)=\"_onDrop($event)\"\n (keydown.enter)=\"browse()\"\n (keydown.space)=\"browse(); $event.preventDefault()\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n role=\"button\"\n [attr.aria-label]=\"'Drop files here or click to browse'\"\n [attr.aria-disabled]=\"disabled()\"\n>\n <fui-icon name=\"upload-simple\" size=\"lg\" class=\"fui-file-upload__icon\"></fui-icon>\n <span class=\"fui-file-upload__text\"> Drag &amp; drop files here or <strong>browse</strong> </span>\n @if (accept()) {\n <span class=\"fui-file-upload__hint\">Accepted: {{ accept() }}</span>\n }\n @if (maxFileSize() > 0) {\n <span class=\"fui-file-upload__hint\">Max size: {{ _formatFileSize(maxFileSize()) }}</span>\n }\n</div>\n\n@if (_files().length > 0) {\n <ul class=\"fui-file-upload__file-list\" role=\"list\">\n @for (fileItem of _files(); track fileItem.name; let i = $index) {\n <li class=\"fui-file-upload__file-item\" [class.fui-file-upload__file-item--error]=\"fileItem.error\">\n @if (showPreview() && fileItem.previewUrl) {\n <img [src]=\"fileItem.previewUrl\" class=\"fui-file-upload__preview\" [alt]=\"fileItem.name\" />\n } @else {\n <fui-icon name=\"file\" size=\"sm\" class=\"fui-file-upload__file-icon\"></fui-icon>\n }\n <div class=\"fui-file-upload__file-info\">\n <span class=\"fui-file-upload__file-name\">{{ fileItem.name }}</span>\n <span class=\"fui-file-upload__file-size\">{{ _formatFileSize(fileItem.size) }}</span>\n @if (fileItem.error) {\n <span class=\"fui-file-upload__file-error\">{{ fileItem.error }}</span>\n }\n </div>\n <button\n type=\"button\"\n class=\"fui-file-upload__remove-btn\"\n (click)=\"removeFile(i); $event.stopPropagation()\"\n [attr.aria-label]=\"'Remove ' + fileItem.name\"\n [disabled]=\"disabled()\"\n >\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\n </button>\n </li>\n }\n </ul>\n}\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}.fui-file-upload{display:block;width:100%}.fui-file-upload__native-input{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.fui-file-upload__dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--fui-gap-8);padding:var(--fui-padding-32, 2rem);border:2px dashed var(--fui-border-color);border-radius:var(--fui-border-radius-md);background-color:var(--fui-surface-bg);cursor:pointer;text-align:center;transition:border-color,background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__dropzone:hover{border-color:var(--fui-primary-60, var(--fui-primary));background-color:var(--fui-primary-10, rgba(124, 58, 237, .04))}.fui-file-upload__dropzone:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-file-upload__icon{color:var(--fui-text-secondary)}.fui-file-upload__text{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);color:var(--fui-text-secondary)}.fui-file-upload__text strong{color:var(--fui-primary);font-weight:var(--fui-font-weight-semibold, 600)}.fui-file-upload__hint{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-text-disabled)}.fui-file-upload__file-list{list-style:none;margin:var(--fui-gap-12, .75rem) 0 0;padding:0;display:flex;flex-direction:column;gap:var(--fui-gap-4)}.fui-file-upload__file-item{display:flex;align-items:center;gap:var(--fui-gap-12, .75rem);padding:var(--fui-padding-8, .5rem) var(--fui-padding-12, .75rem);border:1px solid var(--fui-border-color);border-radius:var(--fui-border-radius-sm);background-color:var(--fui-surface-card, var(--fui-surface-01));transition:border-color,background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__file-item--error{border-color:var(--fui-state-error);background-color:var(--fui-danger-10, rgba(239, 68, 68, .04))}.fui-file-upload__preview{width:48px;height:48px;object-fit:cover;border-radius:var(--fui-border-radius-sm);flex-shrink:0}.fui-file-upload__file-icon{flex-shrink:0;color:var(--fui-text-secondary)}.fui-file-upload__file-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fui-file-upload__file-name{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);font-weight:var(--fui-font-weight-medium, 500);color:var(--fui-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fui-file-upload__file-size{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-text-secondary)}.fui-file-upload__file-error{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-state-error)}.fui-file-upload__remove-btn{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-file-upload__remove-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.5rem;height:1.5rem;border-radius:var(--fui-border-radius-sm);color:var(--fui-text-secondary);opacity:.7;transition:opacity,color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__remove-btn:hover:not(:disabled){opacity:1;color:var(--fui-state-error)}.fui-file-upload__remove-btn:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-file-upload__remove-btn:disabled{opacity:.4;cursor:not-allowed}.fui-file-upload--drag-over .fui-file-upload__dropzone{border-color:var(--fui-primary);border-style:solid;background-color:var(--fui-primary-10, rgba(124, 58, 237, .08))}.fui-file-upload--disabled{opacity:var(--fui-opacity-disabled, .5)}.fui-file-upload--disabled .fui-file-upload__dropzone{cursor:not-allowed;pointer-events:none}.fui-file-upload--disabled .fui-file-upload__remove-btn{cursor:not-allowed}@media(prefers-reduced-motion:reduce){.fui-file-upload__dropzone,.fui-file-upload__file-item,.fui-file-upload__remove-btn{transition:none}}\n"] }]
238
+ }, template: "<input\r\n #fileInput\r\n type=\"file\"\r\n class=\"fui-file-upload__native-input\"\r\n [attr.accept]=\"accept()\"\r\n [attr.multiple]=\"multiple() ? '' : null\"\r\n [attr.disabled]=\"disabled() ? '' : null\"\r\n (change)=\"_onFileInputChange($event)\"\r\n tabindex=\"-1\"\r\n aria-hidden=\"true\"\r\n/>\r\n\r\n<div\r\n class=\"fui-file-upload__dropzone\"\r\n (click)=\"browse()\"\r\n (dragenter)=\"_onDragEnter($event)\"\r\n (dragover)=\"_onDragOver($event)\"\r\n (dragleave)=\"_onDragLeave($event)\"\r\n (drop)=\"_onDrop($event)\"\r\n (keydown.enter)=\"browse()\"\r\n (keydown.space)=\"browse(); $event.preventDefault()\"\r\n [attr.tabindex]=\"disabled() ? -1 : 0\"\r\n role=\"button\"\r\n [attr.aria-label]=\"'Drop files here or click to browse'\"\r\n [attr.aria-disabled]=\"disabled()\"\r\n>\r\n <fui-icon name=\"upload-simple\" size=\"lg\" class=\"fui-file-upload__icon\"></fui-icon>\r\n <span class=\"fui-file-upload__text\"> Drag &amp; drop files here or <strong>browse</strong> </span>\r\n @if (accept()) {\r\n <span class=\"fui-file-upload__hint\">Accepted: {{ accept() }}</span>\r\n }\r\n @if (maxFileSize() > 0) {\r\n <span class=\"fui-file-upload__hint\">Max size: {{ _formatFileSize(maxFileSize()) }}</span>\r\n }\r\n</div>\r\n\r\n@if (_files().length > 0) {\r\n <ul class=\"fui-file-upload__file-list\" role=\"list\">\r\n @for (fileItem of _files(); track fileItem.name; let i = $index) {\r\n <li class=\"fui-file-upload__file-item\" [class.fui-file-upload__file-item--error]=\"fileItem.error\">\r\n @if (showPreview() && fileItem.previewUrl) {\r\n <img [src]=\"fileItem.previewUrl\" class=\"fui-file-upload__preview\" [alt]=\"fileItem.name\" />\r\n } @else {\r\n <fui-icon name=\"file\" size=\"sm\" class=\"fui-file-upload__file-icon\"></fui-icon>\r\n }\r\n <div class=\"fui-file-upload__file-info\">\r\n <span class=\"fui-file-upload__file-name\">{{ fileItem.name }}</span>\r\n <span class=\"fui-file-upload__file-size\">{{ _formatFileSize(fileItem.size) }}</span>\r\n @if (fileItem.error) {\r\n <span class=\"fui-file-upload__file-error\">{{ fileItem.error }}</span>\r\n }\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"fui-file-upload__remove-btn\"\r\n (click)=\"removeFile(i); $event.stopPropagation()\"\r\n [attr.aria-label]=\"'Remove ' + fileItem.name\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n}\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}.fui-file-upload{display:block;width:100%}.fui-file-upload__native-input{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.fui-file-upload__dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--fui-gap-8);padding:var(--fui-padding-32, 2rem);border:2px dashed var(--fui-border-color);border-radius:var(--fui-border-radius-md);background-color:var(--fui-surface-bg);cursor:pointer;text-align:center;transition:border-color,background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__dropzone:hover{border-color:var(--fui-primary-60, var(--fui-primary));background-color:var(--fui-primary-10, rgba(124, 58, 237, .04))}.fui-file-upload__dropzone:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-file-upload__icon{color:var(--fui-text-secondary)}.fui-file-upload__text{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);color:var(--fui-text-secondary)}.fui-file-upload__text strong{color:var(--fui-primary);font-weight:var(--fui-font-weight-semibold, 600)}.fui-file-upload__hint{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-text-disabled)}.fui-file-upload__file-list{list-style:none;margin:var(--fui-gap-12, .75rem) 0 0;padding:0;display:flex;flex-direction:column;gap:var(--fui-gap-4)}.fui-file-upload__file-item{display:flex;align-items:center;gap:var(--fui-gap-12, .75rem);padding:var(--fui-padding-8, .5rem) var(--fui-padding-12, .75rem);border:1px solid var(--fui-border-color);border-radius:var(--fui-border-radius-sm);background-color:var(--fui-surface-card, var(--fui-surface-01));transition:border-color,background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__file-item--error{border-color:var(--fui-state-error);background-color:var(--fui-danger-10, rgba(239, 68, 68, .04))}.fui-file-upload__preview{width:48px;height:48px;object-fit:cover;border-radius:var(--fui-border-radius-sm);flex-shrink:0}.fui-file-upload__file-icon{flex-shrink:0;color:var(--fui-text-secondary)}.fui-file-upload__file-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fui-file-upload__file-name{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);font-weight:var(--fui-font-weight-medium, 500);color:var(--fui-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fui-file-upload__file-size{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-text-secondary)}.fui-file-upload__file-error{font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-01);color:var(--fui-state-error)}.fui-file-upload__remove-btn{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-file-upload__remove-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.5rem;height:1.5rem;border-radius:var(--fui-border-radius-sm);color:var(--fui-text-secondary);opacity:.7;transition:opacity,color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-file-upload__remove-btn:hover:not(:disabled){opacity:1;color:var(--fui-state-error)}.fui-file-upload__remove-btn:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-file-upload__remove-btn:disabled{opacity:.4;cursor:not-allowed}.fui-file-upload--drag-over .fui-file-upload__dropzone{border-color:var(--fui-primary);border-style:solid;background-color:var(--fui-primary-10, rgba(124, 58, 237, .08))}.fui-file-upload--disabled{opacity:var(--fui-opacity-disabled, .5)}.fui-file-upload--disabled .fui-file-upload__dropzone{cursor:not-allowed;pointer-events:none}.fui-file-upload--disabled .fui-file-upload__remove-btn{cursor:not-allowed}@media(prefers-reduced-motion:reduce){.fui-file-upload__dropzone,.fui-file-upload__file-item,.fui-file-upload__remove-btn{transition:none}}\n"] }]
239
239
  }], propDecorators: { accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], maxFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFiles", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showPreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPreview", required: false }] }], filesSelected: [{ type: i0.Output, args: ["filesSelected"] }], fileRemoved: [{ type: i0.Output, args: ["fileRemoved"] }], filesDropped: [{ type: i0.Output, args: ["filesDropped"] }], validationErrors: [{ type: i0.Output, args: ["validationErrors"] }], fileInput: [{ type: i0.ViewChild, args: ['fileInput', { isSignal: true }] }] } });
240
240
 
241
241
  /**