derico.blicca.promoblock 1.0.0a1__tar.gz

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 (121) hide show
  1. derico_blicca_promoblock-1.0.0a1/.copier-answers.yml +14 -0
  2. derico_blicca_promoblock-1.0.0a1/.editorconfig +21 -0
  3. derico_blicca_promoblock-1.0.0a1/.github/workflows/ci.yml +120 -0
  4. derico_blicca_promoblock-1.0.0a1/.gitignore +97 -0
  5. derico_blicca_promoblock-1.0.0a1/.pre-commit-config.yaml +14 -0
  6. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/01-research-image-widget-in-both-hosts.md +181 -0
  7. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/02-research-exercising-native-aurora.md +182 -0
  8. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/03-decide-content-model-and-schema.md +571 -0
  9. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/04-decide-the-theme-seam.md +266 -0
  10. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/05-scaffold-the-package.md +126 -0
  11. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/06-build-the-js-workspace.md +166 -0
  12. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/07-build-the-two-widgets.md +163 -0
  13. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/08-build-editor-half.md +247 -0
  14. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/09-build-server-half.md +226 -0
  15. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/10-build-image-transformer.md +153 -0
  16. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/11-build-the-stylesheet.md +340 -0
  17. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/12-build-registration.md +139 -0
  18. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/13-verify-reference-case-imageless.md +186 -0
  19. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/14-verify-reference-case-image-left.md +221 -0
  20. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/15-verify-native-aurora.md +245 -0
  21. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/16-derico-token-line.md +244 -0
  22. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/17-decide-anatomy-classes.md +301 -0
  23. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/18-publish-and-pin-mx-prod.md +108 -0
  24. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/19-decide-canvas-image-freshness.md +100 -0
  25. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/20-decide-promo-title-scale-axis.md +150 -0
  26. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/21-build-derived-key-provenance.md +179 -0
  27. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/issues/22-verify-canvas-freshness-live.md +134 -0
  28. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/map.md +787 -0
  29. derico_blicca_promoblock-1.0.0a1/.scratch/promo-block/ticket22-canvas-freshness.png +0 -0
  30. derico_blicca_promoblock-1.0.0a1/CHANGELOG.md +21 -0
  31. derico_blicca_promoblock-1.0.0a1/CONTEXT.md +117 -0
  32. derico_blicca_promoblock-1.0.0a1/PKG-INFO +359 -0
  33. derico_blicca_promoblock-1.0.0a1/README.md +326 -0
  34. derico_blicca_promoblock-1.0.0a1/bundle-src/.nvmrc +1 -0
  35. derico_blicca_promoblock-1.0.0a1/bundle-src/README.md +98 -0
  36. derico_blicca_promoblock-1.0.0a1/bundle-src/build-plugins/scope-wrap.ts +106 -0
  37. derico_blicca_promoblock-1.0.0a1/bundle-src/package.json +51 -0
  38. derico_blicca_promoblock-1.0.0a1/bundle-src/pnpm-lock.yaml +7251 -0
  39. derico_blicca_promoblock-1.0.0a1/bundle-src/pnpm-workspace.yaml +4 -0
  40. derico_blicca_promoblock-1.0.0a1/bundle-src/src/index.tsx +56 -0
  41. derico_blicca_promoblock-1.0.0a1/bundle-src/src/promo/PromoEdit.tsx +49 -0
  42. derico_blicca_promoblock-1.0.0a1/bundle-src/src/promo/PromoIcon.tsx +28 -0
  43. derico_blicca_promoblock-1.0.0a1/bundle-src/src/promo/PromoView.tsx +128 -0
  44. derico_blicca_promoblock-1.0.0a1/bundle-src/src/promo/data.ts +378 -0
  45. derico_blicca_promoblock-1.0.0a1/bundle-src/src/promo/schema.ts +215 -0
  46. derico_blicca_promoblock-1.0.0a1/bundle-src/src/styles.css +359 -0
  47. derico_blicca_promoblock-1.0.0a1/bundle-src/src/widgets/ImageWidget.tsx +144 -0
  48. derico_blicca_promoblock-1.0.0a1/bundle-src/src/widgets/LinkWidget.tsx +178 -0
  49. derico_blicca_promoblock-1.0.0a1/bundle-src/src/widgets/SelectWidget.tsx +90 -0
  50. derico_blicca_promoblock-1.0.0a1/bundle-src/src/widgets/TextareaWidget.tsx +79 -0
  51. derico_blicca_promoblock-1.0.0a1/bundle-src/src/widgets/field-shell.tsx +81 -0
  52. derico_blicca_promoblock-1.0.0a1/bundle-src/src/widgets/index.ts +55 -0
  53. derico_blicca_promoblock-1.0.0a1/bundle-src/test/aurora-harness.test.tsx +501 -0
  54. derico_blicca_promoblock-1.0.0a1/bundle-src/test/aurora-packages.d.ts +59 -0
  55. derico_blicca_promoblock-1.0.0a1/bundle-src/test/promo-anatomy.test.tsx +465 -0
  56. derico_blicca_promoblock-1.0.0a1/bundle-src/test/promo-edit.test.tsx +194 -0
  57. derico_blicca_promoblock-1.0.0a1/bundle-src/test/promo-schema.test.ts +335 -0
  58. derico_blicca_promoblock-1.0.0a1/bundle-src/test/promo-screen.test.ts +84 -0
  59. derico_blicca_promoblock-1.0.0a1/bundle-src/test/scope-wrap.test.ts +43 -0
  60. derico_blicca_promoblock-1.0.0a1/bundle-src/test/seam-lockstep.test.ts +177 -0
  61. derico_blicca_promoblock-1.0.0a1/bundle-src/test/sheet-selectors.test.tsx +122 -0
  62. derico_blicca_promoblock-1.0.0a1/bundle-src/test/upstream-registry.ts +198 -0
  63. derico_blicca_promoblock-1.0.0a1/bundle-src/test/widgets.test.tsx +517 -0
  64. derico_blicca_promoblock-1.0.0a1/bundle-src/test/workspace.test.tsx +88 -0
  65. derico_blicca_promoblock-1.0.0a1/bundle-src/tsconfig.json +49 -0
  66. derico_blicca_promoblock-1.0.0a1/bundle-src/vite.config.ts +88 -0
  67. derico_blicca_promoblock-1.0.0a1/bundle-src/vitest.config.ts +29 -0
  68. derico_blicca_promoblock-1.0.0a1/docs/adr/0001-the-promo-is-authored-not-referential.md +150 -0
  69. derico_blicca_promoblock-1.0.0a1/docs/adr/0002-seam-defaults-live-at-their-point-of-use.md +110 -0
  70. derico_blicca_promoblock-1.0.0a1/docs/adr/0003-derived-keys-are-the-servers-and-carry-their-provenance.md +102 -0
  71. derico_blicca_promoblock-1.0.0a1/docs/adr/0004-the-image-field-keeps-its-name-and-gains-a-clear-action.md +70 -0
  72. derico_blicca_promoblock-1.0.0a1/pyproject.toml +127 -0
  73. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/__init__.py +1 -0
  74. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/blocks.py +12 -0
  75. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/configure.zcml +86 -0
  76. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/i18n.py +6 -0
  77. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/image_transform.py +220 -0
  78. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/interfaces.py +7 -0
  79. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/locales/README.rst +37 -0
  80. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/locales/__init__.py +0 -0
  81. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/locales/derico.blicca.promoblock.pot +16 -0
  82. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/locales/en/LC_MESSAGES/derico.blicca.promoblock.po +15 -0
  83. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/locales/update.py +68 -0
  84. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/locales/update.sh +12 -0
  85. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/permissions.zcml +11 -0
  86. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/picture.py +109 -0
  87. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/profiles/default/browserlayer.xml +7 -0
  88. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/profiles/default/catalog.xml +5 -0
  89. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/profiles/default/metadata.xml +7 -0
  90. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/profiles/default/registry.xml +65 -0
  91. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/profiles/default/rolemap.xml +7 -0
  92. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/profiles/uninstall/browserlayer.xml +7 -0
  93. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/profiles/uninstall/metadata.xml +4 -0
  94. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/profiles/uninstall/registry.xml +20 -0
  95. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/promo_data.py +183 -0
  96. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/setuphandlers.py +29 -0
  97. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/static/promo-block.css +284 -0
  98. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/static/promo-block.js +580 -0
  99. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/static/promo-block.js.map +1 -0
  100. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/testing.py +55 -0
  101. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/tests/__init__.py +0 -0
  102. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/tests/conftest.py +14 -0
  103. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/tests/test_image_transform.py +397 -0
  104. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/tests/test_picture.py +48 -0
  105. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/tests/test_promo_data.py +291 -0
  106. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/tests/test_reference_case_band.py +244 -0
  107. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/tests/test_reference_case_image.py +437 -0
  108. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/tests/test_setup.py +129 -0
  109. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/tests/test_upgrade_step_1001.py +193 -0
  110. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/tests/test_view_promo_block_view.py +619 -0
  111. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/upgrades/1001/metadata.txt +1 -0
  112. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/upgrades/1001/registry.xml +65 -0
  113. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/upgrades/1001.zcml +46 -0
  114. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/upgrades/__init__.py +1 -0
  115. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/upgrades/configure.zcml +8 -0
  116. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/views/__init__.py +1 -0
  117. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/views/configure.zcml +27 -0
  118. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/views/promo_block_view.pt +80 -0
  119. derico_blicca_promoblock-1.0.0a1/src/derico/blicca/promoblock/views/promo_block_view.py +188 -0
  120. derico_blicca_promoblock-1.0.0a1/tests/anatomy-cases.json +342 -0
  121. derico_blicca_promoblock-1.0.0a1/uv.lock +6702 -0
