@gramlot/gramlot-examples 0.2.15 → 0.3.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 (74) hide show
  1. package/README.md +12 -5
  2. package/package.json +4 -3
  3. package/src/gramlot_examples/catalog.json +163 -1
  4. package/src/gramlot_examples/gallery/collections.js +4 -0
  5. package/src/gramlot_examples/gallery/dist/frame.js +88 -28
  6. package/src/gramlot_examples/gallery/dist/gallery.js +211 -52
  7. package/src/gramlot_examples/gallery/dist/inputs.js +24456 -0
  8. package/src/gramlot_examples/gallery/dist/inspector.js +42 -18
  9. package/src/gramlot_examples/gallery/dist/layout.js +541 -0
  10. package/src/gramlot_examples/gallery/dist/theme-styles.js +2 -2
  11. package/src/gramlot_examples/gallery/gallery-page.js +49 -17
  12. package/src/gramlot_examples/gallery/gallery.css +50 -4
  13. package/src/gramlot_examples/index.js +3 -2
  14. package/src/gramlot_examples/pages/README.md +5 -2
  15. package/src/gramlot_examples/pages/binding/06_style_and_visibility.md +77 -12
  16. package/src/gramlot_examples/pages/binding/09_forms.js +1 -1
  17. package/src/gramlot_examples/pages/components/01_textbox.js +32 -0
  18. package/src/gramlot_examples/pages/components/01_textbox.md +14 -0
  19. package/src/gramlot_examples/pages/components/02_checkbox.js +25 -0
  20. package/src/gramlot_examples/pages/components/02_checkbox.md +14 -0
  21. package/src/gramlot_examples/pages/components/03_radio_button_text.js +30 -0
  22. package/src/gramlot_examples/pages/components/03_radio_button_text.md +16 -0
  23. package/src/gramlot_examples/pages/components/04_text_box_area.js +23 -0
  24. package/src/gramlot_examples/pages/components/04_text_box_area.md +14 -0
  25. package/src/gramlot_examples/pages/components/05_passwordbox.js +23 -0
  26. package/src/gramlot_examples/pages/components/05_passwordbox.md +14 -0
  27. package/src/gramlot_examples/pages/components/06_radio_button.js +28 -0
  28. package/src/gramlot_examples/pages/components/06_radio_button.md +14 -0
  29. package/src/gramlot_examples/pages/components/07_colorpicker.js +24 -0
  30. package/src/gramlot_examples/pages/components/07_colorpicker.md +14 -0
  31. package/src/gramlot_examples/pages/components/08_horizontal_slider.js +24 -0
  32. package/src/gramlot_examples/pages/components/08_horizontal_slider.md +14 -0
  33. package/src/gramlot_examples/pages/components/09_vertical_slider.js +24 -0
  34. package/src/gramlot_examples/pages/components/09_vertical_slider.md +14 -0
  35. package/src/gramlot_examples/pages/components/10_number_textbox.js +30 -0
  36. package/src/gramlot_examples/pages/components/10_number_textbox.md +16 -0
  37. package/src/gramlot_examples/pages/components/11_date_textbox.js +23 -0
  38. package/src/gramlot_examples/pages/components/11_date_textbox.md +18 -0
  39. package/src/gramlot_examples/pages/components/12_time_textbox.js +23 -0
  40. package/src/gramlot_examples/pages/components/12_time_textbox.md +16 -0
  41. package/src/gramlot_examples/pages/components/13_filtering_select.js +23 -0
  42. package/src/gramlot_examples/pages/components/13_filtering_select.md +20 -0
  43. package/src/gramlot_examples/pages/components/14_callback_select.js +45 -0
  44. package/src/gramlot_examples/pages/components/14_callback_select.md +24 -0
  45. package/src/gramlot_examples/pages/components/15_combo_box.js +23 -0
  46. package/src/gramlot_examples/pages/components/15_combo_box.md +22 -0
  47. package/src/gramlot_examples/pages/components/16_checkbox_text.js +23 -0
  48. package/src/gramlot_examples/pages/components/16_checkbox_text.md +23 -0
  49. package/src/gramlot_examples/pages/components/17_date_calendar.js +25 -0
  50. package/src/gramlot_examples/pages/components/17_date_calendar.md +22 -0
  51. package/src/gramlot_examples/pages/components/18_validation.js +31 -0
  52. package/src/gramlot_examples/pages/components/18_validation.md +29 -0
  53. package/src/gramlot_examples/pages/components/19_formlet.js +26 -0
  54. package/src/gramlot_examples/pages/components/19_formlet.md +12 -0
  55. package/src/gramlot_examples/pages/components/20_group_box.js +26 -0
  56. package/src/gramlot_examples/pages/components/20_group_box.md +12 -0
  57. package/src/gramlot_examples/pages/components/21_switch.js +19 -0
  58. package/src/gramlot_examples/pages/components/21_switch.md +12 -0
  59. package/src/gramlot_examples/pages/components/22_button.js +18 -0
  60. package/src/gramlot_examples/pages/components/22_button.md +12 -0
  61. package/src/gramlot_examples/pages/components/23_toggle_button.js +18 -0
  62. package/src/gramlot_examples/pages/components/23_toggle_button.md +12 -0
  63. package/src/gramlot_examples/pages/components/24_dropdown_button.js +21 -0
  64. package/src/gramlot_examples/pages/components/24_dropdown_button.md +12 -0
  65. package/src/gramlot_examples/pages/components/25_validation_engine.js +51 -0
  66. package/src/gramlot_examples/pages/components/25_validation_engine.md +26 -0
  67. package/src/gramlot_examples/pages/components/README.md +40 -0
  68. package/src/gramlot_examples/pages/controllers/02_controller.js +1 -1
  69. package/src/gramlot_examples/pages/controllers/16_attribute_projection.js +3 -3
  70. package/src/gramlot_examples/pages/controllers/16_attribute_projection.md +8 -8
  71. package/src/gramlot_examples/pages/controllers/22_pointer_transforms.js +39 -0
  72. package/src/gramlot_examples/pages/controllers/22_pointer_transforms.md +64 -0
  73. package/src/gramlot_examples/pages/controllers/README.md +3 -0
  74. package/src/gramlot_examples/pages/html_svg/06_forms.js +3 -3
@@ -1584,13 +1584,13 @@
1584
1584
  });
1585
1585
 
1586
1586
  // node_modules/@gramlot/gramlot/src/index-page-styles.js
