@prolibu-suite/cobalt-form 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +106 -0
  2. package/dist/cjs/co-form-wizard.cjs.entry.js +307 -0
  3. package/dist/cjs/co-form.cjs.entry.js +2 -1
  4. package/dist/cjs/cobalt-form.cjs.js +2 -2
  5. package/dist/cjs/index-CLL7Ervz.js +8155 -0
  6. package/dist/cjs/{index-8raPCV5a.js → index-Mpsm3UE7.js} +8 -0
  7. package/dist/cjs/index.cjs.js +151 -8869
  8. package/dist/cjs/loader.cjs.js +2 -2
  9. package/dist/cobalt-form/cobalt-form.esm.js +1 -1
  10. package/dist/cobalt-form/index.esm.js +1 -7
  11. package/dist/cobalt-form/p-2168be6b.entry.js +1 -0
  12. package/dist/cobalt-form/p-7b8f67bc.entry.js +1 -0
  13. package/dist/cobalt-form/p-C1670_IO.js +2 -0
  14. package/dist/cobalt-form/p-CPE0t-C2.js +7 -0
  15. package/dist/collection/collection-manifest.json +2 -1
  16. package/dist/collection/components/co-form/co-form.css +167 -1
  17. package/dist/collection/components/co-form/co-form.js +278 -9
  18. package/dist/collection/components/co-form-wizard/co-form-wizard.css +363 -0
  19. package/dist/collection/components/co-form-wizard/co-form-wizard.js +502 -0
  20. package/dist/components/co-form-wizard.d.ts +11 -0
  21. package/dist/components/co-form-wizard.js +1 -0
  22. package/dist/components/index.js +5 -5
  23. package/dist/esm/co-form-wizard.entry.js +305 -0
  24. package/dist/esm/co-form.entry.js +2 -1
  25. package/dist/esm/cobalt-form.js +3 -3
  26. package/dist/esm/{index-X0Keifac.js → index-C1670_IO.js} +8 -1
  27. package/dist/esm/index-CPE0t-C2.js +8144 -0
  28. package/dist/esm/index.js +147 -8865
  29. package/dist/esm/loader.js +3 -3
  30. package/dist/types/components/co-form/co-form.d.ts +53 -1
  31. package/dist/types/components/co-form-wizard/co-form-wizard.d.ts +118 -0
  32. package/dist/types/components.d.ts +184 -2
  33. package/package.json +7 -4
  34. package/dist/cobalt-form/p-X0Keifac.js +0 -2
  35. package/dist/cobalt-form/p-ef70e055.entry.js +0 -1
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # @prolibu-suite/cobalt-form
2
+
3
+ `<co-form>` — Web Component schema-driven con validación AJV. Pegás un schema, obtenés un formulario completo. CDN entry point del **Cobalt Design System**.
4
+
5
+ > Schema → formulario. Sin loops, sin componentes, sin framework.
6
+
7
+ ## Instalación
8
+
9
+ ```bash
10
+ pnpm add @prolibu-suite/cobalt-form @prolibu-suite/cobalt-core @prolibu-suite/cobalt-tokens
11
+ ```
12
+
13
+ ## Uso
14
+
15
+ ```js
16
+ import { defineCustomElements as defineCoreElements } from '@prolibu-suite/cobalt-core/loader';
17
+ import { defineCustomElements as defineFormElements } from '@prolibu-suite/cobalt-form/loader';
18
+
19
+ defineCoreElements(window);
20
+ defineFormElements(window);
21
+ ```
22
+
23
+ ```html
24
+ <co-form
25
+ locale="es"
26
+ layout="grid"
27
+ schema='{
28
+ "email": { "type": "String", "required": true, "format": "email" },
29
+ "password": { "type": "String", "required": true, "minLength": 8 },
30
+ "newsletter": { "type": "Boolean", "label": "Suscribirme", "default": true }
31
+ }'
32
+ ></co-form>
33
+
34
+ <script>
35
+ const form = document.querySelector('co-form');
36
+ form.addEventListener('coSubmit', (e) => {
37
+ console.log('values:', e.detail.values);
38
+ });
39
+ </script>
40
+ ```
41
+
42
+ ## Sin build · vía CDN
43
+
44
+ ```html
45
+ <!DOCTYPE html>
46
+ <html>
47
+ <head>
48
+ <link rel="stylesheet" href="https://unpkg.com/@prolibu-suite/cobalt-tokens@0.1.1/build/css/tokens.css">
49
+ <script type="module" src="https://unpkg.com/@prolibu-suite/cobalt-core@0.1.1/dist/cobalt/cobalt.esm.js"></script>
50
+ <script type="module" src="https://unpkg.com/@prolibu-suite/cobalt-form@0.1.1/dist/cobalt-form/cobalt-form.esm.js"></script>
51
+ </head>
52
+ <body>
53
+ <co-form locale="es" schema='{ "email": { "type": "String", "required": true, "format": "email" } }'></co-form>
54
+ </body>
55
+ </html>
56
+ ```
57
+
58
+ ## Eventos
59
+
60
+ | Evento | Detail | Cuándo |
61
+ |---|---|---|
62
+ | `coSubmit` | `{ values, isValid }` | Submit válido |
63
+ | `coChange` | `{ name, value, values }` | Cambio de cualquier campo |
64
+ | `coValidate` | `{ errors, isValid }` | Validación dispara |
65
+
66
+ ## Métodos públicos
67
+
68
+ ```js
69
+ await form.setValue('email', 'nuevo@bar.com');
70
+ await form.getValue('email');
71
+ await form.touch('email');
72
+ await form.submit();
73
+ ```
74
+
75
+ ## Slots para custom fields
76
+
77
+ ```html
78
+ <co-form schema='{ "email": { "type": "String", "required": true, "format": "email" } }'>
79
+ <!-- Reemplazá el render del campo "email" con HTML propio -->
80
+ <div slot="field:email">
81
+ <input type="email" id="myEmail">
82
+ </div>
83
+ </co-form>
84
+ ```
85
+
86
+ ## Demos en vivo
87
+
88
+ 5 niveles de personalización, todos sirviendo `<co-form>` desde unpkg:
89
+
90
+ - [Default](https://dev10.prolibu.com/ui/static/cobalt-form-demo/01-default.html)
91
+ - [Tokens theming](https://dev10.prolibu.com/ui/static/cobalt-form-demo/02-tokens.html)
92
+ - [CSS local](https://dev10.prolibu.com/ui/static/cobalt-form-demo/03-css.html)
93
+ - [Slot override](https://dev10.prolibu.com/ui/static/cobalt-form-demo/04-slot.html)
94
+ - [Renderer propio](https://dev10.prolibu.com/ui/static/cobalt-form-demo/05-custom.html)
95
+
96
+ ## Si usás Vue 3
97
+
98
+ Mirá [`@prolibu-suite/cobalt-form-vue`](https://www.npmjs.com/package/@prolibu-suite/cobalt-form-vue) — composable `useForm()` + `CoFormRenderer.vue`.
99
+
100
+ ## Documentación
101
+
102
+ → [cobalt-docs/formularios](https://dev10.prolibu.com/ui/static/cobalt-docs/formularios/introduccion/) — schemas, validación, ref fields, ejemplos.
103
+
104
+ ## License
105
+
106
+ MIT
@@ -0,0 +1,307 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-Mpsm3UE7.js');
4
+ var index$1 = require('./index-CLL7Ervz.js');
5
+
6
+ const coFormWizardCss = () => `:host{display:block;font-family:var(--co-font-family-primary, sans-serif)}.co-form-wizard{max-width:720px;margin:0 auto;padding:var(--co-spacing-2xl, 24px);display:flex;flex-direction:column;gap:var(--co-spacing-lg, 16px)}.co-form-wizard[data-has-bg]{padding:var(--co-spacing-3xl, 32px) var(--co-spacing-2xl, 24px);background-repeat:no-repeat}.co-form-wizard__title-block{background:var(--co-form-header-bg, var(--co-semantic-surface-page, #fff));border:1px solid var(--co-semantic-border-default, rgba(17, 24, 39, 0.08));border-radius:var(--co-border-radius-lg, 16px);padding:var(--co-spacing-2xl, 24px) var(--co-spacing-3xl, 28px);box-shadow:0 1px 2px rgba(0, 0, 0, 0.04);min-height:var(--co-form-header-height, auto)}.co-form-wizard[data-hide-header] .co-form-wizard__title-block{display:none}.co-form-wizard[data-density="compact"] .co-form-wizard{gap:var(--co-spacing-sm, 8px)}.co-form-wizard[data-density="compact"] .co-form-wizard__title-block{padding:var(--co-spacing-lg, 16px) var(--co-spacing-xl, 20px)}.co-form-wizard[data-density="compact"] .co-form-wizard__page-head,.co-form-wizard[data-density="compact"] .co-form-wizard__nav{padding-top:var(--co-spacing-sm, 8px);padding-bottom:var(--co-spacing-sm, 8px)}.co-form-wizard__title{margin:0;font-size:24px;font-weight:700;letter-spacing:-0.02em;line-height:1.2;color:var(--co-semantic-text-default, #111827)}.co-form-wizard__title-desc{margin:6px 0 0;font-size:var(--co-font-size-14, 14px);color:var(--co-semantic-text-secondary, #6b7280)}.co-form-wizard__stepper{display:flex;align-items:center;gap:var(--co-spacing-sm, 8px);list-style:none;padding:0;margin:0;flex-wrap:wrap}.co-form-wizard__step{display:flex;align-items:center;color:var(--co-semantic-text-secondary, #6b7280);font-size:var(--co-font-size-12, 12px)}.co-form-wizard__step-btn{display:inline-flex;align-items:center;gap:var(--co-spacing-xs, 4px);padding:4px 6px;border:0;background:transparent;border-radius:var(--co-border-radius-xxs, 4px);font:inherit;color:inherit;cursor:pointer}.co-form-wizard__step-btn:hover{background:var(--co-semantic-surface-hover, #f3f4f6);color:var(--co-semantic-text-default, #111827)}.co-form-wizard__step-num{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:var(--co-border-radius-full, 9999px);background:var(--co-semantic-surface-hover, #f3f4f6);font-weight:600}.co-form-wizard__step.is-active .co-form-wizard__step-num{background:var(--co-color-primary-azul, #2563eb);color:white}.co-form-wizard__step.is-done .co-form-wizard__step-num{background:var(--co-color-primary-verde, #02a270);color:white}.co-form-wizard__step.is-active{color:var(--co-semantic-text-default, #111827);font-weight:600}.co-form-wizard__page-card{background:var(--co-semantic-surface-page, #fff);border:1px solid var(--co-semantic-border-default, rgba(17, 24, 39, 0.08));border-radius:var(--co-border-radius-lg, 16px);box-shadow:0 1px 2px rgba(0, 0, 0, 0.04);overflow:hidden;display:flex;flex-direction:column}.co-form-wizard__page-head{padding:var(--co-spacing-xl, 20px) var(--co-spacing-2xl, 24px);border-bottom:1px solid var(--co-semantic-border-default, rgba(17, 24, 39, 0.08));background:var(--co-semantic-surface-hover, #f9fafb)}.co-form-wizard__page-pill{display:inline-flex;font-size:10px;font-weight:700;letter-spacing:0.08em;color:var(--co-color-primary-azul, #2563eb);background:color-mix(in srgb, var(--co-color-primary-azul) 10%, transparent);padding:3px 8px;border-radius:var(--co-border-radius-full, 9999px);margin-bottom:6px}.co-form-wizard__page-title{margin:0;font-size:var(--co-font-size-18, 18px);font-weight:600;line-height:1.3;letter-spacing:-0.01em;color:var(--co-semantic-text-default, #111827)}.co-form-wizard__page-desc{margin:4px 0 0;font-size:var(--co-font-size-13, 13px);color:var(--co-semantic-text-secondary, #6b7280)}.co-form-wizard__page-card>co-form{display:block;padding:var(--co-spacing-xl, 20px) var(--co-spacing-2xl, 24px)}.co-form-wizard__nav{display:flex;justify-content:space-between;gap:var(--co-spacing-sm, 8px);padding:var(--co-spacing-md, 12px) var(--co-spacing-2xl, 24px);border-top:1px solid var(--co-semantic-border-default, rgba(17, 24, 39, 0.08));background:var(--co-semantic-surface-hover, #f9fafb)}.co-form-wizard__empty{padding:var(--co-spacing-lg, 16px);text-align:center;color:var(--co-semantic-text-secondary, #6b7280)}.co-form-wizard__score{text-align:center;padding:var(--co-spacing-2xl, 24px);background:var(--co-semantic-surface-page, #fff);border:1px solid var(--co-semantic-border-default, rgba(17, 24, 39, 0.08));border-radius:var(--co-border-radius-lg, 16px);box-shadow:0 1px 2px rgba(0, 0, 0, 0.04)}.co-form-wizard__score-title{margin:0;font-size:var(--co-font-size-18, 18px)}.co-form-wizard__score-num{font-size:48px;font-weight:600;color:var(--co-color-primary-azul, #2563eb);margin:var(--co-spacing-md, 12px) 0}.co-form-wizard__score-pct{font-size:var(--co-font-size-16, 16px);color:var(--co-semantic-text-secondary, #6b7280);margin-left:var(--co-spacing-sm, 8px)}.co-form-wizard__score-pass{display:inline-block;padding:var(--co-spacing-xs, 4px) var(--co-spacing-md, 12px);border-radius:var(--co-border-radius-full, 9999px);font-weight:600;margin-bottom:var(--co-spacing-md, 12px)}.co-form-wizard__score-pass.is-pass{background:var(--co-color-status-success, #0a7724);color:white}.co-form-wizard__score-pass.is-fail{background:var(--co-color-status-error, #aa2e1b);color:white}.co-form-wizard__score-feedback{text-align:left;list-style:disc;padding-left:var(--co-spacing-2xl, 24px);color:var(--co-semantic-text-default, #111827)}.co-form-wizard[data-has-bg] .co-form-wizard__title-block,.co-form-wizard[data-has-bg] .co-form-wizard__page-card,.co-form-wizard[data-has-bg] .co-form-wizard__score{border:0;box-shadow:0 4px 24px rgba(0, 0, 0, 0.08)}.co-form-wizard[data-theme="dark"]{--co-semantic-surface-page:#1a1f2b;--co-semantic-surface-secondary:#1a1f2b;--co-semantic-surface-primary:#ffffff;--co-semantic-surface-muted:#2a3142;--co-semantic-surface-hover:rgba(255, 255, 255, 0.06);--co-semantic-surface-disabled:rgba(255, 255, 255, 0.04);--co-semantic-text-default:#f9fafb;--co-semantic-text-secondary:#9ca3af;--co-semantic-text-muted:#6b7280;--co-semantic-text-disabled:#4b5563;--co-semantic-border-default:rgba(255, 255, 255, 0.12);--co-semantic-border-subtle:rgba(255, 255, 255, 0.14);--co-semantic-border-strong:rgba(255, 255, 255, 0.25);--co-semantic-border-focus:rgba(255, 255, 255, 0.25);--co-semantic-border-focus-ring:rgba(255, 255, 255, 0.1);color:#f9fafb}.co-form-wizard[data-theme="dark"] .co-form-wizard__page-card,.co-form-wizard[data-theme="dark"] .co-form-wizard__score{background:var(--co-semantic-surface-page);border-color:var(--co-semantic-border-default);color:#f9fafb}.co-form-wizard[data-theme="dark"] .co-form-wizard__title-block{background:var(--co-form-header-bg, var(--co-semantic-surface-page));border-color:var(--co-semantic-border-default);color:#f9fafb}.co-form-wizard[data-theme="dark"] .co-form-wizard__title,.co-form-wizard[data-theme="dark"] .co-form-wizard__page-title{color:#f9fafb}.co-form-wizard[data-theme="dark"] .co-form-wizard__title-desc,.co-form-wizard[data-theme="dark"] .co-form-wizard__page-desc{color:#9ca3af}.co-form-wizard[data-theme="dark"] .co-form-wizard__page-head,.co-form-wizard[data-theme="dark"] .co-form-wizard__nav{background:rgba(255, 255, 255, 0.03);border-color:var(--co-semantic-border-default)}.co-form-wizard[data-theme="dark"] .co-form-wizard__step-num{background:rgba(255, 255, 255, 0.1);color:#f9fafb}.co-form-wizard[data-theme="dark"][data-has-bg] .co-form-wizard__title-block,.co-form-wizard[data-theme="dark"][data-has-bg] .co-form-wizard__page-card,.co-form-wizard[data-theme="dark"][data-has-bg] .co-form-wizard__score{box-shadow:0 4px 24px rgba(0, 0, 0, 0.4)}.co-form-wizard[data-appearance="flat"] .co-form-wizard__title-block,.co-form-wizard[data-appearance="flat"] .co-form-wizard__page-card{background:transparent !important;border:0 !important;box-shadow:none !important;padding:0 !important}.co-form-wizard[data-appearance="flat"] .co-form-wizard__page-head{background:transparent !important;border-bottom:0 !important;padding:0 0 var(--co-spacing-md, 12px) 0 !important}.co-form-wizard[data-appearance="flat"] .co-form-wizard__nav{background:transparent !important;border-top:0 !important;padding:var(--co-spacing-md, 12px) 0 0 !important}.co-form-wizard[data-appearance="flat"] .co-form-wizard__page-card>co-form{padding:0 !important}.co-form-wizard[data-appearance="flat"][data-theme="dark"] .co-form-wizard__title-block,.co-form-wizard[data-appearance="flat"][data-theme="dark"] .co-form-wizard__page-card{color:#f9fafb}`;
7
+
8
+ var __rest = (undefined && undefined.__rest) || function (s, e) {
9
+ var t = {};
10
+ for (var p in s)
11
+ if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
12
+ t[p] = s[p];
13
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
14
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
15
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
16
+ t[p[i]] = s[p[i]];
17
+ }
18
+ return t;
19
+ };
20
+ function safeJsonParse(s) {
21
+ try {
22
+ return JSON.parse(s);
23
+ }
24
+ catch (_a) {
25
+ return null;
26
+ }
27
+ }
28
+ const CoFormWizard = class {
29
+ constructor(hostRef) {
30
+ index.registerInstance(this, hostRef);
31
+ this.coSubmit = index.createEvent(this, "coSubmit");
32
+ this.coPageChange = index.createEvent(this, "coPageChange");
33
+ /** Locale for AJV error messages. */
34
+ this.locale = 'es';
35
+ /** Layout passed to each page's <co-form>. */
36
+ this.layout = 'grid';
37
+ /** Number of columns per page. */
38
+ this.columns = 1;
39
+ this.currentIndex = 0;
40
+ this.values = {};
41
+ this.finalScore = null;
42
+ /**
43
+ * Resolved theme styles for the wizard. Stored as state so render() picks
44
+ * up changes — using `<Host>` to bind the data-attrs + inline styles
45
+ * dodges the `setAttribute()` timing issues we saw with shadow:false.
46
+ */
47
+ this.themeStyles = null;
48
+ this.hasBg = false;
49
+ this.paged = { pages: [] };
50
+ // Use `any` rather than HTMLCoFormElement: type generation happens at
51
+ // build time, and the wizard lives in the same package, so we can't
52
+ // depend on the generated type without a chicken-and-egg.
53
+ this.currentFormEl = null;
54
+ this.handleNext = async () => {
55
+ const ok = await this.commitCurrentPage();
56
+ if (!ok)
57
+ return;
58
+ if (this.currentIndex < this.activePages.length - 1) {
59
+ this.currentIndex += 1;
60
+ this.coPageChange.emit({ index: this.currentIndex, page: this.currentPage });
61
+ }
62
+ };
63
+ this.handlePrev = () => {
64
+ if (this.currentIndex > 0) {
65
+ this.currentIndex -= 1;
66
+ this.coPageChange.emit({ index: this.currentIndex, page: this.currentPage });
67
+ }
68
+ };
69
+ /**
70
+ * Click on a step in the stepper. Backwards navigation is unrestricted
71
+ * (the user already visited those pages). Forward jumps require the
72
+ * current page to validate first, then we hop one page at a time so we
73
+ * don't silently skip validation of intermediate pages.
74
+ */
75
+ this.handleStepClick = async (targetIndex) => {
76
+ if (targetIndex === this.currentIndex)
77
+ return;
78
+ if (targetIndex < this.currentIndex) {
79
+ this.currentIndex = targetIndex;
80
+ this.coPageChange.emit({ index: this.currentIndex, page: this.currentPage });
81
+ return;
82
+ }
83
+ // Forward jump — validate-and-advance one step at a time.
84
+ while (this.currentIndex < targetIndex) {
85
+ const ok = await this.commitCurrentPage();
86
+ if (!ok)
87
+ return;
88
+ this.currentIndex += 1;
89
+ }
90
+ this.coPageChange.emit({ index: this.currentIndex, page: this.currentPage });
91
+ };
92
+ this.handleSubmit = async () => {
93
+ const ok = await this.commitCurrentPage();
94
+ if (!ok)
95
+ return;
96
+ let score;
97
+ if (this.paged.mode === 'quiz') {
98
+ const allFields = index$1.collectQuizFields(this.paged.pages);
99
+ score = index$1.computeScore(this.values, allFields, this.paged.scoring);
100
+ this.finalScore = score;
101
+ }
102
+ this.coSubmit.emit({ values: this.values, score });
103
+ };
104
+ this.handlePageChange = (ev) => {
105
+ this.values = Object.assign(Object.assign({}, this.values), { [ev.detail.name]: ev.detail.value });
106
+ };
107
+ }
108
+ componentWillLoad() {
109
+ this.parseSchema();
110
+ this.values = this.parseInitialValues();
111
+ this.applyTheme();
112
+ }
113
+ onSchemaChange() {
114
+ this.parseSchema();
115
+ this.currentIndex = 0;
116
+ this.applyTheme();
117
+ }
118
+ onThemeChange() {
119
+ this.applyTheme();
120
+ }
121
+ /**
122
+ * Compute the resolved theme styles and store in `@State()` so render()
123
+ * picks them up via `<Host>`. Children `<co-form>` receive a theme with
124
+ * the background stripped (see `themeForChildren`) so only the wizard's
125
+ * outer surface carries it — avoids the image leaking into each page.
126
+ */
127
+ applyTheme() {
128
+ var _a;
129
+ const raw = this.theme
130
+ ? (typeof this.theme === 'string' ? safeJsonParse(this.theme) : this.theme)
131
+ : this.paged.theme;
132
+ console.log('[co-form-wizard] applyTheme called', {
133
+ themeProp: this.theme,
134
+ pagedTheme: (_a = this.paged) === null || _a === void 0 ? void 0 : _a.theme,
135
+ raw,
136
+ });
137
+ if (!raw) {
138
+ this.themeStyles = null;
139
+ this.hasBg = false;
140
+ console.log('[co-form-wizard] no theme — cleared');
141
+ return;
142
+ }
143
+ const resolved = index$1.resolveTheme(raw);
144
+ this.themeStyles = index$1.themeToStyles(resolved);
145
+ this.hasBg = !!(resolved.background.color || resolved.background.imageUrl);
146
+ console.log('[co-form-wizard] theme resolved', {
147
+ resolved,
148
+ modifiers: this.themeStyles.modifiers,
149
+ customProps: this.themeStyles.customProperties,
150
+ hasBg: this.hasBg,
151
+ });
152
+ }
153
+ parseSchema() {
154
+ try {
155
+ const parsed = JSON.parse(this.schema);
156
+ this.paged = index$1.toPagedSchema(parsed);
157
+ }
158
+ catch (err) {
159
+ console.error('[co-form-wizard] failed to parse schema:', err);
160
+ this.paged = { pages: [] };
161
+ }
162
+ }
163
+ parseInitialValues() {
164
+ if (!this.initialValues)
165
+ return {};
166
+ try {
167
+ return JSON.parse(this.initialValues) || {};
168
+ }
169
+ catch (err) {
170
+ console.error('[co-form-wizard] failed to parse initialValues:', err);
171
+ return {};
172
+ }
173
+ }
174
+ /**
175
+ * Theme JSON forwarded to each child <co-form>. Background is stripped
176
+ * here — the wizard's host paints the backdrop, the inner form sits on
177
+ * a solid "page surface" so inputs stay readable.
178
+ */
179
+ get themeForChildren() {
180
+ var _a;
181
+ const raw = this.theme
182
+ ? (typeof this.theme === 'string' ? safeJsonParse(this.theme) : this.theme)
183
+ : (_a = this.paged) === null || _a === void 0 ? void 0 : _a.theme;
184
+ if (!raw || typeof raw !== 'object')
185
+ return undefined;
186
+ // Shallow clone + drop the bg block.
187
+ const _b = raw, rest = __rest(_b, ["background"]);
188
+ return JSON.stringify(rest);
189
+ }
190
+ /**
191
+ * Pages the user should see in order. Filters out pages whose `visibleIf`
192
+ * evaluates to false against the current values.
193
+ */
194
+ get activePages() {
195
+ return this.paged.pages.filter((p) => p.visibleIf ? index$1.evaluateExpression(p.visibleIf, this.values) : true);
196
+ }
197
+ get currentPage() {
198
+ var _a;
199
+ return (_a = this.activePages[this.currentIndex]) !== null && _a !== void 0 ? _a : null;
200
+ }
201
+ async commitCurrentPage() {
202
+ var _a, _b;
203
+ if (!this.currentFormEl)
204
+ return true;
205
+ const isValid = await ((_b = (_a = this.currentFormEl).validateAndCollect) === null || _b === void 0 ? void 0 : _b.call(_a));
206
+ if (!(isValid === null || isValid === void 0 ? void 0 : isValid.valid))
207
+ return false;
208
+ this.values = Object.assign(Object.assign({}, this.values), isValid.values);
209
+ return true;
210
+ }
211
+ /**
212
+ * Host element gets nothing extra — Stencil's shadow:false doesn't
213
+ * reliably rewrite `:host([attr])` selectors, so we put everything on
214
+ * the inner wrapper instead.
215
+ */
216
+ hostProps() {
217
+ return {};
218
+ }
219
+ /**
220
+ * Data attributes + inline styles for the inner `.co-form-wizard`
221
+ * wrapper. Scoped CSS targets descendants of this wrapper via normal
222
+ * descendant selectors that work regardless of Stencil scoping.
223
+ * CSS custom properties (accent / radius / header) cascade from here
224
+ * down to children — no need to also put them on the host.
225
+ */
226
+ wrapperProps() {
227
+ const t = this.themeStyles;
228
+ if (!t)
229
+ return { class: 'co-form-wizard' };
230
+ return Object.assign(Object.assign(Object.assign({ class: 'co-form-wizard', 'data-theme': t.modifiers.colorScheme, 'data-density': t.modifiers.density, 'data-appearance': t.modifiers.appearance, 'data-radius': t.modifiers.radius }, (this.hasBg ? { 'data-has-bg': '' } : {})), (t.modifiers.hideHeader ? { 'data-hide-header': '' } : {})), { style: Object.assign(Object.assign({}, t.customProperties), t.inlineStyles) });
231
+ }
232
+ render() {
233
+ var _a;
234
+ const pages = this.activePages;
235
+ if (pages.length === 0) {
236
+ return (index.h(index.Host, Object.assign({}, this.hostProps()), index.h("div", { class: "co-form-wizard__empty" }, "No pages to display.")));
237
+ }
238
+ // Quiz finished — show the score panel.
239
+ if (this.finalScore && ((_a = this.paged.scoring) === null || _a === void 0 ? void 0 : _a.showScore)) {
240
+ return (index.h(index.Host, Object.assign({}, this.hostProps()), this.renderScorePanel(this.finalScore)));
241
+ }
242
+ const current = pages[this.currentIndex];
243
+ const isFirst = this.currentIndex === 0;
244
+ const isLast = this.currentIndex === pages.length - 1;
245
+ // Each page is a fresh <co-form> with just its own fields. We pass
246
+ // initial values filtered to that page's field names so AJV doesn't
247
+ // complain about unknown properties from other pages.
248
+ const pageFields = Object.keys(current.fields);
249
+ const pageInitial = {};
250
+ for (const k of pageFields) {
251
+ if (k in this.values)
252
+ pageInitial[k] = this.values[k];
253
+ }
254
+ return (index.h(index.Host, Object.assign({}, this.hostProps()), this.renderInner(pages, current, isFirst, isLast, pageInitial)));
255
+ }
256
+ renderInner(pages, current, isFirst, isLast, pageInitial) {
257
+ var _a;
258
+ const customCss = (_a = this.themeStyles) === null || _a === void 0 ? void 0 : _a.customCss;
259
+ return (index.h("div", Object.assign({}, this.wrapperProps()), customCss && index.h("style", null, customCss), index.h("slot", { name: "header" }, (this.paged.title || this.paged.description) && (index.h("header", { class: "co-form-wizard__title-block" }, this.paged.title && (index.h("h1", { class: "co-form-wizard__title" }, this.paged.title)), this.paged.description && (index.h("p", { class: "co-form-wizard__title-desc" }, this.paged.description))))), pages.length > 1 && (index.h("ol", { class: "co-form-wizard__stepper" }, pages.map((p, i) => (index.h("li", { class: {
260
+ 'co-form-wizard__step': true,
261
+ 'is-active': i === this.currentIndex,
262
+ 'is-done': i < this.currentIndex,
263
+ }, key: p.name }, index.h("button", { type: "button", class: "co-form-wizard__step-btn", onClick: () => this.handleStepClick(i) }, index.h("span", { class: "co-form-wizard__step-num" }, i + 1), index.h("span", { class: "co-form-wizard__step-label" }, p.title || p.name))))))), index.h("section", { class: "co-form-wizard__page-card" }, this.renderPageHead(current, pages.length > 1), index.h("co-form", { ref: (el) => (this.currentFormEl = el), schema: JSON.stringify(current.fields), "initial-values": JSON.stringify(pageInitial), locale: this.locale, layout: this.layout, columns: this.columns, theme: this.themeForChildren, "hide-footer": true, onCoChange: this.handlePageChange }), index.h("div", { class: "co-form-wizard__nav" }, index.h("co-button", { label: "Anterior", variant: "outlined", disabled: isFirst, onClick: this.handlePrev }), isLast ? (index.h("co-button", { label: "Enviar", variant: "primary", onClick: this.handleSubmit })) : (index.h("co-button", { label: "Siguiente", variant: "primary", onClick: this.handleNext })))), index.h("slot", { name: "footer" })));
264
+ }
265
+ /**
266
+ * Smart page-head visibility:
267
+ * - Multi-page → always show (pill + title for progress tracking),
268
+ * unless the page explicitly hides title/description.
269
+ * - Single-page with default title "Page N" and no description → hide
270
+ * entirely; the form title block above already provides the context.
271
+ * - Single-page with a custom title or a description → show the
272
+ * relevant parts only.
273
+ * - Explicit `hideTitle` / `hideDescription` overrides on the page
274
+ * always win.
275
+ */
276
+ renderPageHead(current, isMulti) {
277
+ const titleIsDefault = !current.title || /^Page \d+$/i.test(current.title);
278
+ const customTitle = !!current.title && !titleIsDefault;
279
+ const hasDesc = !!current.description;
280
+ const wantsTitle = (customTitle || (isMulti && current.title)) && !current.hideTitle;
281
+ const wantsDesc = hasDesc && !current.hideDescription;
282
+ const wantsPill = isMulti && !current.hideTitle;
283
+ if (!wantsPill && !wantsTitle && !wantsDesc)
284
+ return null;
285
+ return (index.h("header", { class: "co-form-wizard__page-head" }, wantsPill && (index.h("span", { class: "co-form-wizard__page-pill" }, "PAGE ", this.currentIndex + 1)), wantsTitle && (index.h("h2", { class: "co-form-wizard__page-title" }, current.title)), wantsDesc && (index.h("p", { class: "co-form-wizard__page-desc" }, current.description))));
286
+ }
287
+ renderScorePanel(score) {
288
+ const passText = score.passed === true ? 'Aprobado' : score.passed === false ? 'No aprobado' : null;
289
+ return (index.h("div", { class: "co-form-wizard co-form-wizard__score" }, index.h("h2", { class: "co-form-wizard__score-title" }, "Resultado"), index.h("div", { class: "co-form-wizard__score-num" }, score.total, " / ", score.max, index.h("span", { class: "co-form-wizard__score-pct" }, "(", score.percent, "%)")), passText && (index.h("div", { class: {
290
+ 'co-form-wizard__score-pass': true,
291
+ 'is-pass': score.passed === true,
292
+ 'is-fail': score.passed === false,
293
+ } }, passText)), score.feedback.length > 0 && (index.h("ul", { class: "co-form-wizard__score-feedback" }, score.feedback.map((m) => (index.h("li", null, m)))))));
294
+ }
295
+ get host() { return index.getElement(this); }
296
+ static get watchers() { return {
297
+ "schema": [{
298
+ "onSchemaChange": 0
299
+ }],
300
+ "theme": [{
301
+ "onThemeChange": 0
302
+ }]
303
+ }; }
304
+ };
305
+ CoFormWizard.style = coFormWizardCss();
306
+
307
+ exports.co_form_wizard = CoFormWizard;
@@ -1,7 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var index = require('./index.cjs.js');
4
- require('./index-8raPCV5a.js');
4
+ require('./index-Mpsm3UE7.js');
5
+ require('./index-CLL7Ervz.js');
5
6
 
6
7
 
7
8
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-8raPCV5a.js');
3
+ var index = require('./index-Mpsm3UE7.js');
4
4
  var appGlobals = require('./app-globals-V2Kpy_OQ.js');
5
5
 
6
6
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
@@ -19,7 +19,7 @@ var patchBrowser = () => {
19
19
 
20
20
  patchBrowser().then(async (options) => {
21
21
  await appGlobals.globalScripts();
22
- return index.bootstrapLazy([["co-form.cjs",[[260,"co-form",{"schema":[1],"initialValues":[1,"initial-values"],"schemaInstance":[16],"refResolver":[16],"locale":[1],"layout":[1],"excludeFields":[1,"exclude-fields"],"disabled":[4],"readOnly":[4,"read-only"],"snapshot":[32],"refStates":[32],"setValue":[64],"getValue":[64],"touch":[64]},null,{"schema":[{"onSchemaChange":0}],"schemaInstance":[{"onSchemaChange":0}],"locale":[{"onSchemaChange":0}]}]]]], options);
22
+ return index.bootstrapLazy([["co-form.cjs",[[260,"co-form",{"schema":[1],"initialValues":[1,"initial-values"],"schemaInstance":[16],"refResolver":[16],"locale":[1],"layout":[1],"excludeFields":[1,"exclude-fields"],"disabled":[4],"readOnly":[4,"read-only"],"columns":[2],"gap":[1],"footerAlign":[1,"footer-align"],"hideFooter":[4,"hide-footer"],"theme":[1],"snapshot":[32],"refStates":[32],"themeStyles":[32],"hasBg":[32],"setValue":[64],"getValue":[64],"touch":[64],"validateAndCollect":[64]},null,{"schema":[{"onSchemaChange":0}],"schemaInstance":[{"onSchemaChange":0}],"locale":[{"onSchemaChange":0}],"theme":[{"onThemeChange":0}]}]]],["co-form-wizard.cjs",[[260,"co-form-wizard",{"schema":[1],"initialValues":[1,"initial-values"],"locale":[1],"layout":[1],"columns":[2],"theme":[1],"currentIndex":[32],"values":[32],"finalScore":[32],"themeStyles":[32],"hasBg":[32]},null,{"schema":[{"onSchemaChange":0}],"theme":[{"onThemeChange":0}]}]]]], options);
23
23
  });
24
24
 
25
25
  exports.setNonce = index.setNonce;