workers-mini-admin 0.1.1 → 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.
package/README.md CHANGED
@@ -66,6 +66,37 @@ export default {
66
66
  };
67
67
  ```
68
68
 
69
+ ### Declarative fields
70
+
71
+ Supported field types: `text`, `url`, `password`, `number`, `textarea`, `select`, `radio`, `checkbox`, `fieldset`, `row`, `list`, and trusted `html`.
72
+
73
+ **Hints:** `hint` is escaped plain text. Use `hintHtml` for trusted HTML (e.g. `<code>`). If both are set, `hintHtml` wins. For arbitrary in-form markup, use `{ type: 'html', html: '…' }`.
74
+
75
+ **Scalar attrs:** text/url/password support `pattern`, `maxlength`, `minlength`, `autocomplete`, and `spellcheck` (text only). Textareas support `maxlength`, `minlength`, `autocomplete`, and `spellcheck`. Numbers keep `min` / `max` / `step` and also accept `autocomplete`.
76
+
77
+ **Compact rows:** `{ type: 'row', fields: […] }` lays short fields side-by-side (reuses `.row` CSS).
78
+
79
+ **Repeatable lists:**
80
+
81
+ ```ts
82
+ {
83
+ type: 'list',
84
+ name: 'feeds',
85
+ legend: 'Feed sources',
86
+ minItems: 1,
87
+ maxItems: 8,
88
+ itemFields: [
89
+ { type: 'text', name: 'label', label: 'Label', required: true },
90
+ { type: 'url', name: 'url', label: 'URL', required: true },
91
+ ],
92
+ values: [{ label: 'Example', url: 'https://example.com/feed.xml' }],
93
+ }
94
+ ```
95
+
96
+ Form control names are `listName_index_fieldName` (e.g. `feeds_0_url`). `parseAdminForm` returns `values.feeds` as an array of row objects. A small add/remove script is injected automatically when the form contains a list.
97
+
98
+ Stay on Fields for login + KV settings + repeatable lists. Use `body` / `routes` / `extraCss` for live previews and other client-heavy UIs.
99
+
69
100
  ### Mount path / reverse proxy
70
101
 
71
102
  `basePath` defaults to `"/admin"`. Use `""` or `"/"` when the admin is the site root (e.g. `admin.example.com`):
@@ -153,8 +184,8 @@ You can still wire auth and chrome yourself (`isAuthenticated`, `loginResponse`,
153
184
  | Export | Role |
154
185
  | ------------------------------------ | ---------------------------------------------------- |
155
186
  | `createAdmin` | Auth router + form page with configurable `basePath` |
156
- | `adminForm` / `Field` | Declarative form HTML |
157
- | `formText` / `parseAdminForm` | FormData helpers |
187
+ | `adminForm` / `Field` | Declarative form HTML (incl. `list`, `row`) |
188
+ | `formText` / `parseAdminForm` | FormData helpers (lists → row arrays) |
158
189
  | `escapeHtml` | Safe HTML text interpolation |
159
190
  | `hexSha256` / `timingSafeEqual` | Cookie token helpers |
160
191
  | `isAuthenticated` | Cookie or `Authorization: Bearer` check |
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAGA,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ/D;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAS7D;AAED,eAAO,MAAM,mBAAmB,eAAe,CAAC;AAEhD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,EACjB,MAAM,EAAE,MAAM,EACd,UAAU,GAAE,MAA4B,EACxC,IAAI,GAAE,MAAY,GACjB,MAAM,CAGR;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,UAAU,GAAE,MAA4B,GACvC,OAAO,CAAC,OAAO,CAAC,CAkBlB;AAMD,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoBpB;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE;IACtC,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,QAAQ,CAoBX"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAGA,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ/D;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAS7D;AAED,eAAO,MAAM,mBAAmB,eAAe,CAAC;AAEhD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,EACjB,MAAM,EAAE,MAAM,EACd,UAAU,GAAE,MAA4B,EACxC,IAAI,SAAM,GACT,MAAM,CAGR;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,UAAU,GAAE,MAA4B,GACvC,OAAO,CAAC,OAAO,CAAC,CAkBlB;AAMD,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoBpB;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE;IACtC,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,QAAQ,CAoBX"}
package/dist/auth.js CHANGED
@@ -19,7 +19,7 @@ export function timingSafeEqual(a, b) {
19
19
  export const DEFAULT_COOKIE_NAME = 'admin_auth';
20
20
  export function adminAuthCookie(token, isSecure, maxAge, cookieName = DEFAULT_COOKIE_NAME, path = '/') {
21
21
  const secureFlag = isSecure ? 'Secure; ' : '';
22
- return `${cookieName}=${token}; HttpOnly; ${secureFlag}SameSite=Lax; Max-Age=${maxAge}; Path=${path}`;
22
+ return `${cookieName}=${token}; HttpOnly; ${secureFlag}SameSite=Lax; Max-Age=${String(maxAge)}; Path=${path}`;
23
23
  }
24
24
  export async function isAuthenticated(request, secret, cookieName = DEFAULT_COOKIE_NAME) {
25
25
  const auth = request.headers.get('Authorization');
@@ -29,7 +29,7 @@ export async function isAuthenticated(request, secret, cookieName = DEFAULT_COOK
29
29
  return true;
30
30
  }
31
31
  }
32
- const cookie = request.headers.get('Cookie') || '';
32
+ const cookie = request.headers.get('Cookie') ?? '';
33
33
  const match = new RegExp(String.raw `(?:^|;\s*)${escapeRegExp(cookieName)}=([^;]+)`).exec(cookie);
34
34
  if (!match) {
35
35
  return false;
package/dist/auth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/css.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Generated by scripts/embed-css.mjs — edit src/shared.css instead. */
2
- export declare const SHARED_CSS = "* {\n box-sizing: border-box;\n}\n\n.admin-body {\n font-family:\n system-ui,\n -apple-system,\n 'Segoe UI',\n sans-serif;\n margin: 0;\n line-height: 1.45;\n color: #1a1a1a;\n background: #e4e6eb;\n min-height: 100vh;\n text-size-adjust: 100%;\n}\n\n.page-shell {\n max-width: 40rem;\n margin: 0 auto;\n padding: 0.75rem 1rem 2rem;\n}\n\n@media (width >= 640px) {\n .page-shell {\n padding: 1rem 1.25rem 2rem;\n }\n}\n\n.page-header {\n margin-bottom: 1rem;\n}\n\n.page-header h1 {\n font-size: clamp(1.25rem, 4vw, 1.5rem);\n margin: 0 0 0.5rem;\n}\n\n.panel-card {\n background: #fff;\n border-radius: 12px;\n padding: 1rem 1rem 1.25rem;\n box-shadow: 0 1px 3px rgb(0 0 0 / 7%);\n margin-bottom: 1rem;\n}\n\nlabel {\n display: block;\n margin-top: 1rem;\n font-weight: 600;\n font-size: 0.95rem;\n}\n\n.mode-row label {\n margin-top: 0;\n font-weight: normal;\n display: flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.row {\n display: flex;\n gap: 0.75rem;\n flex-wrap: wrap;\n}\n\n.row label {\n flex: 1;\n min-width: min(100%, 5.5rem);\n margin-top: 0;\n}\n\n@media (width <= 480px) {\n .row {\n flex-direction: column;\n }\n\n .row label {\n min-width: 100%;\n }\n}\n\nlabel:first-of-type,\n.panel-card > label:first-child {\n margin-top: 0;\n}\n\ninput[type='text'],\ninput[type='password'],\ninput[type='url'],\ninput[type='number'],\ntextarea,\nselect {\n width: 100%;\n padding: 0.55rem 0.65rem;\n font: inherit;\n border: 1px solid #c5c9d0;\n border-radius: 8px;\n background: #fafbfc;\n}\n\ntextarea {\n min-height: 5.5rem;\n resize: vertical;\n}\n\ninput:focus,\ntextarea:focus,\nselect:focus {\n outline: 2px solid #90cdf4;\n outline-offset: 1px;\n border-color: #3182ce;\n}\n\n.hint {\n font-size: 0.82rem;\n color: #4a5568;\n font-weight: normal;\n}\n\n.actions {\n margin-top: 1.5rem;\n display: flex;\n gap: 0.75rem;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.btn-primary {\n padding: 0.6rem 1.1rem;\n border: none;\n border-radius: 8px;\n background: #2d3748;\n color: #fff;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n min-height: 44px;\n}\n\n.btn-primary:active {\n opacity: 0.94;\n}\n\n.btn-ghost {\n padding: 0.5rem 0.75rem;\n border: none;\n background: transparent;\n color: #4a5568;\n font: inherit;\n cursor: pointer;\n text-decoration: underline;\n min-height: 44px;\n}\n\n.ok {\n color: #276749;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.flash-err {\n color: #c53030;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.warn {\n color: #c05600;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.err {\n color: #b00;\n margin-bottom: 1rem;\n font-size: 0.95rem;\n}\n\n.btn-secondary {\n padding: 0.5rem 0.85rem;\n border: 1px solid #cbd5e0;\n border-radius: 8px;\n background: #f7fafc;\n font: inherit;\n cursor: pointer;\n min-height: 44px;\n font-size: 0.9rem;\n}\n\n.btn-secondary:active {\n background: #edf2f7;\n}\n\nfieldset {\n border: 1px solid #d8dee6;\n padding: 0.75rem 1rem;\n margin-top: 1rem;\n border-radius: 8px;\n background: #fafbfc;\n}\n\nlegend {\n padding: 0 0.35rem;\n font-weight: 600;\n}\n\n.mode-row {\n display: flex;\n flex-wrap: wrap;\n gap: 0.75rem 1.25rem;\n margin-top: 0.5rem;\n}\n\n.mode-row input {\n width: auto;\n margin: 0;\n}\n\n.checkbox-row {\n margin-top: 1rem;\n font-weight: normal;\n display: flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.checkbox-row input {\n width: auto;\n margin: 0;\n}\n\n.login-shell {\n max-width: 24rem;\n margin: 0 auto;\n padding: 1.25rem;\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.login-shell .panel-card {\n width: 100%;\n margin: 0;\n}\n\n.login-shell button {\n width: 100%;\n}";
2
+ export declare const SHARED_CSS = "* {\n box-sizing: border-box;\n}\n\n.admin-body {\n font-family:\n system-ui,\n -apple-system,\n 'Segoe UI',\n sans-serif;\n margin: 0;\n line-height: 1.45;\n color: #1a1a1a;\n background: #e4e6eb;\n min-height: 100vh;\n text-size-adjust: 100%;\n}\n\n.page-shell {\n max-width: 40rem;\n margin: 0 auto;\n padding: 0.75rem 1rem 2rem;\n}\n\n@media (width >= 640px) {\n .page-shell {\n padding: 1rem 1.25rem 2rem;\n }\n}\n\n.page-header {\n margin-bottom: 1rem;\n}\n\n.page-header h1 {\n font-size: clamp(1.25rem, 4vw, 1.5rem);\n margin: 0 0 0.5rem;\n}\n\n.panel-card {\n background: #fff;\n border-radius: 12px;\n padding: 1rem 1rem 1.25rem;\n box-shadow: 0 1px 3px rgb(0 0 0 / 7%);\n margin-bottom: 1rem;\n}\n\nlabel {\n display: block;\n margin-top: 1rem;\n font-weight: 600;\n font-size: 0.95rem;\n}\n\n.mode-row label {\n margin-top: 0;\n font-weight: normal;\n display: flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.row {\n display: flex;\n gap: 0.75rem;\n flex-wrap: wrap;\n}\n\n.row label {\n flex: 1;\n min-width: min(100%, 5.5rem);\n margin-top: 0;\n}\n\n@media (width <= 480px) {\n .row {\n flex-direction: column;\n }\n\n .row label {\n min-width: 100%;\n }\n}\n\nlabel:first-of-type,\n.panel-card > label:first-child {\n margin-top: 0;\n}\n\ninput[type='text'],\ninput[type='password'],\ninput[type='url'],\ninput[type='number'],\ntextarea,\nselect {\n width: 100%;\n padding: 0.55rem 0.65rem;\n font: inherit;\n border: 1px solid #c5c9d0;\n border-radius: 8px;\n background: #fafbfc;\n}\n\ntextarea {\n min-height: 5.5rem;\n resize: vertical;\n}\n\ninput:focus,\ntextarea:focus,\nselect:focus {\n outline: 2px solid #90cdf4;\n outline-offset: 1px;\n border-color: #3182ce;\n}\n\n.hint {\n font-size: 0.82rem;\n color: #4a5568;\n font-weight: normal;\n}\n\n.actions {\n margin-top: 1.5rem;\n display: flex;\n gap: 0.75rem;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.btn-primary {\n padding: 0.6rem 1.1rem;\n border: none;\n border-radius: 8px;\n background: #2d3748;\n color: #fff;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n min-height: 44px;\n}\n\n.btn-primary:active {\n opacity: 0.94;\n}\n\n.btn-ghost {\n padding: 0.5rem 0.75rem;\n border: none;\n background: transparent;\n color: #4a5568;\n font: inherit;\n cursor: pointer;\n text-decoration: underline;\n min-height: 44px;\n}\n\n.ok {\n color: #276749;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.flash-err {\n color: #c53030;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.warn {\n color: #c05600;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.err {\n color: #b00;\n margin-bottom: 1rem;\n font-size: 0.95rem;\n}\n\n.btn-secondary {\n padding: 0.5rem 0.85rem;\n border: 1px solid #cbd5e0;\n border-radius: 8px;\n background: #f7fafc;\n font: inherit;\n cursor: pointer;\n min-height: 44px;\n font-size: 0.9rem;\n}\n\n.btn-secondary:active {\n background: #edf2f7;\n}\n\nfieldset {\n border: 1px solid #d8dee6;\n padding: 0.75rem 1rem;\n margin-top: 1rem;\n border-radius: 8px;\n background: #fafbfc;\n}\n\nlegend {\n padding: 0 0.35rem;\n font-weight: 600;\n}\n\n.mode-row {\n display: flex;\n flex-wrap: wrap;\n gap: 0.75rem 1.25rem;\n margin-top: 0.5rem;\n}\n\n.mode-row input {\n width: auto;\n margin: 0;\n}\n\n.checkbox-row {\n margin-top: 1rem;\n font-weight: normal;\n display: flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.checkbox-row input {\n width: auto;\n margin: 0;\n}\n\n.list-field {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.list-field > legend {\n margin-bottom: 0.25rem;\n}\n\n.list-item {\n margin-top: 0;\n}\n\n.list-item > label:first-of-type,\n.list-item > .row:first-child label {\n margin-top: 0;\n}\n\n.list-item-actions {\n margin-top: 0.75rem;\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n.list-add {\n align-self: flex-start;\n}\n\n.list-add:disabled,\n.list-item-remove:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.login-shell {\n max-width: 24rem;\n margin: 0 auto;\n padding: 1.25rem;\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.login-shell .panel-card {\n width: 100%;\n margin: 0;\n}\n\n.login-shell button {\n width: 100%;\n}";
3
3
  //# sourceMappingURL=css.d.ts.map
package/dist/css.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,eAAO,MAAM,UAAU,+uHAA+uH,CAAC"}
1
+ {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,eAAO,MAAM,UAAU,svIAAsvI,CAAC"}
package/dist/css.js CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Generated by scripts/embed-css.mjs — edit src/shared.css instead. */
2
- export const SHARED_CSS = "* {\n box-sizing: border-box;\n}\n\n.admin-body {\n font-family:\n system-ui,\n -apple-system,\n 'Segoe UI',\n sans-serif;\n margin: 0;\n line-height: 1.45;\n color: #1a1a1a;\n background: #e4e6eb;\n min-height: 100vh;\n text-size-adjust: 100%;\n}\n\n.page-shell {\n max-width: 40rem;\n margin: 0 auto;\n padding: 0.75rem 1rem 2rem;\n}\n\n@media (width >= 640px) {\n .page-shell {\n padding: 1rem 1.25rem 2rem;\n }\n}\n\n.page-header {\n margin-bottom: 1rem;\n}\n\n.page-header h1 {\n font-size: clamp(1.25rem, 4vw, 1.5rem);\n margin: 0 0 0.5rem;\n}\n\n.panel-card {\n background: #fff;\n border-radius: 12px;\n padding: 1rem 1rem 1.25rem;\n box-shadow: 0 1px 3px rgb(0 0 0 / 7%);\n margin-bottom: 1rem;\n}\n\nlabel {\n display: block;\n margin-top: 1rem;\n font-weight: 600;\n font-size: 0.95rem;\n}\n\n.mode-row label {\n margin-top: 0;\n font-weight: normal;\n display: flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.row {\n display: flex;\n gap: 0.75rem;\n flex-wrap: wrap;\n}\n\n.row label {\n flex: 1;\n min-width: min(100%, 5.5rem);\n margin-top: 0;\n}\n\n@media (width <= 480px) {\n .row {\n flex-direction: column;\n }\n\n .row label {\n min-width: 100%;\n }\n}\n\nlabel:first-of-type,\n.panel-card > label:first-child {\n margin-top: 0;\n}\n\ninput[type='text'],\ninput[type='password'],\ninput[type='url'],\ninput[type='number'],\ntextarea,\nselect {\n width: 100%;\n padding: 0.55rem 0.65rem;\n font: inherit;\n border: 1px solid #c5c9d0;\n border-radius: 8px;\n background: #fafbfc;\n}\n\ntextarea {\n min-height: 5.5rem;\n resize: vertical;\n}\n\ninput:focus,\ntextarea:focus,\nselect:focus {\n outline: 2px solid #90cdf4;\n outline-offset: 1px;\n border-color: #3182ce;\n}\n\n.hint {\n font-size: 0.82rem;\n color: #4a5568;\n font-weight: normal;\n}\n\n.actions {\n margin-top: 1.5rem;\n display: flex;\n gap: 0.75rem;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.btn-primary {\n padding: 0.6rem 1.1rem;\n border: none;\n border-radius: 8px;\n background: #2d3748;\n color: #fff;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n min-height: 44px;\n}\n\n.btn-primary:active {\n opacity: 0.94;\n}\n\n.btn-ghost {\n padding: 0.5rem 0.75rem;\n border: none;\n background: transparent;\n color: #4a5568;\n font: inherit;\n cursor: pointer;\n text-decoration: underline;\n min-height: 44px;\n}\n\n.ok {\n color: #276749;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.flash-err {\n color: #c53030;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.warn {\n color: #c05600;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.err {\n color: #b00;\n margin-bottom: 1rem;\n font-size: 0.95rem;\n}\n\n.btn-secondary {\n padding: 0.5rem 0.85rem;\n border: 1px solid #cbd5e0;\n border-radius: 8px;\n background: #f7fafc;\n font: inherit;\n cursor: pointer;\n min-height: 44px;\n font-size: 0.9rem;\n}\n\n.btn-secondary:active {\n background: #edf2f7;\n}\n\nfieldset {\n border: 1px solid #d8dee6;\n padding: 0.75rem 1rem;\n margin-top: 1rem;\n border-radius: 8px;\n background: #fafbfc;\n}\n\nlegend {\n padding: 0 0.35rem;\n font-weight: 600;\n}\n\n.mode-row {\n display: flex;\n flex-wrap: wrap;\n gap: 0.75rem 1.25rem;\n margin-top: 0.5rem;\n}\n\n.mode-row input {\n width: auto;\n margin: 0;\n}\n\n.checkbox-row {\n margin-top: 1rem;\n font-weight: normal;\n display: flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.checkbox-row input {\n width: auto;\n margin: 0;\n}\n\n.login-shell {\n max-width: 24rem;\n margin: 0 auto;\n padding: 1.25rem;\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.login-shell .panel-card {\n width: 100%;\n margin: 0;\n}\n\n.login-shell button {\n width: 100%;\n}";
2
+ export const SHARED_CSS = "* {\n box-sizing: border-box;\n}\n\n.admin-body {\n font-family:\n system-ui,\n -apple-system,\n 'Segoe UI',\n sans-serif;\n margin: 0;\n line-height: 1.45;\n color: #1a1a1a;\n background: #e4e6eb;\n min-height: 100vh;\n text-size-adjust: 100%;\n}\n\n.page-shell {\n max-width: 40rem;\n margin: 0 auto;\n padding: 0.75rem 1rem 2rem;\n}\n\n@media (width >= 640px) {\n .page-shell {\n padding: 1rem 1.25rem 2rem;\n }\n}\n\n.page-header {\n margin-bottom: 1rem;\n}\n\n.page-header h1 {\n font-size: clamp(1.25rem, 4vw, 1.5rem);\n margin: 0 0 0.5rem;\n}\n\n.panel-card {\n background: #fff;\n border-radius: 12px;\n padding: 1rem 1rem 1.25rem;\n box-shadow: 0 1px 3px rgb(0 0 0 / 7%);\n margin-bottom: 1rem;\n}\n\nlabel {\n display: block;\n margin-top: 1rem;\n font-weight: 600;\n font-size: 0.95rem;\n}\n\n.mode-row label {\n margin-top: 0;\n font-weight: normal;\n display: flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.row {\n display: flex;\n gap: 0.75rem;\n flex-wrap: wrap;\n}\n\n.row label {\n flex: 1;\n min-width: min(100%, 5.5rem);\n margin-top: 0;\n}\n\n@media (width <= 480px) {\n .row {\n flex-direction: column;\n }\n\n .row label {\n min-width: 100%;\n }\n}\n\nlabel:first-of-type,\n.panel-card > label:first-child {\n margin-top: 0;\n}\n\ninput[type='text'],\ninput[type='password'],\ninput[type='url'],\ninput[type='number'],\ntextarea,\nselect {\n width: 100%;\n padding: 0.55rem 0.65rem;\n font: inherit;\n border: 1px solid #c5c9d0;\n border-radius: 8px;\n background: #fafbfc;\n}\n\ntextarea {\n min-height: 5.5rem;\n resize: vertical;\n}\n\ninput:focus,\ntextarea:focus,\nselect:focus {\n outline: 2px solid #90cdf4;\n outline-offset: 1px;\n border-color: #3182ce;\n}\n\n.hint {\n font-size: 0.82rem;\n color: #4a5568;\n font-weight: normal;\n}\n\n.actions {\n margin-top: 1.5rem;\n display: flex;\n gap: 0.75rem;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.btn-primary {\n padding: 0.6rem 1.1rem;\n border: none;\n border-radius: 8px;\n background: #2d3748;\n color: #fff;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n min-height: 44px;\n}\n\n.btn-primary:active {\n opacity: 0.94;\n}\n\n.btn-ghost {\n padding: 0.5rem 0.75rem;\n border: none;\n background: transparent;\n color: #4a5568;\n font: inherit;\n cursor: pointer;\n text-decoration: underline;\n min-height: 44px;\n}\n\n.ok {\n color: #276749;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.flash-err {\n color: #c53030;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.warn {\n color: #c05600;\n margin: 0 0 0.75rem;\n font-weight: 600;\n}\n\n.err {\n color: #b00;\n margin-bottom: 1rem;\n font-size: 0.95rem;\n}\n\n.btn-secondary {\n padding: 0.5rem 0.85rem;\n border: 1px solid #cbd5e0;\n border-radius: 8px;\n background: #f7fafc;\n font: inherit;\n cursor: pointer;\n min-height: 44px;\n font-size: 0.9rem;\n}\n\n.btn-secondary:active {\n background: #edf2f7;\n}\n\nfieldset {\n border: 1px solid #d8dee6;\n padding: 0.75rem 1rem;\n margin-top: 1rem;\n border-radius: 8px;\n background: #fafbfc;\n}\n\nlegend {\n padding: 0 0.35rem;\n font-weight: 600;\n}\n\n.mode-row {\n display: flex;\n flex-wrap: wrap;\n gap: 0.75rem 1.25rem;\n margin-top: 0.5rem;\n}\n\n.mode-row input {\n width: auto;\n margin: 0;\n}\n\n.checkbox-row {\n margin-top: 1rem;\n font-weight: normal;\n display: flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.checkbox-row input {\n width: auto;\n margin: 0;\n}\n\n.list-field {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.list-field > legend {\n margin-bottom: 0.25rem;\n}\n\n.list-item {\n margin-top: 0;\n}\n\n.list-item > label:first-of-type,\n.list-item > .row:first-child label {\n margin-top: 0;\n}\n\n.list-item-actions {\n margin-top: 0.75rem;\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n.list-add {\n align-self: flex-start;\n}\n\n.list-add:disabled,\n.list-item-remove:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.login-shell {\n max-width: 24rem;\n margin: 0 auto;\n padding: 1.25rem;\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.login-shell .panel-card {\n width: 100%;\n margin: 0;\n}\n\n.login-shell button {\n width: 100%;\n}";
3
3
  //# sourceMappingURL=css.js.map
package/dist/css.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"css.js","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,MAAM,CAAC,MAAM,UAAU,GAAG,4uHAA4uH,CAAC"}
1
+ {"version":3,"file":"css.js","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,MAAM,CAAC,MAAM,UAAU,GAAG,mvIAAmvI,CAAC"}
package/dist/form.d.ts CHANGED
@@ -1,14 +1,28 @@
1
- export type FieldOption = {
1
+ export interface FieldOption {
2
2
  value: string;
3
3
  label: string;
4
- };
5
- type FieldBase = {
4
+ }
5
+ interface FieldBase {
6
6
  label?: string;
7
+ /**
8
+ Plain-text hint (escaped). Ignored when `hintHtml` is set.
9
+ */
7
10
  hint?: string;
11
+ /**
12
+ Trusted HTML hint. Prefer this over `hint` when both are set.
13
+ */
14
+ hintHtml?: string;
8
15
  required?: boolean;
9
16
  placeholder?: string;
10
- };
11
- export type TextField = FieldBase & {
17
+ }
18
+ interface TextInputAttributes {
19
+ pattern?: string;
20
+ maxlength?: number;
21
+ minlength?: number;
22
+ autocomplete?: string;
23
+ spellcheck?: boolean;
24
+ }
25
+ export type TextField = FieldBase & TextInputAttributes & {
12
26
  type: 'text' | 'url' | 'password';
13
27
  name: string;
14
28
  value?: string;
@@ -20,11 +34,16 @@ export type NumberField = FieldBase & {
20
34
  min?: number;
21
35
  max?: number;
22
36
  step?: number | string;
37
+ autocomplete?: string;
23
38
  };
24
39
  export type TextareaField = FieldBase & {
25
40
  type: 'textarea';
26
41
  name: string;
27
42
  value?: string;
43
+ maxlength?: number;
44
+ minlength?: number;
45
+ autocomplete?: string;
46
+ spellcheck?: boolean;
28
47
  };
29
48
  export type SelectField = FieldBase & {
30
49
  type: 'select';
@@ -47,17 +66,46 @@ export type CheckboxField = FieldBase & {
47
66
  checked?: boolean;
48
67
  value?: string;
49
68
  };
50
- export type FieldsetField = {
69
+ export interface FieldsetField {
51
70
  type: 'fieldset';
52
71
  legend: string;
53
72
  hint?: string;
73
+ hintHtml?: string;
54
74
  fields: Field[];
55
- };
56
- export type HtmlField = {
75
+ }
76
+ export interface HtmlField {
57
77
  type: 'html';
58
78
  html: string;
59
- };
60
- export type Field = TextField | NumberField | TextareaField | SelectField | RadioField | CheckboxField | FieldsetField | HtmlField;
79
+ }
80
+ /**
81
+ Side-by-side layout for short related fields (e.g. day · month · year).
82
+ */
83
+ export interface RowField {
84
+ type: 'row';
85
+ fields: Field[];
86
+ }
87
+ export type ListItemValue = Record<string, string | boolean>;
88
+ /**
89
+ Repeatable group of fields. Form names use `listName_index_fieldName`.
90
+ */
91
+ export interface ListField {
92
+ type: 'list';
93
+ name: string;
94
+ legend?: string;
95
+ hint?: string;
96
+ hintHtml?: string;
97
+ /**
98
+ Template fields for each row (scalars, row, fieldset, html — not nested list).
99
+ */
100
+ itemFields: Field[];
101
+ values: ListItemValue[];
102
+ minItems?: number;
103
+ maxItems?: number;
104
+ addLabel?: string;
105
+ removeLabel?: string;
106
+ }
107
+ export type Field = TextField | NumberField | TextareaField | SelectField | RadioField | CheckboxField | FieldsetField | HtmlField | RowField | ListField;
108
+ export type ParsedAdminForm = Record<string, string | boolean | ListItemValue[]>;
61
109
  export declare function adminForm(options: {
62
110
  action: string;
63
111
  fields: Field[];
@@ -68,7 +116,8 @@ export declare function adminForm(options: {
68
116
  export declare function formText(form: FormData, name: string): string;
69
117
  /**
70
118
  Named scalar values from a form matching the field schema (checkbox → boolean).
119
+ List fields become arrays of row objects keyed by `list.name`.
71
120
  */
72
- export declare function parseAdminForm(form: FormData, fields: Field[]): Record<string, string | boolean>;
121
+ export declare function parseAdminForm(form: FormData, fields: Field[]): ParsedAdminForm;
73
122
  export {};
74
123
  //# sourceMappingURL=form.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG;IAClC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,UAAU,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG;IACpC,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG;IACtC,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG;IACpC,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG;IACtC,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb;;QAEC;IACD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,KAAK,GACb,SAAS,GACT,WAAW,GACX,aAAa,GACb,WAAW,GACX,UAAU,GACV,aAAa,GACb,aAAa,GACb,SAAS,CAAC;AA2Id,wBAAgB,SAAS,CAAC,OAAO,EAAE;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,GAAG,MAAM,CAUT;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7D;AAgCD;;EAEE;AACF,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,KAAK,EAAE,GACd,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAgBlC"}
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,SAAS;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;QAEC;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;QAEC;IACD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,mBAAmB;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,SAAS,GAAG,SAAS,GAC/B,mBAAmB,GAAG;IACpB,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,UAAU,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEJ,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG;IACpC,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG;IACtC,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG;IACpC,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG;IACtC,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb;;QAEC;IACD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;EAEE;AACF,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,KAAK,CAAC;IACZ,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;AAE7D;;EAEE;AACF,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;QAEC;IACD,UAAU,EAAE,KAAK,EAAE,CAAC;IACpB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,KAAK,GACb,SAAS,GACT,WAAW,GACX,aAAa,GACb,WAAW,GACX,UAAU,GACV,aAAa,GACb,aAAa,GACb,SAAS,GACT,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,MAAM,eAAe,GAAG,MAAM,CAClC,MAAM,EACN,MAAM,GAAG,OAAO,GAAG,aAAa,EAAE,CACnC,CAAC;AA+UF,wBAAgB,SAAS,CAAC,OAAO,EAAE;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,GAAG,MAAM,CAaT;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7D;AAsGD;;;EAGE;AACF,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,KAAK,EAAE,GACd,eAAe,CAiBjB"}
package/dist/form.js CHANGED
@@ -1,13 +1,106 @@
1
1
  import { escapeHtml } from './escape.js';
2
- function optionalHint(hint) {
3
- return hint ? ` <span class="hint">${escapeHtml(hint)}</span>` : '';
2
+ import { LIST_FIELD_SCRIPT } from './list-script.js';
3
+ function optionalAttribute(name, value) {
4
+ return value === undefined || value === ''
5
+ ? ''
6
+ : ` ${name}="${escapeHtml(String(value))}"`;
4
7
  }
5
- function labelHtml(id, label, hint) {
6
- return `<label for="${escapeHtml(id)}">${escapeHtml(label)}${optionalHint(hint)}</label>`;
8
+ function spellcheckAttribute(value) {
9
+ if (value === undefined) {
10
+ return '';
11
+ }
12
+ const spellcheckValue = value ? 'true' : 'false';
13
+ return ` spellcheck="${spellcheckValue}"`;
14
+ }
15
+ function hintMarkup(hint, hintHtml, isBlock = false) {
16
+ if (hintHtml) {
17
+ return isBlock
18
+ ? `<p class="hint">${hintHtml}</p>`
19
+ : ` <span class="hint">${hintHtml}</span>`;
20
+ }
21
+ if (hint) {
22
+ return isBlock
23
+ ? `<p class="hint">${escapeHtml(hint)}</p>`
24
+ : ` <span class="hint">${escapeHtml(hint)}</span>`;
25
+ }
26
+ return '';
27
+ }
28
+ function optionalHint(hint, hintHtml) {
29
+ return hintMarkup(hint, hintHtml, false);
30
+ }
31
+ function labelHtml(id, label, hint, hintHtml) {
32
+ return `<label for="${escapeHtml(id)}">${escapeHtml(label)}${optionalHint(hint, hintHtml)}</label>`;
7
33
  }
8
34
  function requiredAttribute(required) {
9
35
  return required ? ' required' : '';
10
36
  }
37
+ function withNamePrefix(field, prefix) {
38
+ if (field.type === 'html') {
39
+ return field;
40
+ }
41
+ if (field.type === 'fieldset') {
42
+ return {
43
+ ...field,
44
+ fields: field.fields.map((child) => withNamePrefix(child, prefix)),
45
+ };
46
+ }
47
+ if (field.type === 'row') {
48
+ return {
49
+ ...field,
50
+ fields: field.fields.map((child) => withNamePrefix(child, prefix)),
51
+ };
52
+ }
53
+ if (field.type === 'list') {
54
+ return field;
55
+ }
56
+ return {
57
+ ...field,
58
+ name: `${prefix}${field.name}`,
59
+ };
60
+ }
61
+ function applyListItemValues(field, values) {
62
+ if (field.type === 'html') {
63
+ return field;
64
+ }
65
+ if (field.type === 'fieldset' || field.type === 'row') {
66
+ return {
67
+ ...field,
68
+ fields: field.fields.map((child) => applyListItemValues(child, values)),
69
+ };
70
+ }
71
+ if (field.type === 'list') {
72
+ return field;
73
+ }
74
+ if (field.type === 'checkbox') {
75
+ const raw = values[field.name];
76
+ const expected = field.value ?? 'on';
77
+ return {
78
+ ...field,
79
+ checked: raw === true ||
80
+ (typeof raw === 'string' && ['true', expected].includes(raw)),
81
+ };
82
+ }
83
+ if (isValueField(field)) {
84
+ const raw = values[field.name];
85
+ return {
86
+ ...field,
87
+ value: typeof raw === 'string' || typeof raw === 'number' ? raw : '',
88
+ };
89
+ }
90
+ return field;
91
+ }
92
+ function emptyItemValues(itemFields) {
93
+ const values = {};
94
+ walkScalarFields(itemFields, (field) => {
95
+ if (field.type === 'checkbox') {
96
+ values[field.name] = false;
97
+ }
98
+ else if (isValueField(field)) {
99
+ values[field.name] = '';
100
+ }
101
+ });
102
+ return values;
103
+ }
11
104
  function renderField(field) {
12
105
  switch (field.type) {
13
106
  case 'html': {
@@ -16,6 +109,12 @@ function renderField(field) {
16
109
  case 'fieldset': {
17
110
  return renderFieldset(field);
18
111
  }
112
+ case 'row': {
113
+ return renderRow(field);
114
+ }
115
+ case 'list': {
116
+ return renderList(field);
117
+ }
19
118
  case 'radio': {
20
119
  return renderRadio(field);
21
120
  }
@@ -37,9 +136,7 @@ function renderField(field) {
37
136
  }
38
137
  }
39
138
  function renderFieldset(field) {
40
- const hint = field.hint
41
- ? `<p class="hint">${escapeHtml(field.hint)}</p>`
42
- : '';
139
+ const hint = hintMarkup(field.hint, field.hintHtml, true);
43
140
  const inner = field.fields.map((child) => renderField(child)).join('\n');
44
141
  return `<fieldset>