@@ -0,0 +1,14 @@
1
+ # Do not edit this file manually.
2
+ # This file is auto-generated by Copier.
3
+ # Changes here will be overwritten when you update the template.
4
+ _src_path: /home/dev/.copier-templates/plone-copier-templates/backend_addon
5
+ author_email: md@derico.de
6
+ author_name: Maik Derstappen
7
+ github_organization: derico-de
8
+ is_headless: false
9
+ package_description: 'Aurora Promo block: an authored promo card with kicker, title,
10
+ description, image and calls to action'
11
+ package_name: derico.blicca.promoblock
12
+ package_title: Derico Blicca Promoblock
13
+ plone_version: '6.0'
14
+
@@ -0,0 +1,21 @@
1
+ [*]
2
+ charset = utf-8
3
+ end_of_line = lf
4
+ indent_style = space
5
+ insert_final_newline = true
6
+ trim_trailing_whitespace = true
7
+
8
+ [*.py]
9
+ indent_size = 4
10
+
11
+ [*.{cfg,ini,toml}]
12
+ indent_size = 4
13
+
14
+ [*.{xml,zcml,html,pt,zpt}]
15
+ indent_size = 2
16
+
17
+ [*.{css,js,json}]
18
+ indent_size = 2
19
+
20
+ [*.{yml,yaml}]
21
+ indent_size = 2
@@ -0,0 +1,120 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+ branches: [main, master]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ env:
16
+ BLICCA_SSH_KEY: ${{ secrets.BLICCA_SSH_KEY }}
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ python-version: ["3.10", "3.11", "3.12"]
21
+
22
+ steps:
23
+ # plone.blicca.auroraeditor is PRIVATE and not on PyPI: it is the editor
24
+ # this block mounts in and the source of the rendering API the package
25
+ # imports, so without it nothing installs and nothing is tested. A
26
+ # missing key is a red job on purpose — a green run over a package
27
+ # that could not be installed says nothing. Use a read-only deploy key
28
+ # scoped to the host repository, not a personal access token.
29
+ - name: Require the host checkout key
30
+ if: env.BLICCA_SSH_KEY == ''
31
+ run: |
32
+ echo "::error::BLICCA_SSH_KEY is not set. This package depends on"
33
+ echo "::error::plone.blicca.auroraeditor, which is private and not"
34
+ echo "::error::on PyPI, so the tests cannot run."
35
+ exit 1
36
+
37
+ # pyproject resolves the sources below from `../<name>`, so this
38
+ # repository checks itself out into a subdirectory and its siblings land
39
+ # beside it, exactly as they sit under the site's `sources/`.
40
+ - uses: actions/checkout@v5
41
+ with:
42
+ path: derico.blicca.promoblock
43
+
44
+ - uses: actions/checkout@v5
45
+ with:
46
+ repository: derico-de/plone.blicca.auroraeditor
47
+ ssh-key: ${{ env.BLICCA_SSH_KEY }}
48
+ persist-credentials: false
49
+ path: plone.blicca.auroraeditor
50
+
51
+ - name: Set up uv and Python ${{ matrix.python-version }}
52
+ uses: astral-sh/setup-uv@v10.0.1
53
+ with:
54
+ enable-cache: true
55
+ python-version: ${{ matrix.python-version }}
56
+
57
+ - name: Run tests
58
+ working-directory: derico.blicca.promoblock
59
+ run: uv run --frozen --extra test pytest -v
60
+
61
+ lint:
62
+ runs-on: ubuntu-latest
63
+ steps:
64
+ - uses: actions/checkout@v5
65
+
66
+ - name: Set up uv
67
+ uses: astral-sh/setup-uv@v10.0.1
68
+ with:
69
+ enable-cache: true
70
+
71
+ - name: Run ruff
72
+ run: uvx ruff@0.16.6 check .
73
+
74
+ bundle:
75
+ # The editor half is committed build output — there is no Node on the
76
+ # deploy host (block add-on contract §3.1) — so nothing rebuilds it at
77
+ # install time and it rots the moment someone edits bundle-src/src/ and
78
+ # forgets. The `git diff --exit-code` below is what makes committing an
79
+ # artifact safe rather than merely convenient.
80
+ runs-on: ubuntu-latest
81
+ steps:
82
+ - uses: actions/checkout@v5
83
+
84
+ # pnpm is pinned here rather than by a `packageManager` field in
85
+ # bundle-src/package.json: pnpm 12 answers that field by writing a
86
+ # `packageManagerDependencies` block into the lockfile — its own binary
87
+ # for every platform — and the lockfile is not the place for that.
88
+ - uses: pnpm/action-setup@v4
89
+ with:
90
+ version: 12.3.4
91
+
92
+ - name: Set up Node
93
+ uses: actions/setup-node@v4
94
+ with:
95
+ node-version-file: bundle-src/.nvmrc
96
+ cache: pnpm
97
+ cache-dependency-path: bundle-src/pnpm-lock.yaml
98
+
99
+ # `working-directory`, not `--dir`: the repository root has no
100
+ # package.json, and pnpm resolves the workspace from where it stands.
101
+ - name: Install
102
+ run: pnpm install --frozen-lockfile
103
+ working-directory: bundle-src
104
+
105
+ - name: Typecheck
106
+ run: pnpm typecheck
107
+ working-directory: bundle-src
108
+
109
+ - name: Build
110
+ run: pnpm build
111
+ working-directory: bundle-src
112
+
113
+ # After the build: the harness reads the built artifact.
114
+ - name: Test
115
+ run: pnpm test
116
+ working-directory: bundle-src
117
+
118
+ # If this fails, someone edited bundle-src/src/ and did not rebuild.
119
+ - name: The committed bundle is the one this source builds
120
+ run: git diff --exit-code -- src/derico/blicca/promoblock/static/
@@ -0,0 +1,97 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ wheels/
22
+ *.egg-info/
23
+ .installed.cfg
24
+ *.egg
25
+
26
+ # PyInstaller
27
+ *.manifest
28
+ *.spec
29
+
30
+ # Installer logs
31
+ pip-log.txt
32
+ pip-delete-this-directory.txt
33
+
34
+ # Unit test / coverage reports
35
+ htmlcov/
36
+ .tox/
37
+ .nox/
38
+ .coverage
39
+ .coverage.*
40
+ .cache
41
+ nosetests.xml
42
+ coverage.xml
43
+ *.cover
44
+ *.py,cover
45
+ .hypothesis/
46
+ .pytest_cache/
47
+
48
+ # Type checkers / linters
49
+ .mypy_cache/
50
+ .pyre/
51
+ .pytype/
52
+ .ruff_cache/
53
+
54
+ # Translations (compiled catalogs are generated; .pot/.po are tracked)
55
+ *.mo
56
+
57
+ # Environments
58
+ .env
59
+ .venv
60
+ env/
61
+ venv/
62
+ ENV/
63
+ env.bak/
64
+ venv.bak/
65
+
66
+ # IDEs / editors
67
+ .idea/
68
+ .vscode/
69
+ *.swp
70
+ *.swo
71
+ *~
72
+
73
+ # Node / frontend tooling (themes, mockup patterns, svelte apps)
74
+ node_modules/
75
+ npm-debug.log*
76
+ yarn-debug.log*
77
+ yarn-error.log*
78
+ pnpm-debug.log*
79
+ .pnpm-store/
80
+ .parcel-cache/
81
+ .vite/
82
+
83
+ # Build outputs from frontend tooling (in addition to top-level dist/)
84
+ src/derico/blicca/promoblock/**/dist/
85
+ src/derico/blicca/promoblock/**/.cache/
86
+
87
+ # Plone / Zope runtime data
88
+ *.fs
89
+ *.fs.index
90
+ *.fs.lock
91
+ *.fs.tmp
92
+ blobs/
93
+
94
+ # Project specific
95
+ *.log
96
+ .DS_Store
97
+ Thumbs.db
@@ -0,0 +1,14 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v4.5.0
4
+ hooks:
5
+ - id: check-yaml
6
+ - id: end-of-file-fixer
7
+ - id: trailing-whitespace
8
+ - id: check-merge-conflict
9
+ - repo: https://github.com/astral-sh/ruff-pre-commit
10
+ rev: v0.3.0
11
+ hooks:
12
+ - id: ruff
13
+ args: [--fix]
14
+ - id: ruff-format
@@ -0,0 +1,181 @@
1
+ # Research: does the host `image` widget behave in both hosts?
2
+
3
+ Type: research
4
+ Status: resolved
5
+ Blocked by: —
6
+
7
+ ## Question
8
+
9
+ The map fixes the image field as **named `image`, taking the host's own widget
10
+ through field-id resolution**. That is a deliberate inversion of `derico-hero`'s
11
+ rule and the single largest assumption in the content model. Confirm or break it
12
+ before ticket 03 writes the schema.
13
+
14
+ Read, don't guess. Sources: `@plone/cmsui/components/Form/Field.tsx` (resolution
15
+ order), `@plone/cmsui/components/ImageWidget/ImageWidget.tsx` (upstream),
16
+ `plone.blicca.auroraeditor/wrapper/src/widgets/ImageWidget.tsx` (the Blicca
17
+ substitute), `@plone/blocks/Image/schema.tsx` (how Aurora's own image block
18
+ declares its field).
19
+
20
+ - **Resolution.** Confirm `getWidgetByFieldId('image')` really wins over an
21
+ explicit `widget:` key, and that both hosts register under exactly `image`.
22
+ If Blicca registers under a different key or category, the whole approach
23
+ falls over.
24
+ - **Stored shape.** Upstream calls `onValueChange(result['@id'], extras)` — an
25
+ absolute `@id` string. Blicca writes `../resolveuid/${item.UID}` — a relative
26
+ path string. Same type, different form. Confirm both, and confirm neither ever
27
+ writes an array or an object, because the view and the template must accept
28
+ whatever comes.
29
+ - **`image_scales` / `image_field`.** Upstream passes them as `extras` to
30
+ `onChange`, but Aurora's `dataAdapter` hook is **vestigial** (zero consumers),
31
+ so nothing may be catching them. Determine whether either host persists them
32
+ at all. If neither does, ticket 10's transformer is the only source and that
33
+ is fine — but it must be known, not assumed.
34
+ - **`widgetOptions.pattern_options`.** Contract §1.5 says `selectableTypes` and
35
+ `upload` are read. Check whether the *host image widget* honours them, or only
36
+ `object_browser` does. If it ignores them, we lose "restrict to Image" and
37
+ need to decide whether that matters.
38
+ - **The fallback.** If any of the above breaks, the alternative is the teaser's
39
+ idiom — `object_browser`, `mode: 'single'`, `selectableTypes: ['Image']`,
40
+ `upload: true`, under a field name that is *not* `image`. Say which, and what
41
+ it costs in native Aurora (where the Blicca upload substitution is absent).
42
+
43
+ ## Answer
44
+
45
+ **Verdict: the assumption holds. Name the field `image` and it gets the host's
46
+ own image widget in both hosts.** Every sub-question below was read off the
47
+ source, not inferred. Two corrections to the map's reasoning and one new
48
+ cross-host divergence came out of it.
49
+
50
+ ### 1. Resolution — confirmed, but for a different reason than the map assumed
51
+
52
+ `components/Form/Field.tsx` (`renderFieldWidget`) resolves in this order:
53
+
54
+ getWidgetByFieldId(id ?? name) <-- FIRST, unconditional
55
+ getWidgetFromTaggedValues(...)
56
+ getWidgetByName(widget) <-- an explicit `widget:` key only gets here
57
+ getWidgetByChoices / ByVocabulary / ByVocabularyFromHint / ByFactory / ByType
58
+ getWidgetDefault()
59
+
60
+ So yes — **field-id beats an explicit `widget:` key**, and a field named `image`
61
+ can never have that resolution overridden from the schema.
62
+
63
+ The key that resolution uses is the **schema property key**.
64
+ `BlockSettingsFormRenderer.tsx` renders each field as
65
+ `<field.Quanta {...schema.properties[key]} name={field.name} ... />` and passes
66
+ no `id`, so `id ?? name` is the property key. Blicca imports that exact
67
+ component (`plone-block-sidebar.tsx:14` imports upstream's `BlockSettingsForm`),
68
+ so **the resolution path is byte-identical in both hosts** — there is no Blicca
69
+ fork to diverge.
70
+
71
+ **Correction to the map's stated mechanism.** The map says both hosts register
72
+ `image` and implies category matters. It does not: `config.getWidget(key)`
73
+ (`@plone/registry/dist/index.js:397`) **iterates every category and returns the
74
+ first match by key**, so `id`/`widget`/`type`/`vocabulary`/`factory` are
75
+ effectively one flat namespace. Both hosts in fact register `image` under
76
+ category **`widget`**, not `id`:
77
+
78
+ - upstream `cmsui/config/widgets.ts:41` — `{key:'widget', definition:{image: ImageWidget}}`
79
+ - Blicca `wrapper/src/bootstrap/config.ts:47` — `{key:'widget', definition:{image: BliccaImageWidget}}`
80
+
81
+ Field-id resolution finds them anyway. The conclusion is unchanged; the reason
82
+ is. **Consequence worth writing into the code comment ticket 03 asks for:** the
83
+ flat namespace is also why the map's `promo_textarea` / `promo_select`
84
+ namespacing is safe *and* why it is necessary — one flat namespace across all
85
+ categories means an unprefixed `textarea` really would collide ecosystem-wide.
86
+
87
+ **Aurora's own image block does NOT use this idiom.** `blocks/Image/schema.tsx`
88
+ names the field **`url`** with `widget: 'image'`. Both routes work; we are
89
+ choosing the more robust one (field-id cannot be knocked out of first place),
90
+ at the cost of not matching upstream's spelling. Take it deliberately — the map
91
+ already says to comment it.
92
+
93
+ ### 2. Stored shape — always a bare string or `null`. Never an array, never an object.
94
+
95
+ | host | write path | value written |
96
+ |---|---|---|
97
+ | Blicca | contentbrowser pick | `` `../resolveuid/${item.UID}` `` (relative), or `item['@id']` if no UID |
98
+ | Blicca | clear | `null` |
99
+ | upstream | object-browser pick | `selectedImage['@id']` — **absolute** |
100
+ | upstream | file upload | `result['@id']` from `@createContent` — **absolute** |
101
+ | upstream | **free-text link input** | any trimmed string the author types, or `null` |
102
+ | upstream | clear | `null` |
103
+
104
+ Neither host ever writes an array or an object. Upstream's `normalizeImageValue`
105
+ does *read* `['@id']` and `[{'@id'}]` shapes tolerantly (legacy Volto defence),
106
+ so tickets 09/10 should **accept** those on read while only ever **writing** a
107
+ string.
108
+
109
+ ### 3. `image_scales` / `image_field` — neither host persists them. Ticket 10 is the only source.
110
+
111
+ Confirmed on both sides, and the reason is the same on both:
112
+
113
+ - `Field.tsx` wires `onChange={(value) => { fieldProps.onChange?.(value); onFieldChange(value); }}`
114
+ — **one argument. The `extras` second argument is dropped on the floor.**
115
+ - Upstream's widget never had them to give: its extras are `{title}` only
116
+ (`onValueChange(result['@id'], {title})`). It never emits `image_scales` or
117
+ `image_field` at all.
118
+ - Blicca's widget *does* pass `{title, image_field, image_scales}`, but through
119
+ that same discarded second argument.
120
+ - Blicca's side-channel `patchSelectedImageBlock` writes them straight onto the
121
+ node — but `isImagePloneBlock()` gates on `node['@type'] === 'image'`, so for
122
+ `@type: 'promo'` **it is a no-op**. Good news twice over: nothing corrupts our
123
+ node, and nothing populates it either.
124
+
125
+ So ticket 10's transformer pair is not merely "the only source" — it is
126
+ load-bearing, and the block must render correctly from a bare URL string with no
127
+ scales present at all.
128
+
129
+ ### 4. `widgetOptions.pattern_options` — ignored by the image widget in both hosts. No loss.
130
+
131
+ Contract §1.5 is describing `object_browser`, not the image widget:
132
+
133
+ - **upstream `ImageWidget`** takes `restrictFileUpload`, `hideLinkPicker`,
134
+ `hideObjectBrowserPicker`, `objectBrowserPickerType`, `imageSize`,
135
+ `uploadPath`, `currentPath` as **direct props**, and **hardcodes**
136
+ `pattern_options: { selectableTypes: ['Image'] }` in its own internal
137
+ `ObjectBrowserProvider`.
138
+ - **Blicca `BliccaImageWidget`** hardcodes `selectableTypes={['Image']}` and
139
+ `upload` on its `PatternHost`.
140
+ - `ObjectBrowserWidget` *is* the one that honours
141
+ `widgetOptions.pattern_options.selectableTypes` (`ObjectBrowserWidget/utils.ts:99-109`).
142
+
143
+ **We lose nothing**: restrict-to-`Image` is what we wanted and both hosts do it
144
+ unconditionally. We simply cannot *configure* it. Do not declare
145
+ `widgetOptions.pattern_options` on the image field — it would be dead weight
146
+ that reads as if it were doing something.
147
+
148
+ **A live lever we do get instead:** `BlockSettingsFormRenderer` spreads
149
+ `{...schema.properties[key]}` into the widget, so any key on the schema property
150
+ arrives as a widget prop. Upstream-only props like `imageSize` or
151
+ `hideLinkPicker` can therefore be set from the schema — harmlessly ignored by
152
+ Blicca's widget, which does not read them.
153
+
154
+ ### 5. NEW — a cross-host value-space divergence the map had not anticipated
155
+
156
+ This did not come from the four bullets but is the biggest thing the reading
157
+ turned up, and it lands on tickets 09, 10 and 15:
158
+
159
+ 1. **Blicca writes relative, upstream writes absolute.** A promo authored in
160
+ Blicca stores `../resolveuid/<UID>`. Upstream's own preview helper is
161
+ `getPreviewSrc(url) = url.startsWith('/') ? url + '/@@images/image/<size>' : url`
162
+ — `../resolveuid/...` does **not** start with `/`, so **native Aurora would
163
+ render a Blicca-authored promo's image as a raw, broken `src`.** It is only
164
+ the editing preview, not the published page, but ticket 15 must expect it
165
+ rather than read it as a build error.
166
+ 2. **Upstream offers a free-text URL input; Blicca does not.** In native Aurora
167
+ an author can type an arbitrary external URL into the image field. So the
168
+ server renderer's link screening (the `path_of` / non-http item in the map's
169
+ constraints) is **not confined to the action links — the image field is a
170
+ second free-text surface**, reachable only from the native host. Ticket 09
171
+ should screen the image value too, not just the CTA hrefs.
172
+
173
+ ### Fallback — not needed, and it would cost more than it saves
174
+
175
+ Recorded for completeness since the ticket asked. The `object_browser` /
176
+ `mode:'single'` / `selectableTypes:['Image']` / `upload:true` idiom under a
177
+ non-`image` field name is **worse in native Aurora**: upstream's
178
+ `ObjectBrowserWidget` has **no upload at all** (the `upload` flag is Blicca's
179
+ `PatternHost` extension; nothing upstream reads it). Choosing it would trade a
180
+ working upload in both hosts for a picker that can only select pre-existing
181
+ images in one of them. Stay with the field named `image`.
@@ -0,0 +1,182 @@
1
+ # Research: how do we exercise the block in native Aurora?
2
+
3
+ Type: research
4
+ Status: resolved
5
+ Blocked by: —
6
+
7
+ ## Question
8
+
9
+ Native-Aurora support is a stated must-have, and **there is no Aurora checkout
10
+ in this environment** — only the source-published `@plone/*` packages under
11
+ `plone.blicca.auroraeditor/wrapper/node_modules/`. A must-have we cannot
12
+ exercise is a claim, not a feature. Establish what verification is actually
13
+ available before ticket 08 builds against the assumption.
14
+
15
+ - **Is there a runnable Aurora?** Determine whether Aurora can be checked out
16
+ and run against this Plone backend at all (`plone.blicca.auroraeditor`'s ADR
17
+ 0003 describes how the wrapper obtains Aurora's packages; the same route may
18
+ or may not yield a running app). If it can, that is the verification path and
19
+ ticket 15 uses it.
20
+ - **If it cannot**, what is the strongest available substitute? Candidates, in
21
+ descending honesty: mounting our `edit`/`view` components in a vitest/jsdom
22
+ harness against the **unsubstituted** upstream `@plone/cmsui` widget registry
23
+ (this catches the whole class of "the widget only exists in Blicca" bugs,
24
+ which is the actual risk); a Storybook-style render; or nothing but code
25
+ review.
26
+ - **What exactly differs between the hosts?** Enumerate it, so the substitute
27
+ test can target it: the widget registry contents, `config.getWidget`
28
+ resolution, the presence of `BliccaChoicesWidget`, the image widget
29
+ substitution, and the link-kit replacement. This list is the test plan.
30
+ - **Decide and record the claim we are entitled to make.** If we can only test
31
+ the registry-level differences, the README says the block *is built against
32
+ upstream-registered widgets and its own*, not that it *is verified in Aurora*.
33
+ Overclaiming here is worse than the gap.
34
+
35
+ ## Answer
36
+
37
+ **Verdict: do not stand up a live Aurora. Verify against the *unsubstituted
38
+ upstream registry* in a vitest/jsdom harness — candidate #2 in this ticket — and
39
+ make the correspondingly narrower claim.** The risk this actually retires is
40
+ "the widget only exists in Blicca", and that risk is fully reachable this way.
41
+
42
+ ### 1. Is there a runnable Aurora? Yes in principle, and it is still the wrong call.
43
+
44
+ Established, not assumed:
45
+
46
+ - Aurora is `plone/volto`, branch **`7-plate`**, app **`apps/seven`** (the
47
+ default branch has no `cmsui`/`blocks`/`layout` — those alphas are published
48
+ off `7-plate`). Every `@plone/*` package here carries
49
+ `repository: plone/volto`.
50
+ - **The network is open in this environment** — `npm view @plone/cmsui` and
51
+ `git ls-remote https://github.com/plone/volto` both succeed. So "we cannot get
52
+ Aurora" is false and should stop being repeated.
53
+
54
+ What makes it the wrong call is not availability, it is **three compounding
55
+ environment problems, none of which is a promo-block question**:
56
+
57
+ 1. **Seven assumes domain-root serving.** Blicca's own `ImageWidget` docstring
58
+ records why: `ImageBlockEdit` flattens URLs against
59
+ `config.settings.apiPath`, "built for Seven's domain-root serving, which
60
+ strips the `/<site>` prefix and 404s every scale on a Classic backend
61
+ without virtual hosting." Running Seven against our Plone at `:8081` means
62
+ standing up VHM rewriting first.
63
+ 2. **Our block has no runtime load path into Seven.** Contract §4 — the import
64
+ map, the `blockAddons` mount option, the wrapper's import+install
65
+ sequencing — is *entirely a Blicca `@@aurora-edit` mechanism*. Aurora proper
66
+ has no runtime add-on loader (§10 lists "Aurora upstream drift —
67
+ reconciliation if Aurora grows its own runtime add-on story" as still open).
68
+ Getting the promo into Seven means adding our package to the **monorepo's**
69
+ deps and registry config and rebuilding the app.
70
+ 3. It is a multi-day environment project sitting off this map's critical path,
71
+ and it would gate tickets 08–15 behind work that teaches us nothing about the
72
+ promo.
73
+
74
+ ### 2. Correction to the destination's wording: there is no single "same bundle"
75
+
76
+ Worth fixing now, because it changes what ticket 15 can honestly assert. The two
77
+ hosts consume **two different artifacts built from one source**:
78
+
79
+ | host | artifact | entry |
80
+ |---|---|---|
81
+ | Blicca | the scope-wrapped Plone static bundle, runtime-imported per contract §4 | `install(config)` via `blockAddons` |
82
+ | Aurora | the **npm package**, a source dependency (`collective.fragmentsblock`'s `bundle-src` exports `./src/index.tsx`) | `install(config)` from Seven's registry config |
83
+
84
+ The **shared, load-bearing surface is `install(config)` plus the `edit` and
85
+ `view` components** — identical in both. That is precisely what a jsdom harness
86
+ can mount. So the substitute is not a watered-down version of the real test; it
87
+ targets the actual shared seam.
88
+
89
+ ### 3. What exactly differs between the hosts — this is the test plan
90
+
91
+ Read off `cmsui/config/widgets.ts` (upstream) versus
92
+ `wrapper/src/bootstrap/config.ts` (Blicca, which installs cmsui first and then
93
+ overrides). **Blicca is upstream + these deltas:**
94
+
95
+ | key (category) | upstream | Blicca | touches the promo? |
96
+ |---|---|---|---|
97
+ | `choices` | **not registered at all** | `BliccaChoicesWidget` | **YES — the one that bites** |
98
+ | `image` (widget) | `cmsui ImageWidget` | `BliccaImageWidget` | **YES** — see ticket 01 |
99
+ | `object_browser` (widget) | React modal, **no upload** | pat-contentbrowser island, upload | no — promo uses free-text links |
100
+ | `boolean` (widget) | Quanta `Checkbox` | `BliccaBooleanWidget` (label adapter) | only if we add a boolean field |
101
+ | `querystring` (widget) | upstream | Blicca | no |
102
+ | `'Relation List'` (factory), `Catalog` (vocabulary) | `ObjectBrowserWidget` | Blicca's | no |
103
+ | `styleFieldDefinition` utility | **`blockWidth` only** (`@plone/blocks/index.ts:147`) | `blockWidth` + **`backgroundColor`** | **YES** |
104
+ | link-kit | cmsui's | `BliccaLinkKit` (Plate plugin) | **no** — promo has no rich text |
105
+ | `BlockSettingsForm` / renderer | upstream | **imports upstream verbatim** (`plone-block-sidebar.tsx:14`) | no difference to test |
106
+ | `align`, `size`, `width`, `date`, `datetime` | upstream | **not overridden** | safe in both |
107
+
108
+ **The three findings that matter:**
109
+
110
+ 1. **`choices` is Blicca-only.** `getWidgetByChoices` returns
111
+ `config.widgets?.choices ?? null`; upstream registers nothing, so **any field
112
+ declared with `choices` silently degrades to a single-line text input in
113
+ native Aurora.** This vindicates the map's decision to ship `promo_select`
114
+ under our own namespaced key rather than lean on `choices` — a
115
+ `widget: 'promo_select'` field resolves through `getWidgetByName` in *both*
116
+ hosts. Ticket 07 is load-bearing for Aurora support, not a nicety.
117
+ 2. **`backgroundColor`'s style definition is Blicca-only**, so the palette field
118
+ cannot function in native Aurora regardless of how we declare it. This is
119
+ consistent with the map's "Not yet specified" note and settles it in the same
120
+ direction: the field is a Blicca-host affordance, and the block must render
121
+ correctly with no `backgroundColor` at all.
122
+ 3. **`textarea` is registered in neither host** — confirming the map. Aurora's
123
+ own teaser `description` (`widget: 'textarea'`) is *already* degraded to a
124
+ one-line input upstream. `promo_textarea` is therefore an improvement on
125
+ upstream behaviour in both hosts, not a workaround for Blicca.
126
+
127
+ ### 4. The harness is idiomatic here, not invented
128
+
129
+ - `collective.fragmentsblock`'s `bundle-src` — the map's designated copy-me
130
+ template — **already ships `"test": "vitest run"`**. Ticket 06 inherits the
131
+ runner for free; no new tooling decision.
132
+ - Upstream `@plone/cmsui` tests itself the same way: `vitest`,
133
+ `@testing-library/react`, `vitest-axe`, a `vitest.config.ts` and
134
+ `setupTesting.ts`, with real widget tests (`ImageWidget.test.tsx`). Mounting
135
+ these source-published packages in jsdom is a **proven** pattern in this exact
136
+ package set, not a hope.
137
+ - Note the wrapper itself has **no test runner** (`wrapper/package.json` has only
138
+ `build`/`watch`/`typecheck`), so the harness belongs in our package's
139
+ `bundle-src`, not in the wrapper.
140
+
141
+ **Shape of the harness (for ticket 15):** in `bundle-src`, build a config the
142
+ way *Aurora* does — `installTheming`, `installPlate`, `installBlocks`,
143
+ `installLayout`, `installCmsui`, and **stop there, applying none of Blicca's
144
+ overrides** — then call our `install(config)` and render `edit` and `view`.
145
+ Assert: every field in our `blockSchema` resolves to a real widget (nothing
146
+ falls through to the default TextField that should not), `promo_textarea` and
147
+ `promo_select` resolve, the `image` field resolves to cmsui's `ImageWidget`, and
148
+ `view` renders the same anatomy classes as under the Blicca config.
149
+
150
+ ### 5. The claim we are entitled to make — record this verbatim in the README
151
+
152
+ > The Promo block is built against upstream-registered Aurora widgets and its
153
+ > own namespaced widgets, and its `install`, `edit` and `view` are exercised in
154
+ > a jsdom harness against an **unsubstituted upstream `@plone/*` registry**. It
155
+ > has **not** been run inside a live Aurora (Seven) application.
156
+
157
+ **Do not** write "verified in Aurora". The residual, honestly-stated gap:
158
+
159
+ - No live Seven run — so app-level integration (routing, loaders,
160
+ `config.settings.apiPath` flattening, real upload against `@createContent`)
161
+ is unexercised.
162
+ - The **npm-package artifact** is not built and consumed by a real Aurora build;
163
+ only the shared source is exercised.
164
+ - A cross-host value-space divergence found in ticket 01 stands unfixed and
165
+ unfixable from our side: a promo authored in Blicca stores
166
+ `../resolveuid/<UID>`, which Seven's `getPreviewSrc` would render as a raw
167
+ `src` because it does not start with `/`. Editing preview only, not published
168
+ output — but ticket 15 must expect it rather than read it as a failure.
169
+
170
+ ### 6. Consequences for the map
171
+
172
+ - **Ticket 15 is re-aimed** from "run it in Aurora" to the harness above; its
173
+ body has been updated and its `Blocked by` dropped from `02, 08` to `08`
174
+ (this ticket is now resolved, and nothing about the harness needs a live
175
+ Aurora).
176
+ - **Standing up a live Seven against this backend is ruled out of scope** for
177
+ this map — it is an environment project, not a promo-block decision, and the
178
+ destination asks for the native-Aurora path *exercised*, which the harness
179
+ does. Recorded in the map's Out of scope.
180
+ - **Ticket 03 gains two hard constraints** rather than open questions: no field
181
+ may rely on `choices` for its widget, and the block must render correctly with
182
+ `backgroundColor` absent.