1587
- var compactStyle = '/* Gramlot Compact: load after gramlot-base/theme.css. Colors and behavior stay in Base. */\n@layer gramlot.tokens {\n :root {\n --gramlot-space-1: .2rem;\n --gramlot-space-2: .4rem;\n --gramlot-space-3: .5rem;\n --gramlot-space-4: .6rem;\n --gramlot-space-6: .9rem;\n --gramlot-space-8: 1.2rem;\n --gramlot-space-12: 1.8rem;\n --gramlot-radius-sm: .25rem;\n --gramlot-radius: .35rem;\n --gramlot-radius-lg: .4rem;\n }\n}\n\n@layer gramlot.base {\n html { font-size: 13px; }\n body { line-height: 1.35; }\n :where(h1, h2, h3, h4, h5, h6, p, ul, ol, dl, blockquote, pre, figure) { margin-block: 0 .5rem; }\n h1 { font-size: 1.35rem; }\n h2 { font-size: 1.15rem; }\n h3 { font-size: 1.05rem; }\n pre { padding: .5rem; }\n blockquote { padding-inline-start: .6rem; }\n hr { margin-block: 1rem; }\n}\n\n@layer gramlot.components {\n :where(button, input[type="button"], input[type="submit"], input[type="reset"], .button) {\n min-block-size: 28px;\n padding: .25rem .5rem;\n font-size: 1rem;\n line-height: 1.35;\n }\n :where(label) { font-size: .95rem; }\n :where(input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]), select, textarea) {\n min-block-size: 28px;\n padding: .25rem .5rem;\n font-size: 1rem;\n line-height: 1.35;\n }\n :where(textarea) { min-block-size: 5rem; }\n :where(input[type="color"]) { min-block-size: 28px; }\n :where(input[type="file"])::file-selector-button { margin-inline-end: .5rem; padding: .25rem .5rem; }\n :where(fieldset) { margin-block-end: .6rem; padding: .5rem; }\n :where(table) { font-size: 1rem; }\n :where(th, td) { padding: .4rem .5rem; }\n :where(details) { padding: .4rem .5rem; }\n :where(details[open] > summary) { margin-block-end: .5rem; }\n :where(dialog) { padding: .75rem; }\n}\n\n@layer gramlot.utilities {\n .example-page { inline-size: min(100% - 1.2rem, var(--gramlot-page-width)); padding-block: .6rem; }\n .card { padding: .6rem; box-shadow: none; }\n}\n';
1587
+ var appearanceStyles = { "base": "", "compact": '/* Gramlot Compact: load after gramlot-base/theme.css. Colors and behavior stay in Base. */\n@layer gramlot.tokens {\n :root {\n --gramlot-field-height: 28px;\n --gramlot-field-line-height: 1.35;\n --gramlot-field-padding: .25rem .5rem;\n --gramlot-field-font-size: 1rem;\n --gramlot-space-1: .2rem;\n --gramlot-space-2: .4rem;\n --gramlot-space-3: .5rem;\n --gramlot-space-4: .6rem;\n --gramlot-space-6: .9rem;\n --gramlot-space-8: 1.2rem;\n --gramlot-space-12: 1.8rem;\n --gramlot-radius-sm: .25rem;\n --gramlot-radius: .35rem;\n --gramlot-radius-lg: .4rem;\n }\n}\n\n@layer gramlot.base {\n html { font-size: 13px; }\n body { line-height: 1.35; }\n :where(h1, h2, h3, h4, h5, h6, p, ul, ol, dl, blockquote, pre, figure) { margin-block: 0 .5rem; }\n h1 { font-size: 1.35rem; }\n h2 { font-size: 1.15rem; }\n h3 { font-size: 1.05rem; }\n pre { padding: .5rem; }\n blockquote { padding-inline-start: .6rem; }\n hr { margin-block: 1rem; }\n}\n\n@layer gramlot.components {\n :where(button, input[type="button"], input[type="submit"], input[type="reset"], .button) {\n min-block-size: 28px;\n padding: .25rem .5rem;\n font-size: 1rem;\n line-height: 1.35;\n }\n :where(label) { font-size: .95rem; }\n :where(input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]), select, textarea) {\n min-block-size: var(--gramlot-field-height);\n padding: var(--gramlot-field-padding);\n font-size: var(--gramlot-field-font-size);\n line-height: var(--gramlot-field-line-height);\n }\n :where(textarea) { min-block-size: 5rem; }\n :where(input[type="color"]) { min-block-size: 28px; }\n :where(input[type="file"])::file-selector-button { margin-inline-end: .5rem; padding: .25rem .5rem; }\n :where(fieldset) { margin-block-end: .6rem; padding: .5rem; }\n :where(table) { font-size: 1rem; }\n :where(th, td) { padding: .4rem .5rem; }\n :where(details) { padding: .4rem .5rem; }\n :where(details[open] > summary) { margin-block-end: .5rem; }\n :where(dialog) { padding: .75rem; }\n}\n\n@layer gramlot.utilities {\n .example-page { inline-size: min(100% - 1.2rem, var(--gramlot-page-width)); padding-block: .6rem; }\n .card { padding: .6rem; box-shadow: none; }\n}\n', "mimi": '/* Gramlot Compact: load after gramlot-base/theme.css. Colors and behavior stay in Base. */\n@layer gramlot.tokens {\n :root {\n --gramlot-field-height: 28px;\n --gramlot-field-line-height: 1.35;\n --gramlot-field-padding: .25rem .5rem;\n --gramlot-field-font-size: 1rem;\n --gramlot-space-1: .2rem;\n --gramlot-space-2: .4rem;\n --gramlot-space-3: .5rem;\n --gramlot-space-4: .6rem;\n --gramlot-space-6: .9rem;\n --gramlot-space-8: 1.2rem;\n --gramlot-space-12: 1.8rem;\n --gramlot-radius-sm: .25rem;\n --gramlot-radius: .35rem;\n --gramlot-radius-lg: .4rem;\n }\n}\n\n@layer gramlot.base {\n html { font-size: 13px; }\n body { line-height: 1.35; }\n :where(h1, h2, h3, h4, h5, h6, p, ul, ol, dl, blockquote, pre, figure) { margin-block: 0 .5rem; }\n h1 { font-size: 1.35rem; }\n h2 { font-size: 1.15rem; }\n h3 { font-size: 1.05rem; }\n pre { padding: .5rem; }\n blockquote { padding-inline-start: .6rem; }\n hr { margin-block: 1rem; }\n}\n\n@layer gramlot.components {\n :where(button, input[type="button"], input[type="submit"], input[type="reset"], .button) {\n min-block-size: 28px;\n padding: .25rem .5rem;\n font-size: 1rem;\n line-height: 1.35;\n }\n :where(label) { font-size: .95rem; }\n :where(input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]), select, textarea) {\n min-block-size: var(--gramlot-field-height);\n padding: var(--gramlot-field-padding);\n font-size: var(--gramlot-field-font-size);\n line-height: var(--gramlot-field-line-height);\n }\n :where(textarea) { min-block-size: 5rem; }\n :where(input[type="color"]) { min-block-size: 28px; }\n :where(input[type="file"])::file-selector-button { margin-inline-end: .5rem; padding: .25rem .5rem; }\n :where(fieldset) { margin-block-end: .6rem; padding: .5rem; }\n :where(table) { font-size: 1rem; }\n :where(th, td) { padding: .4rem .5rem; }\n :where(details) { padding: .4rem .5rem; }\n :where(details[open] > summary) { margin-block-end: .5rem; }\n :where(dialog) { padding: .75rem; }\n}\n\n@layer gramlot.utilities {\n .example-page { inline-size: min(100% - 1.2rem, var(--gramlot-page-width)); padding-block: .6rem; }\n .card { padding: .6rem; box-shadow: none; }\n}\n\n/* Gramlot adaptation of legacy mimi; load after Base and Compact. */\n@layer gramlot.tokens {\n :root {\n --gramlot-background: #EDEEF0;\n --gramlot-surface: #F5F5F6;\n --gramlot-surface-subtle: #E0E1E3;\n --gramlot-ink: #3C3D40;\n --gramlot-text-secondary: #6B6E72;\n --gramlot-border: #BDBFC2;\n --gramlot-border-control: #9EA0A3;\n --gramlot-navigation: #48494C;\n --gramlot-navigation-text: #FFFFFF;\n --gramlot-action: #0071E3;\n --gramlot-action-hover: #005BBB;\n --gramlot-brand-blue: #0071E3;\n --gramlot-brand-yellow: #9EA0A3;\n --gramlot-selected: #E8F1FC;\n --gramlot-focus-ring: #0071E3;\n --gramlot-field-background: #FFFFFF;\n --gramlot-field-readonly-background: #E0E1E3;\n --gramlot-error: #B3261E;\n --gramlot-error-background: #FFF1F0;\n --gramlot-shadow: 0 1px 4px rgb(0 0 0 / 6%);\n --gramlot-radius-sm: 4px;\n --gramlot-radius: 3px;\n --gramlot-radius-lg: 3px;\n --gramlot-field-height: 18px;\n --gramlot-field-padding: 1px 3px;\n --gramlot-field-line-height: 1.15;\n --gramlot-field-font-size: 1rem;\n --gramlot-label-size: .9em;\n --gramlot-label-gap: 2px;\n --gramlot-label-color: var(--gramlot-text-secondary);\n --gramlot-space-4: 6px;\n --gramlot-font-ui: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;\n }\n @media (prefers-color-scheme: dark) {\n :root:not([data-theme="light"]) {\n --gramlot-background: #242527;\n --gramlot-surface: #303134;\n --gramlot-surface-subtle: #3C3D40;\n --gramlot-ink: #F2F2F7;\n --gramlot-text-secondary: #C7C7CC;\n --gramlot-border: #6B6E72;\n --gramlot-border-control: #8E8E93;\n --gramlot-navigation: #1C1C1E;\n --gramlot-action: #78B7FF;\n --gramlot-action-hover: #A6CFFF;\n --gramlot-brand-blue: #3478CA;\n --gramlot-selected: #254163;\n --gramlot-focus-ring: #78B7FF;\n --gramlot-field-background: #202124;\n --gramlot-field-readonly-background: #3C3D40;\n --gramlot-error: #FFB4AB;\n --gramlot-error-background: #482524;\n --gramlot-shadow: 0 1px 4px rgb(0 0 0 / 20%);\n }\n }\n :root[data-theme="dark"] {\n --gramlot-background: #242527;\n --gramlot-surface: #303134;\n --gramlot-surface-subtle: #3C3D40;\n --gramlot-ink: #F2F2F7;\n --gramlot-text-secondary: #C7C7CC;\n --gramlot-border: #6B6E72;\n --gramlot-border-control: #8E8E93;\n --gramlot-navigation: #1C1C1E;\n --gramlot-action: #78B7FF;\n --gramlot-action-hover: #A6CFFF;\n --gramlot-brand-blue: #3478CA;\n --gramlot-selected: #254163;\n --gramlot-focus-ring: #78B7FF;\n --gramlot-field-background: #202124;\n --gramlot-field-readonly-background: #3C3D40;\n --gramlot-error: #FFB4AB;\n --gramlot-error-background: #482524;\n --gramlot-shadow: 0 1px 4px rgb(0 0 0 / 20%);\n }\n}\n@layer gramlot.base {\n html { font-size: 12px; }\n}\n@layer gramlot.components {\n :where(label) { font-size: var(--gramlot-label-size); font-weight: normal; color: var(--gramlot-label-color); margin-block-end: var(--gramlot-label-gap); }\n :where(button, input[type="button"], input[type="submit"], input[type="reset"], .button) { min-block-size: 24px; padding: 2px 8px; font-weight: 500; }\n}\n@layer gramlot.utilities {\n .card { box-shadow: var(--gramlot-shadow); }\n}\n', "joanna": '/* Gramlot Compact: load after gramlot-base/theme.css. Colors and behavior stay in Base. */\n@layer gramlot.tokens {\n :root {\n --gramlot-field-height: 28px;\n --gramlot-field-line-height: 1.35;\n --gramlot-field-padding: .25rem .5rem;\n --gramlot-field-font-size: 1rem;\n --gramlot-space-1: .2rem;\n --gramlot-space-2: .4rem;\n --gramlot-space-3: .5rem;\n --gramlot-space-4: .6rem;\n --gramlot-space-6: .9rem;\n --gramlot-space-8: 1.2rem;\n --gramlot-space-12: 1.8rem;\n --gramlot-radius-sm: .25rem;\n --gramlot-radius: .35rem;\n --gramlot-radius-lg: .4rem;\n }\n}\n\n@layer gramlot.base {\n html { font-size: 13px; }\n body { line-height: 1.35; }\n :where(h1, h2, h3, h4, h5, h6, p, ul, ol, dl, blockquote, pre, figure) { margin-block: 0 .5rem; }\n h1 { font-size: 1.35rem; }\n h2 { font-size: 1.15rem; }\n h3 { font-size: 1.05rem; }\n pre { padding: .5rem; }\n blockquote { padding-inline-start: .6rem; }\n hr { margin-block: 1rem; }\n}\n\n@layer gramlot.components {\n :where(button, input[type="button"], input[type="submit"], input[type="reset"], .button) {\n min-block-size: 28px;\n padding: .25rem .5rem;\n font-size: 1rem;\n line-height: 1.35;\n }\n :where(label) { font-size: .95rem; }\n :where(input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]), select, textarea) {\n min-block-size: var(--gramlot-field-height);\n padding: var(--gramlot-field-padding);\n font-size: var(--gramlot-field-font-size);\n line-height: var(--gramlot-field-line-height);\n }\n :where(textarea) { min-block-size: 5rem; }\n :where(input[type="color"]) { min-block-size: 28px; }\n :where(input[type="file"])::file-selector-button { margin-inline-end: .5rem; padding: .25rem .5rem; }\n :where(fieldset) { margin-block-end: .6rem; padding: .5rem; }\n :where(table) { font-size: 1rem; }\n :where(th, td) { padding: .4rem .5rem; }\n :where(details) { padding: .4rem .5rem; }\n :where(details[open] > summary) { margin-block-end: .5rem; }\n :where(dialog) { padding: .75rem; }\n}\n\n@layer gramlot.utilities {\n .example-page { inline-size: min(100% - 1.2rem, var(--gramlot-page-width)); padding-block: .6rem; }\n .card { padding: .6rem; box-shadow: none; }\n}\n\n/* Gramlot adaptation of legacy joanna; load after Base and Compact. */\n@layer gramlot.tokens {\n :root {\n --gramlot-background: #F2F2F7;\n --gramlot-surface: #FFFFFF;\n --gramlot-surface-subtle: #F2F2F7;\n --gramlot-ink: #3A3A3C;\n --gramlot-text-secondary: #636366;\n --gramlot-border: #D1D1D6;\n --gramlot-border-control: #AEAEB2;\n --gramlot-navigation: #3A3A3C;\n --gramlot-navigation-text: #FFFFFF;\n --gramlot-action: #007AFF;\n --gramlot-action-hover: #0061CC;\n --gramlot-brand-blue: #007AFF;\n --gramlot-brand-yellow: #AEAEB2;\n --gramlot-selected: #E0EFFF;\n --gramlot-focus-ring: #007AFF;\n --gramlot-field-background: #FFFFFF;\n --gramlot-field-readonly-background: #F2F2F7;\n --gramlot-error: #B3261E;\n --gramlot-error-background: #FFF1F0;\n --gramlot-shadow: 0 1px 4px rgb(0 0 0 / 6%);\n --gramlot-radius-sm: 6px;\n --gramlot-radius: 6px;\n --gramlot-radius-lg: 6px;\n --gramlot-field-height: 20px;\n --gramlot-field-padding: 1px 3px;\n --gramlot-field-line-height: 1.15;\n --gramlot-field-font-size: 1rem;\n --gramlot-label-size: .8em;\n --gramlot-label-gap: 2px;\n --gramlot-label-color: var(--gramlot-text-secondary);\n --gramlot-space-4: 6px;\n --gramlot-font-ui: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;\n }\n @media (prefers-color-scheme: dark) {\n :root:not([data-theme="light"]) {\n --gramlot-background: #1C1C1E;\n --gramlot-surface: #2C2C2E;\n --gramlot-surface-subtle: #3A3A3C;\n --gramlot-ink: #F2F2F7;\n --gramlot-text-secondary: #C7C7CC;\n --gramlot-border: #636366;\n --gramlot-border-control: #8E8E93;\n --gramlot-navigation: #1C1C1E;\n --gramlot-action: #78B7FF;\n --gramlot-action-hover: #A6CFFF;\n --gramlot-brand-blue: #3478CA;\n --gramlot-selected: #254163;\n --gramlot-focus-ring: #78B7FF;\n --gramlot-field-background: #202124;\n --gramlot-field-readonly-background: #3A3A3C;\n --gramlot-error: #FFB4AB;\n --gramlot-error-background: #482524;\n --gramlot-shadow: 0 1px 4px rgb(0 0 0 / 20%);\n }\n }\n :root[data-theme="dark"] {\n --gramlot-background: #1C1C1E;\n --gramlot-surface: #2C2C2E;\n --gramlot-surface-subtle: #3A3A3C;\n --gramlot-ink: #F2F2F7;\n --gramlot-text-secondary: #C7C7CC;\n --gramlot-border: #636366;\n --gramlot-border-control: #8E8E93;\n --gramlot-navigation: #1C1C1E;\n --gramlot-action: #78B7FF;\n --gramlot-action-hover: #A6CFFF;\n --gramlot-brand-blue: #3478CA;\n --gramlot-selected: #254163;\n --gramlot-focus-ring: #78B7FF;\n --gramlot-field-background: #202124;\n --gramlot-field-readonly-background: #3A3A3C;\n --gramlot-error: #FFB4AB;\n --gramlot-error-background: #482524;\n --gramlot-shadow: 0 1px 4px rgb(0 0 0 / 20%);\n }\n}\n@layer gramlot.base {\n html { font-size: 13px; }\n}\n@layer gramlot.components {\n :where(label) { font-size: var(--gramlot-label-size); font-weight: normal; color: var(--gramlot-label-color); margin-block-end: var(--gramlot-label-gap); }\n :where(button, input[type="button"], input[type="submit"], input[type="reset"], .button) { min-block-size: 26px; padding: 2px 8px; font-weight: 500; }\n}\n@layer gramlot.utilities {\n .card { box-shadow: var(--gramlot-shadow); }\n}\n' };
1588
1588
 