45
142
  <legend>${escapeHtml(field.legend)}</legend>
@@ -47,9 +144,53 @@ function renderFieldset(field) {
47
144
  ${inner}
48
145
  </fieldset>`;
49
146
  }
147
+ function renderRow(field) {
148
+ const inner = field.fields.map((child) => renderField(child)).join('\n');
149
+ return `<div class="row">
150
+ ${inner}
151
+ </div>`;
152
+ }
153
+ function renderListItem(list, index, values) {
154
+ const prefix = `${list.name}_${String(index)}_`;
155
+ const prepared = list.itemFields.map((child) => withNamePrefix(applyListItemValues(child, values), prefix));
156
+ const inner = prepared.map((child) => renderField(child)).join('\n');
157
+ const itemRemoveText = list.removeLabel ?? 'Remove';
158
+ return `<fieldset class="list-item" data-list-index="${String(index)}">
159
+ ${inner}
160
+ <div class="list-item-actions">
161
+ <button type="button" class="btn-secondary list-item-remove">${escapeHtml(itemRemoveText)}</button>
162
+ </div>
163
+ </fieldset>`;
164
+ }
165
+ function renderList(field) {
166
+ const minItems = field.minItems ?? 0;
167
+ const rows = field.values.length > 0
168
+ ? field.values
169
+ : Array.from({ length: minItems }, () => emptyItemValues(field.itemFields));
170
+ const items = rows
171
+ .map((values, index) => renderListItem(field, index, values))
172
+ .join('\n');
173
+ const templateValues = emptyItemValues(field.itemFields);
174
+ const templateItem = renderListItem(field, 0, templateValues);
175
+ const hint = hintMarkup(field.hint, field.hintHtml, true);
176
+ const legend = field.legend
177
+ ? `<legend>${escapeHtml(field.legend)}</legend>`
178
+ : '';
179
+ const listAddText = field.addLabel ?? 'Add';
180
+ const maxAttribute = field.maxItems === undefined
181
+ ? ''
182
+ : ` data-max-items="${String(field.maxItems)}"`;
183
+ return `<fieldset class="list-field" data-list-name="${escapeHtml(field.name)}" data-min-items="${String(minItems)}"${maxAttribute}>
184
+ ${legend}
185
+ ${hint}
186
+ ${items}
187
+ <template class="list-item-template">${templateItem}</template>
188
+ <button type="button" class="btn-secondary list-add">${escapeHtml(listAddText)}</button>
189
+ </fieldset>`;
190
+ }
50
191
  function renderRadio(field) {
51
192
  const legend = field.label
52
- ? `<legend>${escapeHtml(field.label)}${optionalHint(field.hint)}</legend>`
193
+ ? `<legend>${escapeHtml(field.label)}${optionalHint(field.hint, field.hintHtml)}</legend>`
53
194
  : '';
54
195
  const options = field.options
55
196
  .map((option) => {
@@ -71,21 +212,25 @@ function renderCheckbox(field) {
71
212
  const value = field.value ?? 'on';
72
213
  return `<label class="checkbox-row" for="${escapeHtml(id)}">
73
214
  <input id="${escapeHtml(id)}" type="checkbox" name="${escapeHtml(field.name)}" value="${escapeHtml(value)}"${checked}>
74
- ${escapeHtml(field.label ?? field.name)}${optionalHint(field.hint)}
215
+ ${escapeHtml(field.label ?? field.name)}${optionalHint(field.hint, field.hintHtml)}
75
216
  </label>`;
76
217
  }
77
218
  function renderTextarea(field) {
78
219
  const id = field.name;
79
- const label = field.label ? labelHtml(id, field.label, field.hint) : '';
220
+ const label = field.label
221
+ ? labelHtml(id, field.label, field.hint, field.hintHtml)
222
+ : '';
80
223
  const placeholder = field.placeholder
81
224
  ? ` placeholder="${escapeHtml(field.placeholder)}"`
82
225
  : '';
83
226
  return `${label}
84
- <textarea id="${escapeHtml(id)}" name="${escapeHtml(field.name)}"${placeholder}${requiredAttribute(field.required)}>${escapeHtml(field.value ?? '')}</textarea>`;
227
+ <textarea id="${escapeHtml(id)}" name="${escapeHtml(field.name)}"${placeholder}${optionalAttribute('maxlength', field.maxlength)}${optionalAttribute('minlength', field.minlength)}${optionalAttribute('autocomplete', field.autocomplete)}${spellcheckAttribute(field.spellcheck)}${requiredAttribute(field.required)}>${escapeHtml(field.value ?? '')}</textarea>`;
85
228
  }
86
229
  function renderSelect(field) {
87
230
  const id = field.name;
88
- const label = field.label ? labelHtml(id, field.label, field.hint) : '';
231
+ const label = field.label
232
+ ? labelHtml(id, field.label, field.hint, field.hintHtml)
233
+ : '';
89
234
  const options = field.options
90
235
  .map((option) => {
91
236
  const selected = option.value === (field.value ?? '') ? ' selected' : '';
@@ -99,9 +244,11 @@ function renderSelect(field) {
99
244
  }
100
245
  function renderNumber(field) {
101
246
  const id = field.name;
102
- const label = field.label ? labelHtml(id, field.label, field.hint) : '';
103
- const min = field.min === undefined ? '' : ` min="${field.min}"`;
104
- const max = field.max === undefined ? '' : ` max="${field.max}"`;
247
+ const label = field.label
248
+ ? labelHtml(id, field.label, field.hint, field.hintHtml)
249
+ : '';
250
+ const min = field.min === undefined ? '' : ` min="${String(field.min)}"`;
251
+ const max = field.max === undefined ? '' : ` max="${String(field.max)}"`;
105
252
  const step = field.step === undefined ? '' : ` step="${escapeHtml(String(field.step))}"`;
106
253
  const placeholder = field.placeholder
107
254
  ? ` placeholder="${escapeHtml(field.placeholder)}"`
@@ -110,28 +257,46 @@ function renderNumber(field) {
110
257
  ? ` value="${escapeHtml(String(field.value))}"`
111
258
  : '';
112
259
  return `${label}
113
- <input id="${escapeHtml(id)}" name="${escapeHtml(field.name)}" type="number"${value}${min}${max}${step}${placeholder}${requiredAttribute(field.required)}>`;
260
+ <input id="${escapeHtml(id)}" name="${escapeHtml(field.name)}" type="number"${value}${min}${max}${step}${placeholder}${optionalAttribute('autocomplete', field.autocomplete)}${requiredAttribute(field.required)}>`;
114
261
  }
115
262
  function renderTextInput(field) {
116
263
  const id = field.name;
117
- const label = field.label ? labelHtml(id, field.label, field.hint) : '';
264
+ const label = field.label
265
+ ? labelHtml(id, field.label, field.hint, field.hintHtml)
266
+ : '';
118
267
  const placeholder = field.placeholder
119
268
  ? ` placeholder="${escapeHtml(field.placeholder)}"`
120
269
  : '';
121
270
  const value = field.value === undefined ? '' : ` value="${escapeHtml(field.value)}"`;
271
+ const spellcheck = field.type === 'text' ? spellcheckAttribute(field.spellcheck) : '';
122
272
  return `${label}
123
- <input id="${escapeHtml(id)}" name="${escapeHtml(field.name)}" type="${field.type}"${value}${placeholder}${requiredAttribute(field.required)}>`;
273
+ <input id="${escapeHtml(id)}" name="${escapeHtml(field.name)}" type="${field.type}"${value}${placeholder}${optionalAttribute('pattern', field.pattern)}${optionalAttribute('maxlength', field.maxlength)}${optionalAttribute('minlength', field.minlength)}${optionalAttribute('autocomplete', field.autocomplete)}${spellcheck}${requiredAttribute(field.required)}>`;
274
+ }
275
+ function hasListField(fields) {
276
+ for (const field of fields) {
277
+ if (field.type === 'list') {
278
+ return true;
279
+ }
280
+ if ((field.type === 'fieldset' || field.type === 'row') &&
281
+ hasListField(field.fields)) {
282
+ return true;
283
+ }
284
+ }
285
+ return false;
124
286
  }
125
287
  export function adminForm(options) {
126
288
  const { action, fields, method = 'post', submitLabel = 'Save', id } = options;
127
289
  const idAttribute = id ? ` id="${escapeHtml(id)}"` : '';
128
290
  const body = fields.map((field) => renderField(field)).join('\n');
291
+ const script = hasListField(fields)
292
+ ? `\n<script>${LIST_FIELD_SCRIPT}</script>`
293
+ : '';
129
294
  return `<form method="${method}" action="${escapeHtml(action)}"${idAttribute}>
130
295
  ${body}
131
296
  <div class="actions">
132
297
  <button type="submit" class="btn-primary">${escapeHtml(submitLabel)}</button>
133
298
  </div>
134
- </form>`;
299
+ </form>${script}`;
135
300
  }
136
301
  export function formText(form, name) {
137
302
  const value = form.get(name);
@@ -149,35 +314,93 @@ const VALUE_FIELD_TYPES = new Set([
149
314
  function isValueField(field) {
150
315
  return VALUE_FIELD_TYPES.has(field.type);
151
316
  }
152
- function walkScalarFields(fields, out) {
317
+ function walkScalarFields(fields, visit) {
153
318
  for (const field of fields) {
154
- if (field.type === 'html') {
319
+ if (field.type === 'html' || field.type === 'list') {
155
320
  continue;
156
321
  }
157
- if (field.type === 'fieldset') {
158
- walkScalarFields(field.fields, out);
322
+ if (field.type === 'fieldset' || field.type === 'row') {
323
+ walkScalarFields(field.fields, visit);
159
324
  continue;
160
325
  }
161
- out.push(field);
326
+ visit(field);
162
327
  }
163
328
  }
329
+ function walkLists(fields, out) {
330
+ for (const field of fields) {
331
+ if (field.type === 'list') {
332
+ out.push(field);
333
+ continue;
334
+ }
335
+ if (field.type === 'fieldset' || field.type === 'row') {
336
+ walkLists(field.fields, out);
337
+ }
338
+ }
339
+ }
340
+ function isNamedScalarField(field) {
341
+ return field.type === 'checkbox' || isValueField(field);
342
+ }
343
+ function isCheckboxChecked(form, field, name) {
344
+ const raw = form.get(name);
345
+ const expected = field.value ?? 'on';
346
+ return typeof raw === 'string' && raw === expected;
347
+ }
348
+ function collectListIndices(form, listName) {
349
+ const indices = new Set();
350
+ const prefix = `${listName}_`;
351
+ for (const key of form.keys()) {
352
+ if (!key.startsWith(prefix)) {
353
+ continue;
354
+ }
355
+ const rest = key.slice(prefix.length);
356
+ const underscore = rest.indexOf('_');
357
+ if (underscore <= 0) {
358
+ continue;
359
+ }
360
+ const indexPart = rest.slice(0, underscore);
361
+ if (!/^\d+$/.test(indexPart)) {
362
+ continue;
363
+ }
364
+ indices.add(Number(indexPart));
365
+ }
366
+ return [...indices].toSorted((a, b) => a - b);
367
+ }
368
+ function parseListField(form, list) {
369
+ const indices = collectListIndices(form, list.name);
370
+ return indices.map((index) => {
371
+ const row = {};
372
+ walkScalarFields(list.itemFields, (field) => {
373
+ if (!isNamedScalarField(field)) {
374
+ return;
375
+ }
376
+ const name = `${list.name}_${String(index)}_${field.name}`;
377
+ row[field.name] =
378
+ field.type === 'checkbox'
379
+ ? isCheckboxChecked(form, field, name)
380
+ : formText(form, name);
381
+ });
382
+ return row;
383
+ });
384
+ }
164
385
  /**
165
386
  Named scalar values from a form matching the field schema (checkbox → boolean).
387
+ List fields become arrays of row objects keyed by `list.name`.
166
388
  */
167
389
  export function parseAdminForm(form, fields) {
168
- const scalars = [];
169
- walkScalarFields(fields, scalars);
170
390
  const result = {};
171
- for (const field of scalars) {
172
- if (field.type === 'checkbox') {
173
- const raw = form.get(field.name);
174
- const expected = field.value ?? 'on';
175
- result[field.name] = typeof raw === 'string' && raw === expected;
176
- continue;
177
- }
178
- if (isValueField(field)) {
179
- result[field.name] = formText(form, field.name);
391
+ walkScalarFields(fields, (field) => {
392
+ if (!isNamedScalarField(field)) {
393
+ return;
180
394
  }
395
+ result[field.name] =
396
+ field.type === 'checkbox'
397
+ ? isCheckboxChecked(form, field, field.name)
398
+ : formText(form, field.name);
399
+ });
400
+ const lists = [];
401
+ walkLists(fields, lists);
402
+ for (const list of lists) {
403
+ result[list.name] = parseListField(form, list);
181
404
  }
182
405
  return result;
183
406
  }
package/dist/form.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"form.js","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"form.js","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"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"}
package/dist/handler.d.ts CHANGED
@@ -28,10 +28,10 @@ export type AdminRenderResult = {
28
28
  body: string;
29
29
  fields?: undefined;
30
30
  });
31
- export type AdminSaveResult = {
31
+ export interface AdminSaveResult {
32
32
  flash?: string;
33
- };
34
- export type AdminRouteContext<Env = unknown> = {
33
+ }
34
+ export interface AdminRouteContext<Env = unknown> {
35
35
  request: Request;
36
36
  env: Env;
37
37
  url: URL;
@@ -42,8 +42,8 @@ export type AdminRouteContext<Env = unknown> = {
42
42
  */
43
43
  path: string;
44
44
  requireAuth: () => Promise<Response | undefined>;
45
- };
46
- export type CreateAdminOptions<Env = unknown> = {
45
+ }
46
+ export interface CreateAdminOptions<Env = unknown> {
47
47
  /**
48
48
  Mount path. `""` or `"/"` = site root; default `"/admin"`.
49
49
  */
@@ -72,9 +72,9 @@ export type CreateAdminOptions<Env = unknown> = {
72
72
  */
73
73
  routes?: Record<string, (context: AdminRouteContext<Env>) => Response | Promise<Response>>;
74
74
  disabledMessage?: string;
75
- };
76
- export type AdminHandler<Env = unknown> = {
75
+ }
76
+ export interface AdminHandler<Env = unknown> {
77
77
  fetch: (request: Request, env: Env) => Promise<Response | undefined>;
78
- };
78
+ }
79
79
  export declare function createAdmin<Env = unknown>(options: CreateAdminOptions<Env>): AdminHandler<Env>;
80
80
  //# sourceMappingURL=handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAMA,OAAO,EAAuB,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,WAAW,CAAC;AAGnB,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;MAEE;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;MAEE;IACF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;MAEE;IACF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;MAEE;IACF,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,GAAG,CACF;IAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAAE,CAC7E,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,GAAG,GAAG,OAAO,IAAI;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB;;MAEE;IACF,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,kBAAkB,CAAC,GAAG,GAAG,OAAO,IAAI;IAC9C;;MAEE;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,GAAG,SAAS,CAAC;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;MAEE;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,OAAO,EAAE;QAChB,OAAO,EAAE,OAAO,CAAC;QACjB,GAAG,EAAE,GAAG,CAAC;QACT,GAAG,EAAE,GAAG,CAAC;KACV,KAAK,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrD,IAAI,EAAE,CAAC,OAAO,EAAE;QACd,OAAO,EAAE,OAAO,CAAC;QACjB,GAAG,EAAE,GAAG,CAAC;QACT,GAAG,EAAE,GAAG,CAAC;QACT,IAAI,EAAE,QAAQ,CAAC;KAChB,KAAK,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACjD;;;MAGE;IACF,MAAM,CAAC,EAAE,MAAM,CACb,MAAM,EACN,CAAC,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAClE,CAAC;IACF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,YAAY,CAAC,GAAG,GAAG,OAAO,IAAI;IACxC,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;CACtE,CAAC;AA4BF,wBAAgB,WAAW,CAAC,GAAG,GAAG,OAAO,EACvC,OAAO,EAAE,kBAAkB,CAAC,GAAG,CAAC,GAC/B,YAAY,CAAC,GAAG,CAAC,CAwJnB"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAMA,OAAO,EAAuB,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,WAAW,CAAC;AAGnB,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;MAEE;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;MAEE;IACF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;MAEE;IACF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;MAEE;IACF,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,GAAG,CACF;IAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAAE,CAC7E,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB,CAAC,GAAG,GAAG,OAAO;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB;;MAEE;IACF,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,kBAAkB,CAAC,GAAG,GAAG,OAAO;IAC/C;;MAEE;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,GAAG,SAAS,CAAC;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;MAEE;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,OAAO,EAAE;QAChB,OAAO,EAAE,OAAO,CAAC;QACjB,GAAG,EAAE,GAAG,CAAC;QACT,GAAG,EAAE,GAAG,CAAC;KACV,KAAK,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrD,IAAI,EAAE,CAAC,OAAO,EAAE;QACd,OAAO,EAAE,OAAO,CAAC;QACjB,GAAG,EAAE,GAAG,CAAC;QACT,GAAG,EAAE,GAAG,CAAC;QACT,IAAI,EAAE,QAAQ,CAAC;KAChB,KAAK,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACjD;;;MAGE;IACF,MAAM,CAAC,EAAE,MAAM,CACb,MAAM,EACN,CAAC,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAClE,CAAC;IACF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY,CAAC,GAAG,GAAG,OAAO;IACzC,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;CACtE;AA4BD,wBAAgB,WAAW,CAAC,GAAG,GAAG,OAAO,EACvC,OAAO,EAAE,kBAAkB,CAAC,GAAG,CAAC,GAC/B,YAAY,CAAC,GAAG,CAAC,CAwJnB"}
package/dist/html.d.ts CHANGED
@@ -14,7 +14,7 @@ Allow only simple CSS lengths for shellMaxWidth (no injection).
14
14
  */
15
15
  export declare function isSafeCssLength(value: string): boolean;
16
16
  export declare function resolveFlashClass(flash: string, tone?: FlashTone): 'ok' | 'warn' | 'flash-err';
17
- export type AdminPageOptions = {
17
+ export interface AdminPageOptions {
18
18
  title: string;
19
19
  body: string;
20
20
  flash?: string;
@@ -42,6 +42,6 @@ export type AdminPageOptions = {
42
42
  Attributes merged onto `<body>` (values escaped).
43
43
  */
44
44
  bodyAttrs?: Record<string, string>;
45
- };
45
+ }
46
46
  export declare function adminPage(options: AdminPageOptions): string;
47
47
  //# sourceMappingURL=html.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhD,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAM,GAAG,QAAQ,CAKzD;AAED,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAClC,QAAQ,CAUV;AAKD,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAKhE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CA+BT;AAED;;EAEE;AACF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,SAAS,GACf,IAAI,GAAG,MAAM,GAAG,WAAW,CAO7B;AAaD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;MAEE;IACF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;MAEE;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;MAEE;IACF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;MAGE;IACF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;MAEE;IACF,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAAC;AAEF,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAgD3D"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhD,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAM,GAAG,QAAQ,CAKzD;AAED,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAClC,QAAQ,CAUV;AAKD,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAKhE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CA+BT;AAED;;EAEE;AACF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,SAAS,GACf,IAAI,GAAG,MAAM,GAAG,WAAW,CAO7B;AAaD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;MAEE;IACF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;MAEE;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;MAEE;IACF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;MAGE;IACF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;MAEE;IACF,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAgD3D"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { adminAuthCookie, DEFAULT_COOKIE_NAME, hexSha256, isAuthenticated, loginResponse, logoutResponse, timingSafeEqual, } from './auth.js';
2
2
  export { SHARED_CSS } from './css.js';
3
- export { adminForm, formText, parseAdminForm, type CheckboxField, type Field, type FieldOption, type FieldsetField, type HtmlField, type NumberField, type RadioField, type SelectField, type TextareaField, type TextField, } from './form.js';
3
+ export { adminForm, formText, parseAdminForm, type CheckboxField, type Field, type FieldOption, type FieldsetField, type HtmlField, type ListField, type ListItemValue, type NumberField, type ParsedAdminForm, type RadioField, type RowField, type SelectField, type TextareaField, type TextField, } from './form.js';
4
4
  export { createAdmin, type AdminHandler, type AdminRenderResult, type AdminRouteContext, type AdminSaveResult, type CreateAdminOptions, } from './handler.js';
5
5
  export { adminDisabledResponse, adminPage, escapeHtml, html, isSafeCssLength, loginPageHtml, redirect, resolveFlashClass, type AdminPageOptions, type FlashTone, } from './html.js';
6
6
  export { cookiePathForBase, joinBasePath, normalizeBasePath, normalizePathname, relativeToBase, resolveBasePath, } from './path.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,eAAe,EACf,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EACL,SAAS,EACT,QAAQ,EACR,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,SAAS,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,WAAW,EACX,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,qBAAqB,EACrB,SAAS,EACT,UAAU,EACV,IAAI,EACJ,eAAe,EACf,aAAa,EACb,QAAQ,EACR,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,SAAS,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,eAAe,EACf,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EACL,SAAS,EACT,QAAQ,EACR,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,SAAS,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,WAAW,EACX,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,qBAAqB,EACrB,SAAS,EACT,UAAU,EACV,IAAI,EACJ,eAAe,EACf,aAAa,EACb,QAAQ,EACR,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,SAAS,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,MAAM,WAAW,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,eAAe,EACf,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EACL,SAAS,EACT,QAAQ,EACR,cAAc,GAWf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,WAAW,GAMZ,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,qBAAqB,EACrB,SAAS,EACT,UAAU,EACV,IAAI,EACJ,eAAe,EACf,aAAa,EACb,QAAQ,EACR,iBAAiB,GAGlB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,eAAe,EACf,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EACL,SAAS,EACT,QAAQ,EACR,cAAc,GAef,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,WAAW,GAMZ,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,qBAAqB,EACrB,SAAS,EACT,UAAU,EACV,IAAI,EACJ,eAAe,EACf,aAAa,EACb,QAAQ,EACR,iBAAiB,GAGlB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ Client script for `type: 'list'` add/remove. Injected once when a form contains a list.
3
+ */
4
+ export declare const LIST_FIELD_SCRIPT = "(function () {\n function escapeRegExp(value) {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n }\n\n function reindexItem(item, index, listName) {\n var nextPrefix = listName + '_' + index + '_';\n var nameRe = new RegExp('^' + escapeRegExp(listName) + '_\\\\d+_');\n item.setAttribute('data-list-index', String(index));\n item.querySelectorAll('[name]').forEach(function (el) {\n var name = el.getAttribute('name');\n if (!name || !nameRe.test(name)) return;\n var fieldName = name.replace(nameRe, '');\n el.setAttribute('name', nextPrefix + fieldName);\n if (el.id && nameRe.test(el.id)) {\n el.id = nextPrefix + fieldName;\n }\n });\n item.querySelectorAll('[for]').forEach(function (el) {\n var forId = el.getAttribute('for');\n if (!forId || !nameRe.test(forId)) return;\n var fieldName = forId.replace(nameRe, '');\n el.setAttribute('for', nextPrefix + fieldName);\n });\n }\n\n function reindexAll(list) {\n var listName = list.getAttribute('data-list-name');\n var items = list.querySelectorAll(':scope > .list-item');\n items.forEach(function (item, index) {\n reindexItem(item, index, listName);\n });\n updateButtons(list);\n }\n\n function updateButtons(list) {\n var minItems = Number(list.getAttribute('data-min-items') || '0');\n var maxItems = list.getAttribute('data-max-items');\n var max = maxItems === null || maxItems === '' ? Infinity : Number(maxItems);\n var items = list.querySelectorAll(':scope > .list-item');\n var count = items.length;\n items.forEach(function (item) {\n var remove = item.querySelector('.list-item-remove');\n if (remove) remove.disabled = count <= minItems;\n });\n var add = list.querySelector(':scope > .list-add');\n if (add) add.disabled = count >= max;\n }\n\n function clearItemValues(item) {\n item.querySelectorAll('input, textarea, select').forEach(function (el) {\n if (el.type === 'checkbox' || el.type === 'radio') {\n el.checked = false;\n } else if (el.tagName === 'SELECT') {\n el.selectedIndex = 0;\n } else {\n el.value = '';\n }\n });\n }\n\n document.addEventListener('click', function (event) {\n var target = event.target;\n if (!(target instanceof Element)) return;\n\n var addBtn = target.closest('.list-add');\n if (addBtn) {\n var list = addBtn.closest('.list-field');\n if (!list) return;\n event.preventDefault();\n var maxItems = list.getAttribute('data-max-items');\n var max = maxItems === null || maxItems === '' ? Infinity : Number(maxItems);\n var items = list.querySelectorAll(':scope > .list-item');\n if (items.length >= max) return;\n var template = list.querySelector(':scope > template.list-item-template');\n var source = template\n ? template.content.querySelector('.list-item')\n : items[items.length - 1];\n if (!source) return;\n var clone = source.cloneNode(true);\n clearItemValues(clone);\n list.insertBefore(clone, template || addBtn);\n reindexAll(list);\n return;\n }\n\n var removeBtn = target.closest('.list-item-remove');\n if (removeBtn) {\n var item = removeBtn.closest('.list-item');\n var listEl = removeBtn.closest('.list-field');\n if (!item || !listEl) return;\n event.preventDefault();\n var minItems = Number(listEl.getAttribute('data-min-items') || '0');\n var count = listEl.querySelectorAll(':scope > .list-item').length;\n if (count <= minItems) return;\n item.remove();\n reindexAll(listEl);\n }\n });\n\n document.querySelectorAll('.list-field').forEach(updateButtons);\n})();";
5
+ //# sourceMappingURL=list-script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-script.d.ts","sourceRoot":"","sources":["../src/list-script.ts"],"names":[],"mappings":"AAAA;;EAEE;AACF,eAAO,MAAM,iBAAiB,wrHAqGxB,CAAC"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ Client script for `type: 'list'` add/remove. Injected once when a form contains a list.
3
+ */
4
+ export const LIST_FIELD_SCRIPT = `(function () {
5
+ function escapeRegExp(value) {
6
+ return value.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&');
7
+ }
8
+
9
+ function reindexItem(item, index, listName) {
10
+ var nextPrefix = listName + '_' + index + '_';
11
+ var nameRe = new RegExp('^' + escapeRegExp(listName) + '_\\\\d+_');
12
+ item.setAttribute('data-list-index', String(index));
13
+ item.querySelectorAll('[name]').forEach(function (el) {
14
+ var name = el.getAttribute('name');
15
+ if (!name || !nameRe.test(name)) return;
16
+ var fieldName = name.replace(nameRe, '');
17
+ el.setAttribute('name', nextPrefix + fieldName);
18
+ if (el.id && nameRe.test(el.id)) {
19
+ el.id = nextPrefix + fieldName;
20
+ }
21
+ });
22
+ item.querySelectorAll('[for]').forEach(function (el) {
23
+ var forId = el.getAttribute('for');
24
+ if (!forId || !nameRe.test(forId)) return;
25
+ var fieldName = forId.replace(nameRe, '');
26
+ el.setAttribute('for', nextPrefix + fieldName);
27
+ });
28
+ }
29
+
30
+ function reindexAll(list) {
31
+ var listName = list.getAttribute('data-list-name');
32
+ var items = list.querySelectorAll(':scope > .list-item');
33
+ items.forEach(function (item, index) {
34
+ reindexItem(item, index, listName);
35
+ });
36
+ updateButtons(list);
37
+ }
38
+
39
+ function updateButtons(list) {
40
+ var minItems = Number(list.getAttribute('data-min-items') || '0');
41
+ var maxItems = list.getAttribute('data-max-items');
42
+ var max = maxItems === null || maxItems === '' ? Infinity : Number(maxItems);
43
+ var items = list.querySelectorAll(':scope > .list-item');
44
+ var count = items.length;
45
+ items.forEach(function (item) {
46
+ var remove = item.querySelector('.list-item-remove');
47
+ if (remove) remove.disabled = count <= minItems;
48
+ });
49
+ var add = list.querySelector(':scope > .list-add');
50
+ if (add) add.disabled = count >= max;
51
+ }
52
+
53
+ function clearItemValues(item) {
54
+ item.querySelectorAll('input, textarea, select').forEach(function (el) {
55
+ if (el.type === 'checkbox' || el.type === 'radio') {
56
+ el.checked = false;
57
+ } else if (el.tagName === 'SELECT') {
58
+ el.selectedIndex = 0;
59
+ } else {
60
+ el.value = '';
61
+ }
62
+ });
63
+ }
64
+
65
+ document.addEventListener('click', function (event) {
66
+ var target = event.target;
67
+ if (!(target instanceof Element)) return;
68
+
69
+ var addBtn = target.closest('.list-add');
70
+ if (addBtn) {
71
+ var list = addBtn.closest('.list-field');
72
+ if (!list) return;
73
+ event.preventDefault();
74
+ var maxItems = list.getAttribute('data-max-items');
75
+ var max = maxItems === null || maxItems === '' ? Infinity : Number(maxItems);
76
+ var items = list.querySelectorAll(':scope > .list-item');
77
+ if (items.length >= max) return;
78
+ var template = list.querySelector(':scope > template.list-item-template');
79
+ var source = template
80
+ ? template.content.querySelector('.list-item')
81
+ : items[items.length - 1];
82
+ if (!source) return;
83
+ var clone = source.cloneNode(true);
84
+ clearItemValues(clone);
85
+ list.insertBefore(clone, template || addBtn);
86
+ reindexAll(list);
87
+ return;
88
+ }
89
+
90
+ var removeBtn = target.closest('.list-item-remove');
91
+ if (removeBtn) {
92
+ var item = removeBtn.closest('.list-item');
93
+ var listEl = removeBtn.closest('.list-field');
94
+ if (!item || !listEl) return;
95
+ event.preventDefault();
96
+ var minItems = Number(listEl.getAttribute('data-min-items') || '0');
97
+ var count = listEl.querySelectorAll(':scope > .list-item').length;
98
+ if (count <= minItems) return;
99
+ item.remove();
100
+ reindexAll(listEl);
101
+ }
102
+ });
103
+
104
+ document.querySelectorAll('.list-field').forEach(updateButtons);
105
+ })();`;
106
+ //# sourceMappingURL=list-script.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-script.js","sourceRoot":"","sources":["../src/list-script.ts"],"names":[],"mappings":"AAAA;;EAEE;AACF,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAqG3B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workers-mini-admin",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Tiny single-user admin for Cloudflare Workers: cookie/Bearer auth, declarative forms, configurable mount",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,22 +30,22 @@
30
30
  "dist"
31
31
  ],
32
32
  "devDependencies": {
33
- "@eslint/js": "^10.0.1",
34
33
  "eslint": "^10.12.0",
35
- "eslint-config-prettier": "^10.1.8",
36
- "eslint-config-narwhal": "^1.0.2",
34
+ "eslint-config-narwhal": "^2.1.1",
37
35
  "husky": "^9.1.7",
38
36
  "lint-staged": "^17.6.0",
39
37
  "prettier": "^3.9.9",
40
38
  "stylelint": "^17.16.0",
41
39
  "stylelint-config-standard": "^40.0.0",
42
40
  "typescript": "^6.0.3",
43
- "typescript-eslint": "^8.71.0",
44
41
  "wrangler": "^4.147.0"
45
42
  },
46
43
  "engines": {
47
44
  "node": ">=24"
48
45
  },
46
+ "devEngines": {
47
+ "node": "26"
48
+ },
49
49
  "publishConfig": {
50
50
  "access": "public"
51
51
  },