1589
1589
  // node_modules/@gramlot/gramlot/src/index-theme.js
1590
1590
  var THEME_READY = "index:theme-ready";
1591
1591
  var THEME_SET = "index:theme-set";
1592
1592
  var THEMES = /* @__PURE__ */ new Set(["light", "dark"]);
1593
- var APPEARANCES = /* @__PURE__ */ new Set(["base", "compact"]);
1593
+ var APPEARANCES = /* @__PURE__ */ new Set(["base", "compact", "mimi", "joanna"]);
1594
1594
 
1595
1595
  // node_modules/@gramlot/gramlot/src/index-page-runtime.js
1596
1596
  function mountIndexPage(renderer, root, onSelection = () => {
@@ -1607,6 +1607,10 @@
1607
1607
  const appearance = byId("index-appearance");
1608
1608
  const sidebar = byId("index-sidebar");
1609
1609
  const sidebarHandle = byId("index-sidebar-divider");
1610
+ const navigationToggle = byId("index-navigation-toggle");
1611
+ const codeToggle = byId("index-code-toggle");
1612
+ const codeSidebar = byId("index-code");
1613
+ const codeHandle = byId("index-code-divider");
1610
1614
  const preferencesKey = `gramlot.${shell.id}.preferences:${window2.location.pathname}`;
1611
1615
  let preferences = {};
1612
1616
  try {
@@ -1630,12 +1634,17 @@
1630
1634
  state.setItem("keyboard", keyboard?.checked ?? false);
1631
1635
  state.setItem("theme", theme?.value ?? "light");
1632
1636
  state.setItem("appearance", appearance?.value ?? "compact");
1637
+ state.setItem("navigationVisible", preferences.navigationVisible !== false);
1638
+ state.setItem("codeVisible", preferences.codeVisible !== false);
1633
1639
  const savePreferences = () => {
1634
1640
  try {
1635
1641
  window2.localStorage.setItem(preferencesKey, JSON.stringify({
1636
1642
  theme: state.getItem("theme"),
1637
1643
  appearance: state.getItem("appearance"),
1638
- sidebarWidth: state.getItem("preferredSidebarWidth")
1644
+ sidebarWidth: state.getItem("preferredSidebarWidth"),
1645
+ codeWidth: state.getItem("preferredCodeWidth"),
1646
+ navigationVisible: state.getItem("navigationVisible"),
1647
+ codeVisible: state.getItem("codeVisible")
1639
1648
  }));
1640
1649
  } catch (error) {
1641
1650
  if (error.name !== "SecurityError" && error.name !== "QuotaExceededError") throw error;
@@ -1643,7 +1652,7 @@
1643
1652
  };
1644
1653
  const entries2 = /* @__PURE__ */ new Map();
1645
1654
  const releases = [];
1646
- const style = root.builder.wrapSource(root.value).style(compactStyle, { media: (appearance?.value ?? "compact") === "compact" ? "all" : "not all" });
1655
+ const style = root.builder.wrapSource(root.value).style(appearanceStyles[appearance?.value ?? "compact"]);
1647
1656
  let drag = null;
1648
1657
  let disposed = false;
1649
1658
  let installPrompt = null;
@@ -1673,10 +1682,27 @@
1673
1682
  const send = (frame) => frame.contentWindow.postMessage({ type: THEME_SET, theme: state.getItem("theme"), appearance: state.getItem("appearance") }, "*");
1674
1683
  const applyTheme = () => {
1675
1684
  document2.documentElement.setAttribute("data-theme", state.getItem("theme"));
1676
- style.setAttr({ media: state.getItem("appearance") === "compact" ? "all" : "not all" });
1685
+ style.setValue(appearanceStyles[state.getItem("appearance")]);
1677
1686
  for (const { frame } of entries2.values()) if (frame) send(frame);
1678
1687
  };
1679
1688
  const updateInspector = () => onSelection(entries2, state.getItem("active"));
1689
+ const updatePanels = () => {
1690
+ if (navigationToggle) {
1691
+ const visible = state.getItem("navigationVisible");
1692
+ set(sidebar, { hidden: !visible });
1693
+ set(sidebarHandle, { hidden: !visible });
1694
+ set(navigationToggle, { aria_expanded: String(visible) });
1695
+ set(shell, { data_navigation_hidden: String(!visible) });
1696
+ }
1697
+ if (codeSidebar) {
1698
+ const available = Boolean(entries2.get(state.getItem("active"))?.code);
1699
+ const visible = available && state.getItem("codeVisible");
1700
+ set(codeSidebar, { hidden: !visible });
1701
+ set(codeHandle, { hidden: !visible });
1702
+ set(codeToggle, { disabled: !available, aria_expanded: String(visible) });
1703
+ set(shell, { data_code_visible: String(visible) });
1704
+ }
1705
+ };
1680
1706
  function select(key) {
1681
1707
  const entry = entries2.get(key);
1682
1708
  if (!opened.getItem(key)) {
@@ -1689,29 +1715,38 @@
1689
1715
  const active = current === key;
1690
1716
  set(item.tab, { aria_selected: String(active), tabindex: active && state.getItem("keyboard") ? 0 : -1 });
1691
1717
  set(item.panel, { hidden: !active });
1718
+ if (item.code) set(item.code, { hidden: !active });
1692
1719
  if (item.open) set(item.open, { aria_current: active ? "page" : null });
1693
1720
  }
1694
1721
  state.setItem("active", key);
1722
+ updatePanels();
1695
1723
  updateInspector();
1696
1724
  }
1697
- function setRatio(entry, value) {
1698
- const ratio = Math.max(20, Math.min(80, value));
1699
- state.setItem(`ratio.${entry.key}`, ratio);
1700
- set(entry.split, { style: `--split-position: ${ratio}%` });
1701
- set(entry.handle, { aria_valuenow: ratio });
1702
- }
1703
1725
  const sidebarMaximum = () => Math.max(120, Math.min(460, Math.floor(window2.innerWidth * 0.6)));
1726
+ const applyWidths = () => set(shell, { style: `--sidebar-width: ${state.getItem("sidebarWidth")}px; --code-width: ${state.getItem("codeWidth") ?? 420}px` });
1704
1727
  const setSidebarWidth = (value, remember = false) => {
1705
1728
  const maximum = sidebarMaximum();
1706
1729
  const width = Math.max(120, Math.min(maximum, value));
1707
1730
  state.setItem("sidebarWidth", width);
1708
- set(shell, { style: `--sidebar-width: ${width}px` });
1731
+ applyWidths();
1709
1732
  set(sidebarHandle, { aria_valuenow: width, aria_valuemax: maximum });
1710
1733
  if (remember) {
1711
1734
  state.setItem("preferredSidebarWidth", width);
1712
1735
  savePreferences();
1713
1736
  }
1714
1737
  };
1738
+ const codeMaximum = () => Math.max(200, Math.floor(window2.innerWidth * 0.6));
1739
+ const setCodeWidth = (value, remember = false) => {
1740
+ const maximum = codeMaximum();
1741
+ const width = Math.max(200, Math.min(maximum, value));
1742
+ state.setItem("codeWidth", width);
1743
+ applyWidths();
1744
+ set(codeHandle, { aria_valuenow: width, aria_valuemax: maximum });
1745
+ if (remember) {
1746
+ state.setItem("preferredCodeWidth", width);
1747
+ savePreferences();
1748
+ }
1749
+ };
1715
1750
  const beginDrag = (handle, event, move) => {
1716
1751
  if (event.button !== 0) return;
1717
1752
  stopDrag();
@@ -1756,6 +1791,38 @@
1756
1791
  const width = typeof savedWidth === "number" && Number.isFinite(savedWidth) && savedWidth >= 120 && savedWidth <= 460 ? savedWidth : sidebar.getBoundingClientRect().width || Number(sidebarHandle.getAttribute("aria-valuenow"));
1757
1792
  state.setItem("preferredSidebarWidth", width);
1758
1793
  setSidebarWidth(width);
1794
+ listen(navigationToggle, "click", () => {
1795
+ state.setItem("navigationVisible", !state.getItem("navigationVisible"));
1796
+ updatePanels();
1797
+ savePreferences();
1798
+ });
1799
+ listen(codeToggle, "click", () => {
1800
+ state.setItem("codeVisible", !state.getItem("codeVisible"));
1801
+ updatePanels();
1802
+ savePreferences();
1803
+ });
1804
+ if (codeHandle) {
1805
+ const saved = preferences.codeWidth;
1806
+ const width2 = typeof saved === "number" && Number.isFinite(saved) && saved >= 200 ? saved : 420;
1807
+ state.setItem("preferredCodeWidth", width2);
1808
+ setCodeWidth(width2);
1809
+ listen(codeHandle, "keydown", (event) => {
1810
+ const current = state.getItem("codeWidth");
1811
+ const value = event.key === "ArrowLeft" ? current + 10 : event.key === "ArrowRight" ? current - 10 : event.key === "Home" ? 200 : event.key === "End" ? codeMaximum() : null;
1812
+ if (value == null) return;
1813
+ event.preventDefault();
1814
+ setCodeWidth(value, true);
1815
+ });
1816
+ listen(codeHandle, "pointerdown", (event) => beginDrag(
1817
+ codeHandle,
1818
+ event,
1819
+ (x2) => setCodeWidth(Math.round(shell.getBoundingClientRect().right - x2), true)
1820
+ ));
1821
+ listen(codeHandle, "lostpointercapture", () => {
1822
+ if (drag?.handle === codeHandle) stopDrag();
1823
+ });
1824
+ listen(window2, "resize", () => setCodeWidth(state.getItem("preferredCodeWidth")));
1825
+ }
1759
1826
  listen(sidebarHandle, "keydown", (event) => {
1760
1827
  const current = state.getItem("sidebarWidth");
1761
1828
  const value = event.key === "ArrowLeft" ? current - 10 : event.key === "ArrowRight" ? current + 10 : event.key === "Home" ? 120 : event.key === "End" ? sidebarMaximum() : null;
@@ -1778,6 +1845,7 @@
1778
1845
  key,
1779
1846
  tab,
1780
1847
  panel: byId(`panel-${key}`),
1848
+ code: byId(`codepane-${key}`),
1781
1849
  open: key === "intro" ? null : byId(`open-${key}`)
1782
1850
  };
1783
1851
  entries2.set(key, entry);
@@ -1802,25 +1870,7 @@
1802
1870
  prepareEntry(entry, { byId, node, set, listen });
1803
1871
  if (entry.panel.classList.contains("index-category")) continue;
1804
1872
  entry.frame = byId(`frame-${key}`);
1805
- entry.split = byId(`split-${key}`);
1806
- entry.handle = byId(`divider-${key}`);
1807
- if (entry.handle) state.setItem(`ratio.${key}`, Number(entry.handle.getAttribute("aria-valuenow")));
1808
1873
  listen(entry.frame, "load", () => send(entry.frame));
1809
- if (!entry.handle) continue;
1810
- listen(entry.handle, "keydown", (event) => {
1811
- const current = state.getItem(`ratio.${key}`);
1812
- const value = event.key === "ArrowLeft" ? current - 5 : event.key === "ArrowRight" ? current + 5 : event.key === "Home" ? 20 : event.key === "End" ? 80 : null;
1813
- if (value == null) return;
1814
- event.preventDefault();
1815
- setRatio(entry, value);
1816
- });
1817
- listen(entry.handle, "pointerdown", (event) => beginDrag(entry.handle, event, (x2) => {
1818
- const bounds = entry.split.getBoundingClientRect();
1819
- if (bounds.width > 0) setRatio(entry, Math.round((x2 - bounds.left) * 100 / bounds.width));
1820
- }));
1821
- listen(entry.handle, "lostpointercapture", () => {
1822
- if (drag?.handle === entry.handle) stopDrag();
1823
- });
1824
1874
  }
1825
1875
  listen(document2, "pointermove", (event) => {
1826
1876
  if (!drag || event.pointerId !== drag.pointerId) return;
@@ -1839,7 +1889,7 @@
1839
1889
  }
1840
1890
  });
1841
1891
  listen(appearance, "change", () => {
1842
- if (!APPEARANCES.has(appearance?.value ?? "compact")) throw new Error("Index appearance must be base or compact");
1892
+ if (!APPEARANCES.has(appearance?.value ?? "compact")) throw new Error("Unknown index appearance");
1843
1893
  state.setItem("appearance", appearance?.value ?? "compact");
1844
1894
  set(appearance, { value: appearance?.value ?? "compact" });
1845
1895
  for (const option of appearance.options) set(option, { selected: option.value === (appearance?.value ?? "compact") });
@@ -1865,6 +1915,7 @@
1865
1915
  }
1866
1916
  });
1867
1917
  applyTheme();
1918
+ updatePanels();
1868
1919
  updateInspector();
1869
1920
  renderer.onDispose(root, dispose);
1870
1921
  } catch (error) {
@@ -1874,6 +1925,85 @@
1874
1925
  return { dispose };
1875
1926
  }
1876
1927
 
1928
+ // src/gramlot_examples/gallery/browser/gallery-settings.js
1929
+ var SETTINGS_SET = "gallery:settings-set";
1930
+ var LABEL_POSITIONS = /* @__PURE__ */ new Set(["example", "TL", "TC", "TR", "L", "R", "BL", "BC", "BR"]);
1931
+ function mountGallerySettings(renderer, root) {
1932
+ const document2 = renderer.destination.ownerDocument;
1933
+ const window2 = document2.defaultView;
1934
+ const control = document2.getElementById("gallery-label-position");
1935
+ const source = renderer.elements.get(control).node;
1936
+ const state = new root.builder.data.constructor();
1937
+ const key = `gramlot.gallery.settings:${window2.location.pathname}`;
1938
+ let saved;
1939
+ try {
1940
+ saved = window2.localStorage.getItem(key);
1941
+ } catch (error) {
1942
+ if (error.name !== "SecurityError") throw error;
1943
+ }
1944
+ state.setItem("labelPosition", LABEL_POSITIONS.has(saved) ? saved : "example");
1945
+ source.setAttr({ value: state.getItem("labelPosition") });
1946
+ for (const option of control.options) renderer.elements.get(option).node.setAttr({ selected: option.value === state.getItem("labelPosition") });
1947
+ const frames = () => [...renderer.records.get(root).element.querySelectorAll(".gallery-preview iframe")];
1948
+ const previewKey = (frame) => frame.id.slice("frame-".length);
1949
+ const send = (frame) => frame.contentWindow.postMessage({
1950
+ type: SETTINGS_SET,
1951
+ labelPosition: state.getItem("labelPosition"),
1952
+ touchMode: state.getItem(`preview.${previewKey(frame)}`) === "mobile" ? "on" : "off"
1953
+ }, "*");
1954
+ const listeners = [];
1955
+ for (const frame of frames()) {
1956
+ const key2 = previewKey(frame);
1957
+ const stage = document2.getElementById(`preview-stage-${key2}`);
1958
+ state.setItem(`preview.${key2}`, "normal");
1959
+ for (const mode of ["normal", "mobile"]) {
1960
+ const button = document2.getElementById(`preview-${mode}-${key2}`);
1961
+ const select = () => {
1962
+ state.setItem(`preview.${key2}`, mode);
1963
+ renderer.elements.get(stage).node.setAttr({ "data-preview-mode": mode });
1964
+ for (const candidate of ["normal", "mobile"]) {
1965
+ const target = document2.getElementById(`preview-${candidate}-${key2}`);
1966
+ renderer.elements.get(target).node.setAttr({ "aria-pressed": String(candidate === mode) });
1967
+ }
1968
+ if (frame.hasAttribute("src")) send(frame);
1969
+ };
1970
+ button.addEventListener("click", select);
1971
+ listeners.push(() => button.removeEventListener("click", select));
1972
+ }
1973
+ }
1974
+ const change = () => {
1975
+ state.setItem("labelPosition", control.value);
1976
+ source.setAttr({ value: control.value });
1977
+ try {
1978
+ window2.localStorage.setItem(key, control.value);
1979
+ } catch (error) {
1980
+ if (!["SecurityError", "QuotaExceededError"].includes(error.name)) throw error;
1981
+ }
1982
+ for (const frame of frames()) if (frame.hasAttribute("src")) send(frame);
1983
+ };
1984
+ const message = (event) => {
1985
+ if (event.data?.type !== THEME_READY) return;
1986
+ const frame = frames().find((item) => item.contentWindow === event.source);
1987
+ if (frame) {
1988
+ send(frame);
1989
+ const button = document2.getElementById(`preview-mobile-${previewKey(frame)}`);
1990
+ if (button) renderer.elements.get(button).node.setAttr({ title: event.data.devices?.length ? `Declared devices: ${event.data.devices.join(", ")}` : "Device suitability not declared; preview only" });
1991
+ }
1992
+ };
1993
+ control.addEventListener("change", change);
1994
+ window2.addEventListener("message", message);
1995
+ let disposed = false;
1996
+ const dispose = () => {
1997
+ if (disposed) return;
1998
+ disposed = true;
1999
+ for (const release of listeners) release();
2000
+ control.removeEventListener("change", change);
2001
+ window2.removeEventListener("message", message);
2002
+ };
2003
+ renderer.onDispose(root, dispose);
2004
+ return { dispose };
2005
+ }
2006
+
1877
2007
  // node_modules/highlight.js/es/core.js
1878
2008
  var import_core = __toESM(require_core(), 1);
1879
2009
  var core_default = import_core.default;
@@ -6354,7 +6484,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
6354
6484
 
6355
6485
  // src/gramlot_examples/gallery/browser/gallery.js
6356
6486
  function mountGallery(renderer, root, onSelection) {
6357
- return mountIndexPage(renderer, root, onSelection, (entry, { byId, node, set, listen }) => {
6487
+ const settings = mountGallerySettings(renderer, root);
6488
+ const index = mountIndexPage(renderer, root, onSelection, (entry, { byId, node, set, listen }) => {
6358
6489
  const { key } = entry;
6359
6490
  renderReadme(byId(`readme-${key}`));
6360
6491
  if (entry.panel.classList.contains("index-category")) return;
@@ -6374,17 +6505,21 @@ Please report this to https://github.com/markedjs/marked.`, e) {
6374
6505
  set(byId(item.getAttribute("aria-controls")), { hidden: !active });
6375
6506
  }
6376
6507
  };
6377
- for (const [index, sourceTab] of sourceTabs.entries()) {
6508
+ for (const [index2, sourceTab] of sourceTabs.entries()) {
6378
6509
  listen(sourceTab, "click", () => selectSource(sourceTab));
6379
6510
  listen(sourceTab, "keydown", (event) => {
6380
6511
  if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) return;
6381
- const next = event.key === "Home" ? 0 : event.key === "End" ? sourceTabs.length - 1 : (index + (event.key === "ArrowRight" ? 1 : -1) + sourceTabs.length) % sourceTabs.length;
6512
+ const next = event.key === "Home" ? 0 : event.key === "End" ? sourceTabs.length - 1 : (index2 + (event.key === "ArrowRight" ? 1 : -1) + sourceTabs.length) % sourceTabs.length;
6382
6513
  event.preventDefault();
6383
6514
  selectSource(sourceTabs[next]);
6384
6515
  sourceTabs[next].focus();
6385
6516
  });
6386
6517
  }
6387
6518
  });
6519
+ return { dispose() {
6520
+ settings.dispose();
6521
+ index.dispose();
6522
+ } };
6388
6523
  }
6389
6524
 
6390
6525
  // inspector-runtime:runtime
@@ -6437,6 +6572,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
6437
6572
  }
6438
6573
  throw new Error(`Invalid ${type} value: ${text2 || "(empty)"}`);
6439
6574
  }
6575
+ function readParameterEnums(node) {
6576
+ return Object.fromEntries(Object.entries(node._getMeta("gramlot_component")?.parameters ?? {}).filter(([, spec]) => spec.enum).map(([name, spec]) => [name, spec.enum]));
6577
+ }
6440
6578
  var InspectorStyles = class {
6441
6579
  #document;
6442
6580
  #element = null;
@@ -6525,7 +6663,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
6525
6663
  if (!identities.has(node)) identities.set(node, ++nextNode);
6526
6664
  return identities.get(node);
6527
6665
  };
6528
- const describe = (store, ancestors = /* @__PURE__ */ new Set()) => {
6666
+ const describe = (store, root, ancestors = /* @__PURE__ */ new Set()) => {
6529
6667
  if (ancestors.has(store)) throw new Error("Inspector snapshots require an acyclic Bag");
6530
6668
  const next = /* @__PURE__ */ new Set([...ancestors, store]);
6531
6669
  return store.getNodes().map((node) => {
@@ -6536,15 +6674,16 @@ Please report this to https://github.com/markedjs/marked.`, e) {
6536
6674
  label: node.label,
6537
6675
  revision: versions.get(node) ?? 0,
6538
6676
  value: branch ? null : cell(value),
6539
- children: branch ? describe(value, next) : null,
6677
+ children: branch ? describe(value, root, next) : null,
6540
6678
  readonly: !!node.resolver,
6679
+ parameterEnums: root === "source" ? readParameterEnums(node) : {},
6541
6680
  attrs: Object.entries(node.getAttr()).filter(([name]) => name !== "_meta").map(([name, value2]) => [name, cell(value2)])
6542
6681
  };
6543
6682
  });
6544
6683
  };
6545
6684
  const snapshot = () => ({
6546
- data: describe(bag("data")),
6547
- source: describe(bag("source")),
6685
+ data: describe(bag("data"), "data"),
6686
+ source: describe(bag("source"), "source"),
6548
6687
  breakpoints: [...breakpoints.values()].map(({ test, ...record }) => record)
6549
6688
  });
6550
6689
  const send = (data) => {
@@ -6764,6 +6903,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
6764
6903
  id: row.id,
6765
6904
  revision: row.revision,
6766
6905
  branch,
6906
+ parameterEnums: row.parameterEnums,
6767
6907
  readonly: row.readonly || !!row.value?.readonly,
6768
6908
  readonlyAttrs: new Set(row.attrs.filter(([, descriptor]) => descriptor.readonly).map(([name]) => name)),
6769
6909
  valueWire: JSON.stringify(row.value),
@@ -6793,7 +6933,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
6793
6933
  this.#notify();
6794
6934
  }
6795
6935
  };
6796
- var gramlot_tools_inspector_default = ":host { all: initial; color-scheme: light; font: 12px/1.4 system-ui, sans-serif; color: #38414b; }\n* { box-sizing: border-box; }\nbutton, input, select { font: inherit; color: inherit; }\nbutton { cursor: pointer; }\nbutton:focus-visible, input:focus-visible, select:focus-visible { outline: 1px solid #3574cb; outline-offset: -1px; }\n.tree { padding: 7px 3px; }\n.properties { background: white; }\n.properties-heading { font-size: 11px; display: flex; align-items: center; justify-content: space-between; height: 29px; padding: 0 8px; background: #f1f3f5; color: #6d7989; border-bottom: 1px solid #d1d7df; }\n.properties-heading button { background: white; border: 1px solid #c5cdda; border-radius: 2px; width: 23px; height: 23px; padding: 0; font-size: 18px; line-height: 20px; }\nfieldset { border: 0; margin: 0; padding: 0; min-width: 0; }\n.property-row { display: grid; grid-template-columns: minmax(95px, 30%) minmax(0, 1fr); min-height: 20px; border-bottom: 1px solid #d1d7df; font-size: 11px; }\n.property-name { display: flex; align-items: center; justify-content: flex-end; background: #888; color: white; font-weight: 700; padding: 1px 6px; border-right: 1px solid #d1d7df; overflow-wrap: anywhere; text-align: right; }\n.property-value { display: flex; align-items: center; min-width: 0; }\n.property-row input { border: 0; border-radius: 0; min-width: 0; width: 100%; height: 19px; padding: 1px 5px; background: transparent; }\n.property-name input { color: white; text-align: right; padding: 0; }\n.property-value input { flex: 1; }\n.property-value input[type=checkbox] { flex: none; width: 14px; height: 14px; margin: 2px 6px; }\n.property-value select { max-width: 82px; height: 20px; padding: 0; border: 0; border-left: 1px solid #d1d7df; background: #f1f3f5; font-size: 10px; }\n.remove { margin-left: auto; flex: none; width: 22px; height: 20px; padding: 3px; border: 0; background: transparent; color: #7c8797; opacity: 0; }\n.remove svg { width: 13px; height: 13px; }\n.property-row:hover .remove, .property-row:focus-within .remove { opacity: 1; }\n.remove:hover { color: #b82323; background: #fbe9e9; }\n:disabled { cursor: default; opacity: .65; }\n.path { flex: none; padding: 5px 9px; border-top: 1px solid #c9cfd6; background: #f5f7f9; color: #697687; font-size: 11px; min-height: 27px; overflow-wrap: anywhere; }\n.error, .edit-status, .breakpoint-status, .breakpoint-line { font-size: 11px; margin: 0; padding: 3px 8px; overflow-wrap: anywhere; }\n.error, .edit-status, .breakpoint-status { color: #a12121; }\n.breakpoint-line { background: #fff2ed; color: #854127; border-bottom: 1px solid #d1d7df; }\n.error:empty, .edit-status:empty, .breakpoint-status:empty, .breakpoint-line:empty { display: none; }\n.breakpoint-dialog { width: min(340px, 90vw); color: #38414b; border: 1px solid #bbc3cf; border-radius: 4px; padding: 12px; box-shadow: 0 8px 28px #0003; font: 12px/1.4 system-ui, sans-serif; }\n.breakpoint-dialog::backdrop { background: #0002; }\n.breakpoint-dialog h2 { font-size: 13px; margin: 0 0 10px; overflow-wrap: anywhere; }\n.breakpoint-dialog select, .breakpoint-dialog input { width: 100%; border: 1px solid #bbc3cf; padding: 4px; margin: 0 0 7px; background: white; }\n.dialog-actions { display: flex; gap: 6px; justify-content: flex-end; margin-top: 7px; }\n.dialog-actions button { padding: 3px 10px; border: 1px solid #bbc3cf; border-radius: 3px; background: #f1f3f5; }\n.heading-label { flex: 1; }\n.properties-heading .breakpoint-count { width: auto; padding: 0 5px; margin-right: 5px; font-size: 11px; color: #b04a35; }\n.breakpoint-entry { display: flex; align-items: center; gap: 6px; padding: 4px 0; border-bottom: 1px solid #d1d7df; }\n.breakpoint-entry span { flex: 1; overflow-wrap: anywhere; }\n.breakpoint-entry button { background: transparent; border: 0; font-size: 17px; }\n[hidden] { display: none !important; }\n.targetbar { flex: none; height: 28px; padding: 2px 6px; background: #edf2fa; border-bottom: 1px solid #dadce0; }\n.targetbar select { width: 100%; height: 23px; border: 0; background: transparent; font-size: 11px; }\n.styles-panel { flex: 1; min-height: 0; overflow: auto; background: #fff; font-size: 11px; }\n.styles-toolbar { position: sticky; top: 0; z-index: 1; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding: 6px 8px; background: #f1f3f5; border-bottom: 1px solid #d1d7df; }\n.styles-toolbar span { flex: 1; font-weight: 600; }\n.styles-toolbar button, .styles-toolbar a { padding: 3px 7px; border: 1px solid #c5cdda; border-radius: 3px; background: white; }\n.styles-toolbar a { color: inherit; text-decoration: none; }\n.styles-toolbar a[aria-disabled=true] { cursor: default; opacity: .65; }\n.styles-toolbar a:focus-visible { outline: 1px solid #3574cb; outline-offset: -1px; }\n.styles-help, .styles-empty, .styles-status { margin: 0; padding: 7px 9px; color: #697687; }\n.styles-status { color: #a12121; }\n.styles-status:empty { display: none; }\n.styles-group h3 { margin: 0; padding: 6px 9px; font-size: 11px; background: #edf2fa; border-block: 1px solid #d1d7df; }\n.style-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 25px 23px; align-items: center; gap: 8px; min-width: 0; padding: 3px 9px; border-bottom: 1px solid #e8ebef; }\n.style-row label { min-width: 0; font: 11px/1.4 ui-monospace, monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.style-row input { min-width: 0; width: 100%; height: 23px; padding: 2px 5px; border: 1px solid #c5cdda; border-radius: 3px; background: white; }\n.style-row input[type=color] { width: 25px; padding: 1px; cursor: pointer; }\n.style-row button { grid-column: 4; width: 23px; height: 23px; padding: 0; border: 1px solid #c5cdda; border-radius: 3px; background: #f5f7f9; font-size: 15px; }\n\n:host([embedded]) { display: block; height: 100%; min-height: 0; }\n:host([embedded]) > div { height: 100%; }\n.embedded-panel { display: flex; flex-direction: column; height: 100%; min-height: 0; overflow: hidden; }\n";
6936
+ var gramlot_tools_inspector_default = ":host { all: initial; color-scheme: light; font: 12px/1.4 system-ui, sans-serif; color: #38414b; }\n* { box-sizing: border-box; }\nbutton, input, select { font: inherit; color: inherit; }\nbutton { cursor: pointer; }\nbutton:focus-visible, input:focus-visible, select:focus-visible { outline: 1px solid #3574cb; outline-offset: -1px; }\n.tree { padding: 7px 3px; }\n.properties { background: white; }\n.properties-heading { font-size: 11px; display: flex; align-items: center; justify-content: space-between; height: 29px; padding: 0 8px; background: #f1f3f5; color: #6d7989; border-bottom: 1px solid #d1d7df; }\n.properties-heading button { background: white; border: 1px solid #c5cdda; border-radius: 2px; width: 23px; height: 23px; padding: 0; font-size: 18px; line-height: 20px; }\nfieldset { border: 0; margin: 0; padding: 0; min-width: 0; }\n.property-row { display: grid; grid-template-columns: minmax(95px, 30%) minmax(0, 1fr); min-height: 20px; border-bottom: 1px solid #d1d7df; font-size: 11px; }\n.property-name { display: flex; align-items: center; justify-content: flex-end; background: #888; color: white; font-weight: 700; padding: 1px 6px; border-right: 1px solid #d1d7df; overflow-wrap: anywhere; text-align: right; }\n.property-value { display: flex; align-items: center; min-width: 0; }\n.property-row input { border: 0; border-radius: 0; min-width: 0; width: 100%; height: 19px; padding: 1px 5px; background: transparent; }\n.property-name input { color: white; text-align: right; padding: 0; }\n.property-value input { flex: 1; }\n.property-value input[type=checkbox] { flex: none; width: 14px; height: 14px; margin: 2px 6px; }\n.property-value select { max-width: 82px; height: 20px; padding: 0; border: 0; border-left: 1px solid #d1d7df; background: #f1f3f5; font-size: 10px; }\n.remove { display: inline-flex; align-items: center; justify-content: center; margin-left: auto; flex: none; width: 22px; height: 20px; padding: 3px; border: 0; background: transparent; color: #7c8797; opacity: 0; }\n.remove svg { width: 13px; height: 13px; }\n.property-row:hover .remove, .property-row:focus-within .remove { opacity: 1; }\n.remove:hover { color: #b82323; background: #fbe9e9; }\n:disabled { cursor: default; opacity: .65; }\n.path { flex: none; padding: 5px 9px; border-top: 1px solid #c9cfd6; background: #f5f7f9; color: #697687; font-size: 11px; min-height: 27px; overflow-wrap: anywhere; }\n.error, .edit-status, .breakpoint-status, .breakpoint-line { font-size: 11px; margin: 0; padding: 3px 8px; overflow-wrap: anywhere; }\n.error, .edit-status, .breakpoint-status { color: #a12121; }\n.breakpoint-line { background: #fff2ed; color: #854127; border-bottom: 1px solid #d1d7df; }\n.error:empty, .edit-status:empty, .breakpoint-status:empty, .breakpoint-line:empty { display: none; }\n.breakpoint-dialog { width: min(340px, 90vw); color: #38414b; border: 1px solid #bbc3cf; border-radius: 4px; padding: 12px; box-shadow: 0 8px 28px #0003; font: 12px/1.4 system-ui, sans-serif; }\n.breakpoint-dialog::backdrop { background: #0002; }\n.breakpoint-dialog h2 { font-size: 13px; margin: 0 0 10px; overflow-wrap: anywhere; }\n.breakpoint-dialog select, .breakpoint-dialog input { width: 100%; border: 1px solid #bbc3cf; padding: 4px; margin: 0 0 7px; background: white; }\n.dialog-actions { display: flex; gap: 6px; justify-content: flex-end; margin-top: 7px; }\n.dialog-actions button { padding: 3px 10px; border: 1px solid #bbc3cf; border-radius: 3px; background: #f1f3f5; }\n.heading-label { flex: 1; }\n.properties-heading .breakpoint-count { width: auto; padding: 0 5px; margin-right: 5px; font-size: 11px; color: #b04a35; }\n.breakpoint-entry { display: flex; align-items: center; gap: 6px; padding: 4px 0; border-bottom: 1px solid #d1d7df; }\n.breakpoint-entry span { flex: 1; overflow-wrap: anywhere; }\n.breakpoint-entry button { background: transparent; border: 0; font-size: 17px; }\n[hidden] { display: none !important; }\n.targetbar { flex: none; height: 28px; padding: 2px 6px; background: #edf2fa; border-bottom: 1px solid #dadce0; }\n.targetbar select { width: 100%; height: 23px; border: 0; background: transparent; font-size: 11px; }\n.styles-panel { flex: 1; min-height: 0; overflow: auto; background: #fff; font-size: 11px; }\n.styles-toolbar { position: sticky; top: 0; z-index: 1; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding: 6px 8px; background: #f1f3f5; border-bottom: 1px solid #d1d7df; }\n.styles-toolbar span { flex: 1; font-weight: 600; }\n.styles-toolbar button, .styles-toolbar a { padding: 3px 7px; border: 1px solid #c5cdda; border-radius: 3px; background: white; }\n.styles-toolbar a { color: inherit; text-decoration: none; }\n.styles-toolbar a[aria-disabled=true] { cursor: default; opacity: .65; }\n.styles-toolbar a:focus-visible { outline: 1px solid #3574cb; outline-offset: -1px; }\n.styles-help, .styles-empty, .styles-status { margin: 0; padding: 7px 9px; color: #697687; }\n.styles-status { color: #a12121; }\n.styles-status:empty { display: none; }\n.styles-group h3 { margin: 0; padding: 6px 9px; font-size: 11px; background: #edf2fa; border-block: 1px solid #d1d7df; }\n.style-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 25px 23px; align-items: center; gap: 8px; min-width: 0; padding: 3px 9px; border-bottom: 1px solid #e8ebef; }\n.style-row label { min-width: 0; font: 11px/1.4 ui-monospace, monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.style-row input { min-width: 0; width: 100%; height: 23px; padding: 2px 5px; border: 1px solid #c5cdda; border-radius: 3px; background: white; }\n.style-row input[type=color] { width: 25px; padding: 1px; cursor: pointer; }\n.style-row button { grid-column: 4; width: 23px; height: 23px; padding: 0; border: 1px solid #c5cdda; border-radius: 3px; background: #f5f7f9; font-size: 15px; }\n\n:host([embedded]) { display: block; height: 100%; min-height: 0; }\n:host([embedded]) > div { height: 100%; }\n.embedded-panel { display: flex; flex-direction: column; height: 100%; min-height: 0; overflow: hidden; }\n\n.property-value select.enum-value { flex: 1; min-width: 0; max-width: none; width: 100%; border: 0; background: white; font: inherit; padding: 1px 5px; }\n";
6797
6937
  var gramlot_poc_tree_default = "/* Copyright 2025-2026 Softwell S.r.l. - SPDX-License-Identifier: Apache-2.0\n * Inspector subset of the DevTools storeTree stylesheet and inspector.css variables. */\n:host { display:block; font:11px/18px -apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif; color:#38414b; }\n:host([hidden]) { display:none; }\nul { list-style:none; margin:0; padding-left:17px; }\n.tree-root { padding-left:16px; }\n.tree-root > ul { padding-left:2px; }\nsummary, .leaf { position:relative; }\nli { line-height:18px; }\nsummary { display:flex; align-items:center; gap:7px; padding:0 5px; cursor:pointer; user-select:none; list-style:none; }\nsummary::-webkit-details-marker { display:none; }\nsummary::before { content:''; width:5px; height:5px; border-right:1.5px solid #78818a; border-bottom:1.5px solid #78818a; transform:rotate(-45deg); flex:none; margin:0 3px; }\ndetails[open] > summary::before { transform:rotate(45deg); }\n.leaf { display:flex; align-items:center; gap:7px; padding:0 5px 0 23px; cursor:pointer; }\nsummary:hover,.leaf:hover { background:#f0f3f6; }\n.selected,.selected:hover { background:transparent; color:#315dbd; font-weight:700; border-radius:2px; }\n.caption { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n/* Reserve a left gutter; showing an action must not shift the node label. */\n.actions { position:absolute; left:-14px; top:0; display:inline-flex; opacity:0; pointer-events:none; }\nsummary:hover > .actions,.leaf:hover > .actions,summary:focus-visible > .actions,.leaf:focus-visible > .actions,\n.actions:has(button:focus-visible),.actions:has(button.active) { opacity:1; pointer-events:auto; }\n.actions button { border:0; background:transparent; color:#80868b; font:inherit; font-size:11px; line-height:18px; width:14px; height:18px; padding:0; cursor:pointer; border-radius:3px; }\n.actions button:hover { background:#e1e5ed; }\n.actions button[data-action=breakpoint] { font-size:0; }\n.actions button[data-action=breakpoint]::before { content:''; display:inline-block; box-sizing:border-box; width:8px; height:8px; border:1.5px solid currentColor; border-radius:50%; vertical-align:middle; }\n.actions button.active { color:#b3261e; }\n.actions button.active.conditional { color:#f9ab00; }\n.actions button.active[data-action=breakpoint]::before { background:currentColor; }\n.actions button:focus-visible,summary:focus-visible,.leaf:focus-visible { outline:2px solid #356f9f; outline-offset:-2px; }\n";
6798
6938
  var sequence = 0;
6799
6939
  var GramlotPocTree = class extends HTMLElement {
@@ -7243,6 +7383,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
7243
7383
  ui.data.setItem("editor.dirty", true);
7244
7384
  ui.data.setItem("editor.status", "Unsaved changes");
7245
7385
  }
7386
+ enumChanged(node) {
7387
+ this.editChanged(node);
7388
+ inspector.#applyEdit();
7389
+ }
7246
7390
  typeChanged(node) {
7247
7391
  const row = ui.data.getItem(`editor.rows.${node.getAttr("data-row")}`);
7248
7392
  row.setItem("inputType", inspector.#inputType(row.getItem("type")));
@@ -7429,7 +7573,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
7429
7573
  const targetbar = palette.div({ node_label: "targetbar", class: "targetbar", hidden: "^singleTarget" });
7430
7574
  targetbar.select({ node_label: "targets", value: "^targetId", disabled: "^busy", "aria-label": "Inspected page", connect_onchange: "inspector.selectTarget" });
7431
7575
  const toolbar = palette.webcomponent({ code: "gramlot-poc-tabs", node_label: "tabs", role: "tablist", "aria-label": "Inspected root" });
7432
- for (const name of ["Data", "Source", "Styles"]) toolbar.button(name, {
7576
+ for (const name of ["Data", "Source", "Styles"]) toolbar.html_button(name, {
7433
7577
  node_label: name.toLowerCase(),
7434
7578
  type: "button",
7435
7579
  role: "tab",
@@ -7451,7 +7595,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
7451
7595
  const properties = content.section({ node_label: "properties", slot: "bottom", class: "properties", "aria-label": "Selected node properties" });
7452
7596
  const heading = properties.div({ class: "properties-heading" });
7453
7597
  heading.span("Properties", { class: "heading-label" });
7454
- heading.button("^breakpointCount", {
7598
+ heading.html_button("^breakpointCount", {
7455
7599
  type: "button",
7456
7600
  class: "breakpoint-count",
7457
7601
  hidden: "^noBreakpoints",
@@ -7459,7 +7603,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
7459
7603
  title: "Active breakpoints",
7460
7604
  connect_onclick: "inspector.showBreakpoints"
7461
7605
  });
7462
- heading.button("+", {
7606
+ heading.html_button("+", {
7463
7607
  type: "button",
7464
7608
  "aria-label": "Add attribute",
7465
7609
  title: "Add attribute",
@@ -7475,8 +7619,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
7475
7619
  const styles = palette.section({ node_label: "styles", class: "styles-panel", hidden: "^treeActive", "aria-label": "CSS variables" });
7476
7620
  const stylebar = styles.div({ class: "styles-toolbar" });
7477
7621
  stylebar.span("Document variables");
7478
- stylebar.button("Refresh", { type: "button", disabled: "^styles.busy", connect_onclick: "inspector.refreshStyles" });
7479
- stylebar.button("Reset all", { type: "button", disabled: "^styles.noChanges", connect_onclick: "inspector.resetStyles" });
7622
+ stylebar.html_button("Refresh", { type: "button", disabled: "^styles.busy", connect_onclick: "inspector.refreshStyles" });
7623
+ stylebar.html_button("Reset all", { type: "button", disabled: "^styles.noChanges", connect_onclick: "inspector.resetStyles" });
7480
7624
  stylebar.a("Download CSS", { href: "^styles.downloadUrl", download: "theme-overrides.css", "aria-disabled": "^styles.noDownload" });
7481
7625
  styles.p("Temporary preview \xB7 Enter or leave a field to apply. Closing the connection clears previews.", { class: "styles-help" });
7482
7626
  styles.p("^styles.status", { role: "status", class: "styles-status" });
@@ -7492,12 +7636,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
7492
7636
  breakpoint.input({ value: "^editor.condition", live: true, connect_oninput: "inspector.breakpointChanged", "aria-label": "Breakpoint condition", placeholder: "Condition (optional)" });
7493
7637
  breakpoint.p("^breakpointStatus", { role: "status", class: "breakpoint-status" });
7494
7638
  const actions = breakpoint.div({ class: "dialog-actions" });
7495
- actions.button("Cancel", { type: "button", connect_onclick: "inspector.closeBreakpoint" });
7496
- actions.button("Save", { type: "button", connect_onclick: "inspector.setBreakpoint" });
7639
+ actions.html_button("Cancel", { type: "button", connect_onclick: "inspector.closeBreakpoint" });
7640
+ actions.html_button("Save", { type: "button", connect_onclick: "inspector.setBreakpoint" });
7497
7641
  const list = palette.dialog({ node_label: "breakpoints", "aria-label": "Active breakpoints", class: "breakpoint-dialog" });
7498
7642
  list.h2("Active breakpoints");
7499
7643
  list.div({ node_label: "entries" });
7500
- list.div({ class: "dialog-actions" }).button("Close", { type: "button", connect_onclick: "inspector.closeBreakpoints" });
7644
+ list.div({ class: "dialog-actions" }).html_button("Close", { type: "button", connect_onclick: "inspector.closeBreakpoints" });
7501
7645
  ui.src.startSource(builder.source);
7502
7646
  for (const name of ["data", "source"]) this.#trees[name] = ui.dom.getDomNode(ui.src.source.getNode(`main.palette.content.tree.${name}`));
7503
7647
  this.#renderTargets();
@@ -7714,7 +7858,7 @@ ${declarations}
7714
7858
  "data-field": "color",
7715
7859
  connect_onchange: "inspector.setStyle"
7716
7860
  });
7717
- row.button("\u21B6", {
7861
+ row.html_button("\u21B6", {
7718
7862
  type: "button",
7719
7863
  "aria-label": `Reset ${record.name}`,
7720
7864
  title: "Reset variable",
@@ -7784,6 +7928,7 @@ ${declarations}
7784
7928
  this.#snapshot = entry ? {
7785
7929
  node: entry.node,
7786
7930
  value: entry.node.getValue(true),
7931
+ parameterEnums: ui.data.getItem("root") !== "source" ? {} : this.#connection ? this.#connection.nodeInfo(entry.node).parameterEnums : readParameterEnums(entry.node),
7787
7932
  attrs: { ...entry.node.getAttr() },
7788
7933
  resolver: entry.node.resolver,
7789
7934
  revision: this.#connection?.nodeInfo(entry.node)?.revision
@@ -7821,7 +7966,20 @@ ${declarations}
7821
7966
  if (fresh) label.input({ value: "^.name", live: true, "aria-label": "New attribute name", "data-row": row.label, connect_oninput: "inspector.editChanged" });
7822
7967
  else label.span(name);
7823
7968
  const cell = line.div({ class: "property-value" });
7824
- cell.input({
7969
+ const choices = !primary && this.#snapshot.parameterEnums[name];
7970
+ const value = data.getItem("text");
7971
+ if (choices && choices.includes(value)) {
7972
+ const select = cell.select({
7973
+ value: "^.text",
7974
+ class: "enum-value",
7975
+ disabled: locked,
7976
+ "aria-label": `${name} value`,
7977
+ "data-row": row.label,
7978
+ connect_onchange: "inspector.enumChanged",
7979
+ connect_onkeydown: "inspector.editKey"
7980
+ });
7981
+ for (const choice of choices) select.option(choice, { value: choice });
7982
+ } else cell.input({
7825
7983
  value: "^.text",
7826
7984
  type: "^.inputType",
7827
7985
  live: true,
@@ -7835,10 +7993,10 @@ ${declarations}
7835
7993
  });
7836
7994
  if (fresh) {
7837
7995
  const type = cell.select({ value: "^.type", "aria-label": "New attribute type", "data-row": row.label, connect_onchange: "inspector.typeChanged" });
7838
- for (const value of editorTypes) type.option(value, { value });
7996
+ for (const value2 of editorTypes) type.option(value2, { value: value2 });
7839
7997
  }
7840
7998
  if (!primary) {
7841
- const button = cell.button({
7999
+ const button = cell.html_button({
7842
8000
  type: "button",
7843
8001
  disabled: locked,
7844
8002
  "aria-label": `Remove ${name || "new attribute"}`,
@@ -7874,6 +8032,7 @@ ${declarations}
7874
8032
  this.#loadEditor(this.#selected());
7875
8033
  } else {
7876
8034
  this.#snapshot = {
8035
+ ...this.#snapshot,
7877
8036
  node: target,
7878
8037
  value: target.getValue(true),
7879
8038
  attrs: { ...target.getAttr() },
@@ -8033,7 +8192,7 @@ ${declarations}
8033
8192
  const config = node.value;
8034
8193
  const row = builder.root.div({ class: "breakpoint-entry" });
8035
8194
  row.span(`${config.getItem("root")}: ${config.getItem("path")} \xB7 ${config.getItem("mode")} \xB7 ${config.getItem("hits")} hits`);
8036
- row.button("\xD7", {
8195
+ row.html_button("\xD7", {
8037
8196
  type: "button",
8038
8197
  "aria-label": `Remove breakpoint ${config.getItem("root")}: ${config.getItem("path")}`,
8039
8198
  "data-breakpoint": node.label,