@bettercms-ai/kit 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/adapters/dock-values.d.ts +28 -0
- package/dist/adapters/dock-values.js +41 -0
- package/dist/adapters/dock-values.js.map +1 -0
- package/{adapters → dist/adapters}/icons.js +2 -2
- package/dist/adapters/icons.js.map +1 -0
- package/{adapters → dist/adapters}/lossy.d.ts +90 -31
- package/dist/adapters/lossy.js +414 -0
- package/dist/adapters/lossy.js.map +1 -0
- package/{adapters → dist/adapters}/prod-types.d.ts +82 -4
- package/{adapters → dist/adapters}/prod-types.js +71 -3
- package/dist/adapters/prod-types.js.map +1 -0
- package/{adapters → dist/adapters}/schema.d.ts +40 -1
- package/{adapters → dist/adapters}/schema.js +996 -179
- package/dist/adapters/schema.js.map +1 -0
- package/{adapters → dist/adapters}/values.d.ts +26 -5
- package/{adapters → dist/adapters}/values.js +87 -17
- package/dist/adapters/values.js.map +1 -0
- package/dist/brand/logo.js +96 -0
- package/dist/brand/logo.js.map +1 -0
- package/{context.d.ts → dist/context.d.ts} +92 -2
- package/{context.js → dist/context.js} +5 -2
- package/dist/context.js.map +1 -0
- package/{controls → dist/controls}/button.d.ts +19 -5
- package/{controls → dist/controls}/button.js +125 -54
- package/dist/controls/button.js.map +1 -0
- package/{controls → dist/controls}/c1.js +1 -1
- package/dist/controls/c1.js.map +1 -0
- package/{controls → dist/controls}/c2.js +1 -1
- package/dist/controls/c2.js.map +1 -0
- package/{controls → dist/controls}/choice.d.ts +7 -2
- package/{controls → dist/controls}/choice.js +71 -18
- package/dist/controls/choice.js.map +1 -0
- package/{controls → dist/controls}/code-register.js +1 -1
- package/dist/controls/code-register.js.map +1 -0
- package/{controls → dist/controls}/code.js +10 -9
- package/dist/controls/code.js.map +1 -0
- package/{controls → dist/controls}/color.js +8 -8
- package/dist/controls/color.js.map +1 -0
- package/{controls → dist/controls}/component-services.d.ts +42 -0
- package/dist/controls/component-services.js +7 -0
- package/dist/controls/component-services.js.map +1 -0
- package/{controls → dist/controls}/date-register.js +1 -1
- package/dist/controls/date-register.js.map +1 -0
- package/{controls → dist/controls}/date-zone.js +8 -2
- package/dist/controls/date-zone.js.map +1 -0
- package/{controls → dist/controls}/date.js +32 -24
- package/dist/controls/date.js.map +1 -0
- package/{controls → dist/controls}/form-picker-register.js +1 -1
- package/dist/controls/form-picker-register.js.map +1 -0
- package/{controls → dist/controls}/form-picker.js +11 -9
- package/dist/controls/form-picker.js.map +1 -0
- package/{controls → dist/controls}/icon-register.js +1 -1
- package/dist/controls/icon-register.js.map +1 -0
- package/{controls → dist/controls}/icon.d.ts +4 -2
- package/{controls → dist/controls}/icon.js +32 -27
- package/dist/controls/icon.js.map +1 -0
- package/{controls → dist/controls}/index.d.ts +1 -1
- package/{controls → dist/controls}/index.js +4 -3
- package/dist/controls/index.js.map +1 -0
- package/{controls → dist/controls}/json-register.js +1 -1
- package/dist/controls/json-register.js.map +1 -0
- package/{controls → dist/controls}/json.js +13 -3
- package/dist/controls/json.js.map +1 -0
- package/{controls → dist/controls}/link.js +6 -6
- package/dist/controls/link.js.map +1 -0
- package/{controls → dist/controls}/location-register.js +1 -1
- package/dist/controls/location-register.js.map +1 -0
- package/{controls → dist/controls}/location.js +64 -40
- package/dist/controls/location.js.map +1 -0
- package/{controls → dist/controls}/media-register.js +1 -1
- package/dist/controls/media-register.js.map +1 -0
- package/{controls → dist/controls}/media-services.d.ts +6 -0
- package/dist/controls/media-services.js +0 -0
- package/{controls → dist/controls}/media.d.ts +35 -4
- package/{controls → dist/controls}/media.js +491 -171
- package/dist/controls/media.js.map +1 -0
- package/{controls → dist/controls}/number.js +10 -9
- package/dist/controls/number.js.map +1 -0
- package/{controls → dist/controls}/reference-register.js +1 -1
- package/dist/controls/reference-register.js.map +1 -0
- package/{controls → dist/controls}/reference-services.d.ts +4 -0
- package/dist/controls/reference-services.js +0 -0
- package/{controls → dist/controls}/reference.d.ts +1 -1
- package/{controls → dist/controls}/reference.js +93 -77
- package/dist/controls/reference.js.map +1 -0
- package/dist/controls/rich-text/blocks.d.ts +49 -0
- package/{controls → dist/controls}/rich-text/blocks.js +471 -144
- package/dist/controls/rich-text/blocks.js.map +1 -0
- package/{controls → dist/controls}/rich-text/catalog.d.ts +4 -1
- package/{controls → dist/controls}/rich-text/catalog.js +75 -65
- package/dist/controls/rich-text/catalog.js.map +1 -0
- package/{controls → dist/controls}/rich-text/codec.d.ts +9 -1
- package/{controls → dist/controls}/rich-text/codec.js +3 -1
- package/dist/controls/rich-text/codec.js.map +1 -0
- package/{controls → dist/controls}/rich-text/component-card.d.ts +1 -1
- package/{controls → dist/controls}/rich-text/component-card.js +417 -99
- package/dist/controls/rich-text/component-card.js.map +1 -0
- package/dist/controls/rich-text/component-panel.d.ts +47 -0
- package/dist/controls/rich-text/component-panel.js +141 -0
- package/dist/controls/rich-text/component-panel.js.map +1 -0
- package/{controls → dist/controls}/rich-text/control.d.ts +1 -2
- package/{controls → dist/controls}/rich-text/control.js +84 -42
- package/dist/controls/rich-text/control.js.map +1 -0
- package/{controls → dist/controls}/rich-text/dom.d.ts +52 -9
- package/{controls → dist/controls}/rich-text/dom.js +379 -50
- package/dist/controls/rich-text/dom.js.map +1 -0
- package/{controls → dist/controls}/rich-text/editor.d.ts +7 -0
- package/{controls → dist/controls}/rich-text/editor.js +148 -48
- package/dist/controls/rich-text/editor.js.map +1 -0
- package/{controls → dist/controls}/rich-text/floating.d.ts +6 -1
- package/{controls → dist/controls}/rich-text/floating.js +35 -18
- package/dist/controls/rich-text/floating.js.map +1 -0
- package/{controls → dist/controls}/rich-text/index.js +1 -1
- package/dist/controls/rich-text/index.js.map +1 -0
- package/dist/controls/rich-text/link-form.js +147 -0
- package/dist/controls/rich-text/link-form.js.map +1 -0
- package/{controls → dist/controls}/rich-text/markdown.js +4 -2
- package/dist/controls/rich-text/markdown.js.map +1 -0
- package/{controls → dist/controls}/rich-text/ops.js +17 -15
- package/dist/controls/rich-text/ops.js.map +1 -0
- package/dist/controls/rich-text/plain.d.ts +17 -0
- package/dist/controls/rich-text/plain.js +44 -0
- package/dist/controls/rich-text/plain.js.map +1 -0
- package/{controls → dist/controls}/rich-text/toolbar.d.ts +6 -2
- package/{controls → dist/controls}/rich-text/toolbar.js +12 -7
- package/dist/controls/rich-text/toolbar.js.map +1 -0
- package/{controls → dist/controls}/scale.js +5 -5
- package/dist/controls/scale.js.map +1 -0
- package/{controls → dist/controls}/slot-register.js +1 -1
- package/dist/controls/slot-register.js.map +1 -0
- package/{controls → dist/controls}/slot-services.d.ts +25 -0
- package/dist/controls/slot-services.js +155 -0
- package/dist/controls/slot-services.js.map +1 -0
- package/{controls → dist/controls}/slot.js +42 -24
- package/dist/controls/slot.js.map +1 -0
- package/{controls → dist/controls}/table/index.js +1 -1
- package/dist/controls/table/index.js.map +1 -0
- package/{controls → dist/controls}/table/prod.js +3 -3
- package/dist/controls/table/prod.js.map +1 -0
- package/{controls → dist/controls}/table/refs.js +13 -2
- package/dist/controls/table/refs.js.map +1 -0
- package/{controls → dist/controls}/table/stored.js +1 -1
- package/dist/controls/table/stored.js.map +1 -0
- package/{controls → dist/controls}/table/table-editor.js +51 -48
- package/dist/controls/table/table-editor.js.map +1 -0
- package/{controls → dist/controls}/table/table-link.js +3 -3
- package/dist/controls/table/table-link.js.map +1 -0
- package/{controls → dist/controls}/table/table.js +3 -3
- package/dist/controls/table/table.js.map +1 -0
- package/{controls → dist/controls}/text.d.ts +2 -2
- package/{controls → dist/controls}/text.js +78 -43
- package/dist/controls/text.js.map +1 -0
- package/dist/controls/unknown-value.d.ts +17 -0
- package/dist/controls/unknown-value.js +66 -0
- package/dist/controls/unknown-value.js.map +1 -0
- package/dist/core/core.d.ts +63 -0
- package/dist/core/core.js +171 -0
- package/dist/core/core.js.map +1 -0
- package/dist/core/facets.d.ts +347 -0
- package/dist/core/facets.js +334 -0
- package/dist/core/facets.js.map +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.js +3 -0
- package/{engine → dist/engine}/array.js +34 -21
- package/dist/engine/array.js.map +1 -0
- package/{engine → dist/engine}/bits.js +1 -1
- package/dist/engine/bits.js.map +1 -0
- package/{engine → dist/engine}/breadcrumb.d.ts +3 -3
- package/{engine → dist/engine}/breadcrumb.js +12 -36
- package/dist/engine/breadcrumb.js.map +1 -0
- package/{engine → dist/engine}/expand.d.ts +2 -4
- package/{engine → dist/engine}/expand.js +5 -22
- package/dist/engine/expand.js.map +1 -0
- package/{engine → dist/engine}/field-list.js +1 -1
- package/dist/engine/field-list.js.map +1 -0
- package/{engine → dist/engine}/field-shell.js +249 -121
- package/dist/engine/field-shell.js.map +1 -0
- package/{engine → dist/engine}/frame.d.ts +3 -1
- package/{engine → dist/engine}/frame.js +16 -14
- package/dist/engine/frame.js.map +1 -0
- package/{engine → dist/engine}/group-summary.d.ts +2 -1
- package/{engine → dist/engine}/group-summary.js +7 -3
- package/dist/engine/group-summary.js.map +1 -0
- package/{engine → dist/engine}/grouping.d.ts +19 -5
- package/{engine → dist/engine}/grouping.js +193 -21
- package/dist/engine/grouping.js.map +1 -0
- package/{engine → dist/engine}/item-list.d.ts +11 -1
- package/{engine → dist/engine}/item-list.js +35 -13
- package/dist/engine/item-list.js.map +1 -0
- package/{engine → dist/engine}/kit-field.js +45 -10
- package/dist/engine/kit-field.js.map +1 -0
- package/{engine → dist/engine}/schema-form.d.ts +27 -2
- package/{engine → dist/engine}/schema-form.js +182 -40
- package/dist/engine/schema-form.js.map +1 -0
- package/{engine → dist/engine}/slot.js +5 -15
- package/dist/engine/slot.js.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/{kit.css → dist/kit.css} +19 -0
- package/{lib → dist/lib}/cn.js +7 -4
- package/dist/lib/cn.js.map +1 -0
- package/{lib → dist/lib}/columns.js +4 -1
- package/dist/lib/columns.js.map +1 -0
- package/{lib → dist/lib}/frames.js +2 -2
- package/dist/lib/frames.js.map +1 -0
- package/dist/lib/icon-image.d.ts +10 -0
- package/dist/lib/icon-image.js +8 -0
- package/dist/lib/icon-image.js.map +1 -0
- package/{lib → dist/lib}/icons.js +4 -3
- package/dist/lib/icons.js.map +1 -0
- package/dist/lib/input-modality.d.ts +11 -0
- package/dist/lib/input-modality.js +47 -0
- package/dist/lib/input-modality.js.map +1 -0
- package/dist/lib/key-event.d.ts +11 -0
- package/dist/lib/key-event.js +16 -0
- package/dist/lib/key-event.js.map +1 -0
- package/{lib → dist/lib}/path.js +4 -2
- package/dist/lib/path.js.map +1 -0
- package/{lib → dist/lib}/schema.d.ts +34 -3
- package/{lib → dist/lib}/schema.js +110 -13
- package/dist/lib/schema.js.map +1 -0
- package/{lib → dist/lib}/utils.js +1 -1
- package/dist/lib/utils.js.map +1 -0
- package/{lib → dist/lib}/validate.d.ts +11 -1
- package/{lib → dist/lib}/validate.js +85 -11
- package/dist/lib/validate.js.map +1 -0
- package/dist/library/analysis.d.ts +23 -0
- package/dist/library/analysis.js +160 -0
- package/dist/library/analysis.js.map +1 -0
- package/dist/library/catalog.d.ts +57 -0
- package/dist/library/catalog.js +307 -0
- package/dist/library/catalog.js.map +1 -0
- package/dist/library/coreNotes.d.ts +8 -0
- package/dist/library/coreNotes.js +111 -0
- package/dist/library/coreNotes.js.map +1 -0
- package/dist/library/coverage.d.ts +40 -0
- package/dist/library/coverage.js +59 -0
- package/dist/library/coverage.js.map +1 -0
- package/dist/library/entries/advanced.entries.d.ts +2 -0
- package/dist/library/entries/advanced.entries.js +6579 -0
- package/dist/library/entries/advanced.entries.js.map +1 -0
- package/dist/library/entries/commerce.entries.d.ts +2 -0
- package/dist/library/entries/commerce.entries.js +4140 -0
- package/dist/library/entries/commerce.entries.js.map +1 -0
- package/dist/library/entries/company.entries.d.ts +2 -0
- package/dist/library/entries/company.entries.js +2731 -0
- package/dist/library/entries/company.entries.js.map +1 -0
- package/dist/library/entries/conversion.entries.d.ts +2 -0
- package/dist/library/entries/conversion.entries.js +3707 -0
- package/dist/library/entries/conversion.entries.js.map +1 -0
- package/dist/library/entries/data.entries.d.ts +7 -0
- package/dist/library/entries/data.entries.js +4613 -0
- package/dist/library/entries/data.entries.js.map +1 -0
- package/dist/library/entries/events.entries.d.ts +2 -0
- package/dist/library/entries/events.entries.js +3428 -0
- package/dist/library/entries/events.entries.js.map +1 -0
- package/dist/library/entries/features.entries.d.ts +2 -0
- package/dist/library/entries/features.entries.js +3157 -0
- package/dist/library/entries/features.entries.js.map +1 -0
- package/dist/library/entries/heroes.entries.d.ts +2 -0
- package/dist/library/entries/heroes.entries.js +3401 -0
- package/dist/library/entries/heroes.entries.js.map +1 -0
- package/dist/library/entries/index.d.ts +3 -0
- package/dist/library/entries/index.js +35 -0
- package/dist/library/entries/index.js.map +1 -0
- package/dist/library/entries/listings.entries.d.ts +2 -0
- package/dist/library/entries/listings.entries.js +2976 -0
- package/dist/library/entries/listings.entries.js.map +1 -0
- package/dist/library/entries/longform.entries.d.ts +2 -0
- package/dist/library/entries/longform.entries.js +4227 -0
- package/dist/library/entries/longform.entries.js.map +1 -0
- package/dist/library/entries/media.entries.d.ts +2 -0
- package/dist/library/entries/media.entries.js +2781 -0
- package/dist/library/entries/media.entries.js.map +1 -0
- package/dist/library/entries/navigation.entries.d.ts +2 -0
- package/dist/library/entries/navigation.entries.js +4011 -0
- package/dist/library/entries/navigation.entries.js.map +1 -0
- package/dist/library/entries/pricing.entries.d.ts +2 -0
- package/dist/library/entries/pricing.entries.js +2383 -0
- package/dist/library/entries/pricing.entries.js.map +1 -0
- package/dist/library/entries/social-proof.entries.d.ts +2 -0
- package/dist/library/entries/social-proof.entries.js +2297 -0
- package/dist/library/entries/social-proof.entries.js.map +1 -0
- package/dist/library/examples/bento.d.ts +92 -0
- package/dist/library/examples/bento.js +201 -0
- package/dist/library/examples/bento.js.map +1 -0
- package/dist/library/examples/blocks.d.ts +14 -0
- package/dist/library/examples/blocks.js +313 -0
- package/dist/library/examples/blocks.js.map +1 -0
- package/dist/library/examples/faq.d.ts +28 -0
- package/dist/library/examples/faq.js +230 -0
- package/dist/library/examples/faq.js.map +1 -0
- package/dist/library/examples/hero.d.ts +43 -0
- package/dist/library/examples/hero.js +222 -0
- package/dist/library/examples/hero.js.map +1 -0
- package/dist/library/examples/index.d.ts +36 -0
- package/dist/library/examples/index.js +109 -0
- package/dist/library/examples/index.js.map +1 -0
- package/dist/library/examples/journalStory.d.ts +93 -0
- package/dist/library/examples/journalStory.js +338 -0
- package/dist/library/examples/journalStory.js.map +1 -0
- package/dist/library/examples/megaMenu.d.ts +134 -0
- package/dist/library/examples/megaMenu.js +442 -0
- package/dist/library/examples/megaMenu.js.map +1 -0
- package/dist/library/examples/pricing.d.ts +103 -0
- package/dist/library/examples/pricing.js +479 -0
- package/dist/library/examples/pricing.js.map +1 -0
- package/dist/library/examples/tabs.d.ts +87 -0
- package/dist/library/examples/tabs.js +180 -0
- package/dist/library/examples/tabs.js.map +1 -0
- package/dist/library/export.d.ts +42 -0
- package/dist/library/export.js +80 -0
- package/dist/library/export.js.map +1 -0
- package/dist/library/index.d.ts +13 -0
- package/dist/library/index.js +6 -0
- package/dist/library/kit-catalog.json +1510 -0
- package/dist/library/types.d.ts +42 -0
- package/dist/library/types.js +0 -0
- package/{schema → dist/schema}/adapters.js +1 -2
- package/dist/schema/adapters.js.map +1 -0
- package/{schema → dist/schema}/help.d.ts +2 -0
- package/{schema → dist/schema}/help.js +6 -4
- package/dist/schema/help.js.map +1 -0
- package/{schema → dist/schema}/scale.js +1 -1
- package/dist/schema/scale.js.map +1 -0
- package/{schema → dist/schema}/sources.js +1 -1
- package/dist/schema/sources.js.map +1 -0
- package/{schema → dist/schema}/table.js +11 -10
- package/dist/schema/table.js.map +1 -0
- package/{schema → dist/schema}/types.d.ts +29 -1
- package/{schema → dist/schema}/types.js +1 -1
- package/dist/schema/types.js.map +1 -0
- package/dist/styles.css +2 -0
- package/dist/table/table-view.d.ts +14 -0
- package/dist/table/table-view.js +140 -0
- package/dist/table/table-view.js.map +1 -0
- package/dist/table/table.css +73 -0
- package/dist/testing/corpus.d.ts +63 -0
- package/dist/testing/corpus.js +129 -0
- package/dist/testing/corpus.js.map +1 -0
- package/dist/testing/test-form.d.ts +11 -0
- package/dist/testing/test-form.js +38 -0
- package/dist/testing/test-form.js.map +1 -0
- package/dist/theme.css +345 -0
- package/dist/theme.d.ts +22 -0
- package/dist/theme.js +43 -0
- package/dist/theme.js.map +1 -0
- package/dist/tokens.css +542 -0
- package/dist/types.js +0 -0
- package/{ui → dist/ui}/action-tray.d.ts +1 -1
- package/{ui → dist/ui}/action-tray.js +20 -19
- package/dist/ui/action-tray.js.map +1 -0
- package/dist/ui/autocomplete.d.ts +30 -0
- package/dist/ui/autocomplete.js +139 -0
- package/dist/ui/autocomplete.js.map +1 -0
- package/{ui → dist/ui}/button.d.ts +3 -3
- package/{ui → dist/ui}/button.js +6 -7
- package/dist/ui/button.js.map +1 -0
- package/{ui → dist/ui}/choice-switch.js +1 -1
- package/dist/ui/choice-switch.js.map +1 -0
- package/{ui → dist/ui}/controls.js +51 -39
- package/dist/ui/controls.js.map +1 -0
- package/{ui → dist/ui}/display.d.ts +10 -3
- package/{ui → dist/ui}/display.js +57 -46
- package/dist/ui/display.js.map +1 -0
- package/{ui → dist/ui}/expanded-editor-modal.d.ts +2 -2
- package/{ui → dist/ui}/expanded-editor-modal.js +6 -6
- package/dist/ui/expanded-editor-modal.js.map +1 -0
- package/{ui → dist/ui}/field-context.js +1 -1
- package/dist/ui/field-context.js.map +1 -0
- package/{ui → dist/ui}/floating-panel.d.ts +1 -1
- package/{ui → dist/ui}/floating-panel.js +28 -12
- package/dist/ui/floating-panel.js.map +1 -0
- package/{ui → dist/ui}/index.d.ts +4 -0
- package/dist/ui/index.js +18 -0
- package/{ui → dist/ui}/input.d.ts +1 -1
- package/{ui → dist/ui}/input.js +9 -9
- package/dist/ui/input.js.map +1 -0
- package/{ui → dist/ui}/mode-bar.js +3 -3
- package/dist/ui/mode-bar.js.map +1 -0
- package/{ui → dist/ui}/overlay.d.ts +77 -5
- package/dist/ui/overlay.js +697 -0
- package/dist/ui/overlay.js.map +1 -0
- package/{ui → dist/ui}/path-crumbs.js +37 -3
- package/dist/ui/path-crumbs.js.map +1 -0
- package/{ui → dist/ui}/presence.js +2 -2
- package/dist/ui/presence.js.map +1 -0
- package/{ui → dist/ui}/select.js +89 -87
- package/dist/ui/select.js.map +1 -0
- package/{ui → dist/ui}/shortcut-hint.js +1 -1
- package/dist/ui/shortcut-hint.js.map +1 -0
- package/dist/ui/spinner.d.ts +24 -0
- package/dist/ui/spinner.js +42 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/split-button.d.ts +32 -0
- package/dist/ui/split-button.js +60 -0
- package/dist/ui/split-button.js.map +1 -0
- package/{ui → dist/ui}/surfaces.js +1 -1
- package/dist/ui/surfaces.js.map +1 -0
- package/dist/ui/tab.d.ts +38 -0
- package/dist/ui/tab.js +87 -0
- package/dist/ui/tab.js.map +1 -0
- package/dist/ui/toast.d.ts +20 -0
- package/dist/ui/toast.js +115 -0
- package/dist/ui/toast.js.map +1 -0
- package/{ui → dist/ui}/tooltip-root.d.ts +4 -3
- package/{ui → dist/ui}/tooltip-root.js +9 -8
- package/dist/ui/tooltip-root.js.map +1 -0
- package/{ui → dist/ui}/variants.js +1 -1
- package/dist/ui/variants.js.map +1 -0
- package/package.json +77 -23
- package/adapters/icons.js.map +0 -1
- package/adapters/lossy.js +0 -233
- package/adapters/lossy.js.map +0 -1
- package/adapters/prod-types.js.map +0 -1
- package/adapters/schema.js.map +0 -1
- package/adapters/values.js.map +0 -1
- package/brand/logo.js +0 -9
- package/brand/logo.js.map +0 -1
- package/context.js.map +0 -1
- package/controls/button.js.map +0 -1
- package/controls/c1.js.map +0 -1
- package/controls/c2.js.map +0 -1
- package/controls/choice.js.map +0 -1
- package/controls/code-register.js.map +0 -1
- package/controls/code.js.map +0 -1
- package/controls/color.js.map +0 -1
- package/controls/date-register.js.map +0 -1
- package/controls/date-zone.js.map +0 -1
- package/controls/date.js.map +0 -1
- package/controls/form-picker-register.js.map +0 -1
- package/controls/form-picker.js.map +0 -1
- package/controls/icon-register.js.map +0 -1
- package/controls/icon.js.map +0 -1
- package/controls/index.js.map +0 -1
- package/controls/json-register.js.map +0 -1
- package/controls/json.js.map +0 -1
- package/controls/link.js.map +0 -1
- package/controls/location-register.js.map +0 -1
- package/controls/location.js.map +0 -1
- package/controls/media-register.js.map +0 -1
- package/controls/media.js.map +0 -1
- package/controls/number.js.map +0 -1
- package/controls/reference-register.js.map +0 -1
- package/controls/reference.js.map +0 -1
- package/controls/rich-text/blocks.d.ts +0 -28
- package/controls/rich-text/blocks.js.map +0 -1
- package/controls/rich-text/catalog.js.map +0 -1
- package/controls/rich-text/codec.js.map +0 -1
- package/controls/rich-text/component-card.js.map +0 -1
- package/controls/rich-text/control.js.map +0 -1
- package/controls/rich-text/dom.js.map +0 -1
- package/controls/rich-text/editor.js.map +0 -1
- package/controls/rich-text/floating.js.map +0 -1
- package/controls/rich-text/index.js.map +0 -1
- package/controls/rich-text/link-form.js +0 -111
- package/controls/rich-text/link-form.js.map +0 -1
- package/controls/rich-text/markdown.js.map +0 -1
- package/controls/rich-text/ops.js.map +0 -1
- package/controls/rich-text/toolbar.js.map +0 -1
- package/controls/scale.js.map +0 -1
- package/controls/slot-register.js.map +0 -1
- package/controls/slot-services.js +0 -38
- package/controls/slot-services.js.map +0 -1
- package/controls/slot.js.map +0 -1
- package/controls/table/index.js.map +0 -1
- package/controls/table/prod.js.map +0 -1
- package/controls/table/refs.js.map +0 -1
- package/controls/table/stored.js.map +0 -1
- package/controls/table/table-editor.js.map +0 -1
- package/controls/table/table-link.js.map +0 -1
- package/controls/table/table.js.map +0 -1
- package/controls/text.js.map +0 -1
- package/engine/array.js.map +0 -1
- package/engine/bits.js.map +0 -1
- package/engine/breadcrumb.js.map +0 -1
- package/engine/expand.js.map +0 -1
- package/engine/field-list.js.map +0 -1
- package/engine/field-shell.js.map +0 -1
- package/engine/frame.js.map +0 -1
- package/engine/group-summary.js.map +0 -1
- package/engine/grouping.js.map +0 -1
- package/engine/item-list.js.map +0 -1
- package/engine/kit-field.js.map +0 -1
- package/engine/schema-form.js.map +0 -1
- package/engine/slot.js.map +0 -1
- package/index.js +0 -55
- package/index.js.map +0 -1
- package/lib/cn.js.map +0 -1
- package/lib/columns.js.map +0 -1
- package/lib/frames.js.map +0 -1
- package/lib/icons.js.map +0 -1
- package/lib/path.js.map +0 -1
- package/lib/schema.js.map +0 -1
- package/lib/utils.js.map +0 -1
- package/lib/validate.js.map +0 -1
- package/schema/adapters.js.map +0 -1
- package/schema/help.js.map +0 -1
- package/schema/scale.js.map +0 -1
- package/schema/sources.js.map +0 -1
- package/schema/table.js.map +0 -1
- package/schema/types.js.map +0 -1
- package/ui/action-tray.js.map +0 -1
- package/ui/button.js.map +0 -1
- package/ui/choice-switch.js.map +0 -1
- package/ui/controls.js.map +0 -1
- package/ui/display.js.map +0 -1
- package/ui/expanded-editor-modal.js.map +0 -1
- package/ui/field-context.js.map +0 -1
- package/ui/floating-panel.js.map +0 -1
- package/ui/index.js +0 -13
- package/ui/input.js.map +0 -1
- package/ui/mode-bar.js.map +0 -1
- package/ui/overlay.js +0 -378
- package/ui/overlay.js.map +0 -1
- package/ui/path-crumbs.js.map +0 -1
- package/ui/presence.js.map +0 -1
- package/ui/select.js.map +0 -1
- package/ui/shortcut-hint.js.map +0 -1
- package/ui/surfaces.js.map +0 -1
- package/ui/tooltip-root.js.map +0 -1
- package/ui/variants.js.map +0 -1
- /package/{_virtual → dist/_virtual}/_rolldown/runtime.js +0 -0
- /package/{adapters → dist/adapters}/icons.d.ts +0 -0
- /package/{brand → dist/brand}/logo.d.ts +0 -0
- /package/{controls → dist/controls}/c1.d.ts +0 -0
- /package/{controls → dist/controls}/c2.d.ts +0 -0
- /package/{controls → dist/controls}/code-register.d.ts +0 -0
- /package/{controls → dist/controls}/code.d.ts +0 -0
- /package/{controls → dist/controls}/color.d.ts +0 -0
- /package/{controls → dist/controls}/date-register.d.ts +0 -0
- /package/{controls → dist/controls}/date-zone.d.ts +0 -0
- /package/{controls → dist/controls}/date.d.ts +0 -0
- /package/{controls → dist/controls}/form-picker-register.d.ts +0 -0
- /package/{controls → dist/controls}/form-picker.d.ts +0 -0
- /package/{controls → dist/controls}/icon-register.d.ts +0 -0
- /package/{controls → dist/controls}/json-register.d.ts +0 -0
- /package/{controls → dist/controls}/json.d.ts +0 -0
- /package/{controls → dist/controls}/link.d.ts +0 -0
- /package/{controls → dist/controls}/location-register.d.ts +0 -0
- /package/{controls → dist/controls}/location.d.ts +0 -0
- /package/{controls → dist/controls}/media-register.d.ts +0 -0
- /package/{controls → dist/controls}/number.d.ts +0 -0
- /package/{controls → dist/controls}/reference-register.d.ts +0 -0
- /package/{controls → dist/controls}/rich-text/index.d.ts +0 -0
- /package/{controls → dist/controls}/rich-text/link-form.d.ts +0 -0
- /package/{controls → dist/controls}/rich-text/markdown.d.ts +0 -0
- /package/{controls → dist/controls}/rich-text/ops.d.ts +0 -0
- /package/{controls → dist/controls}/scale.d.ts +0 -0
- /package/{controls → dist/controls}/slot-register.d.ts +0 -0
- /package/{controls → dist/controls}/slot.d.ts +0 -0
- /package/{controls → dist/controls}/table/index.d.ts +0 -0
- /package/{controls → dist/controls}/table/prod.d.ts +0 -0
- /package/{controls → dist/controls}/table/refs.d.ts +0 -0
- /package/{controls → dist/controls}/table/stored.d.ts +0 -0
- /package/{controls → dist/controls}/table/table-editor.d.ts +0 -0
- /package/{controls → dist/controls}/table/table-link.d.ts +0 -0
- /package/{controls → dist/controls}/table/table.d.ts +0 -0
- /package/{engine → dist/engine}/array.d.ts +0 -0
- /package/{engine → dist/engine}/bits.d.ts +0 -0
- /package/{engine → dist/engine}/field-list.d.ts +0 -0
- /package/{engine → dist/engine}/field-shell.d.ts +0 -0
- /package/{engine → dist/engine}/kit-field.d.ts +0 -0
- /package/{engine → dist/engine}/slot.d.ts +0 -0
- /package/{index.d.ts → dist/index.d.ts} +0 -0
- /package/{lib → dist/lib}/cn.d.ts +0 -0
- /package/{lib → dist/lib}/columns.d.ts +0 -0
- /package/{lib → dist/lib}/frames.d.ts +0 -0
- /package/{lib → dist/lib}/icons.d.ts +0 -0
- /package/{lib → dist/lib}/path.d.ts +0 -0
- /package/{lib → dist/lib}/utils.d.ts +0 -0
- /package/{schema → dist/schema}/adapters.d.ts +0 -0
- /package/{schema → dist/schema}/scale.d.ts +0 -0
- /package/{schema → dist/schema}/sources.d.ts +0 -0
- /package/{schema → dist/schema}/table.d.ts +0 -0
- /package/{types.d.ts → dist/types.d.ts} +0 -0
- /package/{ui → dist/ui}/choice-switch.d.ts +0 -0
- /package/{ui → dist/ui}/controls.d.ts +0 -0
- /package/{ui → dist/ui}/field-context.d.ts +0 -0
- /package/{ui → dist/ui}/mode-bar.d.ts +0 -0
- /package/{ui → dist/ui}/path-crumbs.d.ts +0 -0
- /package/{ui → dist/ui}/presence.d.ts +0 -0
- /package/{ui → dist/ui}/select.d.ts +0 -0
- /package/{ui → dist/ui}/shortcut-hint.d.ts +0 -0
- /package/{ui → dist/ui}/surfaces.d.ts +0 -0
- /package/{ui → dist/ui}/variants.d.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-card.js","names":[],"sources":["../../../src/controls/rich-text/component-card.tsx"],"sourcesContent":["/**\n * The embedded component card (V2 features/blocks/instance-card.tsx + instance-ui.tsx StateChip / MissingNote / dialogs),\n * drawn when the host can look the component up (KitServices.useComponentInfo, component-services.ts):\n *\n * ┌ [icon] Inline CTA 🔗 2 places · ● Edited here ⋯ ┐ 36px strip\n * ├ ⚠ The original \"Product card\" was deleted. … [Keep as a separate copy] [Remove] ┤ missing only\n * │ the component itself, drawn live with this place's values (KitServices.ComponentPreview), else │\n * │ its snapshot where this place shows exactly that, else its fields; at most 240px, faded │\n * └──────────────────────────────────────────────────────────────────────────────┘\n *\n * Every state comes from the lookup or the stored copy: \"Missing component\" only when the library says there is no\n * such component, the count only when the host measured it, \"Edited here\" only for overrides of fields the component\n * has, \"Detached\" for a separate copy (V2 instances.ts `detached`), and \"Shared version changed\" only when the\n * component's current version (`info.publishedAt`) differs from the one the copy was taken from.\n *\n * A separate copy is made through the host (`copyComponent`, which answers what readers see now) and written as ONE\n * undo step (V2 detachNow: \"Make a separate copy\"); \"Use shared version again\" (V2 RelinkDialog) keeps this place's\n * edits as overrides or drops them, also one step. A host without `copyComponent` offers neither.\n *\n * Deviation from V2: V2 shows \"Shared version changed\" on a LINKED instance after a breaking release (instances.ts\n * `pending`). A linked instance here follows every publish of its component, so there is nothing to review; the\n * notice is drawn on a separate copy instead, whose source moved on, and it opens \"Use shared version again\".\n */\nimport * as React from \"react\";\nimport {\n IconAdjustmentsHorizontal, IconAlertTriangle, IconArrowBarToDown, IconArrowBarToUp, IconArrowUpRight, IconCheck, IconComponents, IconCopy, IconDots,\n IconGripVertical, IconLayoutNavbarCollapse, IconLayoutNavbarExpand, IconLink, IconRefresh, IconReplace, IconRestore, IconTrash, IconUnlink,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../lib/cn\";\nimport { eventKey } from \"../../lib/key-event\";\nimport { useKitServices, type KitServices } from \"../../context\";\nimport { Button, IconButton } from \"../../ui/button\";\nimport {\n Menu, MenuContent, MenuItem, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, Tooltip,\n} from \"../../ui/overlay\";\nimport type { KitComponentField, KitComponentInfo, KitComponentPreviewProps, KitInsertableComponent } from \"../component-services\";\nimport type { ComponentModel, IslandEl } from \"./dom\";\nimport type { IslandCtx } from \"./blocks\";\nimport { useCatalogComponents } from \"./catalog\";\nimport { ComponentPanel, closeComponentPanel, openComponentPanel, useComponentPanel } from \"./component-panel\";\n\n/** V2 NARROW: at or under this card width the scope chip shows its icon only. */\nconst NARROW = 480;\n/** V2 PREVIEW_CAP: the preview at rest is at most this tall, faded when its content is taller. */\nconst PREVIEW_H = 240;\n\nconst placesShort = (n: number) => `${n} ${n === 1 ? \"place\" : \"places\"}`;\n\nfunction useWidth(ref: React.RefObject<HTMLElement | null>) {\n const [w, setW] = React.useState(0);\n React.useLayoutEffect(() => {\n const el = ref.current;\n if (!el) return;\n setW(el.clientWidth);\n if (typeof ResizeObserver === \"undefined\") return;\n const ro = new ResizeObserver(() => setW(el.clientWidth));\n ro.observe(el);\n return () => ro.disconnect();\n }, [ref]);\n return w;\n}\n\n/** A stored value as one line of reading text, or null when it has none (lists, empty values, flags). */\nfunction readable(v: unknown): string | null {\n if (typeof v === \"number\") return String(v);\n if (typeof v === \"string\") {\n // an inline image (an icon prop) is kilobytes of base64, never readable text\n if (v.startsWith(\"data:image/\")) return \"Image\";\n // tags become spaces; the parser then decodes what is left (`l'Excellence` → l'Excellence, → space)\n const decoded = new DOMParser().parseFromString(v.replace(/<[^>]+>/g, \" \"), \"text/html\").body.textContent ?? \"\";\n const t = decoded.replace(/\\s+/g, \" \").trim();\n return t || null;\n }\n if (v && typeof v === \"object\" && !Array.isArray(v)) {\n // a rich-text value is { html, value, format }; an image { url, altText }\n // truthy, not `??`: an empty label must not hide the html or url after it\n const o = v as { label?: unknown; text?: unknown; title?: unknown; altText?: unknown; href?: unknown; url?: unknown; html?: unknown };\n return readable(o.label || o.text || o.title || o.altText || o.href || o.url || o.html);\n }\n return null;\n}\n\nconst parseObj = (s: string | undefined): Record<string, unknown> => {\n try {\n const v = s ? (JSON.parse(s) as unknown) : {};\n return v && typeof v === \"object\" && !Array.isArray(v) ? (v as Record<string, unknown>) : {};\n } catch {\n return {};\n }\n};\n/** True when `a` is a later instant than `b`; false when either is absent or unreadable (never a made-up \"changed\"). */\nconst laterThan = (a: string | null | undefined, b: string | undefined) => {\n const x = a ? Date.parse(a) : NaN;\n const y = b ? Date.parse(b) : NaN;\n return Number.isFinite(x) && Number.isFinite(y) && x > y;\n};\nconst same = (a: unknown, b: unknown) => a === b || JSON.stringify(a) === JSON.stringify(b);\n\ntype UseComponentInfo = NonNullable<KitServices[\"useComponentInfo\"]>;\n/**\n * \"Collapse preview\", remembered per component (V2 instance-card): read before the first render, so a reload never\n * draws the preview and then folds it away. Storage that is absent or throws reads as expanded.\n */\nfunction useCollapsed(ref: string | undefined): [boolean, (next: boolean) => void] {\n const key = ref ? `bcms:card-collapsed:${ref}` : null;\n const [collapsed, setState] = React.useState(() => {\n try {\n return !!key && globalThis.localStorage?.getItem(key) === \"1\";\n } catch {\n return false;\n }\n });\n const set = React.useCallback(\n (next: boolean) => {\n setState(next);\n if (!key) return;\n try {\n if (next) globalThis.localStorage?.setItem(key, \"1\");\n else globalThis.localStorage?.removeItem(key);\n } catch {\n // not remembered; the card still folds for this session\n }\n },\n [key],\n );\n return [collapsed, set];\n}\n\ntype SetComponent = (patch: Partial<ComponentModel> | ((m: ComponentModel) => ComponentModel), label: string, record?: boolean) => void;\n\nexport function ComponentCard({\n m, el, ctx, use, overrides, set,\n}: { m: ComponentModel; el: IslandEl; ctx: IslandCtx; use: UseComponentInfo; overrides: Record<string, unknown>; set: SetComponent }) {\n const { copyComponent, toast, ComponentPreview, IconGlyph, componentVariantMember, ComponentSettings, openComponent, componentHref } = useKitServices();\n // a linked place's layout is its family's member component (a variant is its own component): the card reads and\n // draws that member, as V2 draws the instance in its variant. No member → the layout stays named in the rows.\n const member = !m.detached && m.ref && m.variant ? componentVariantMember?.(m.ref, m.variant) : undefined;\n const ref = member ?? m.ref;\n const variant = member ? undefined : m.variant;\n const { info, loading, error } = use(ref ?? \"\");\n const card = React.useRef<HTMLDivElement | null>(null);\n const width = useWidth(card);\n const narrow = !!width && width <= NARROW;\n const [collapsed, setCollapsed] = useCollapsed(m.ref);\n const [dialog, setDialog] = React.useState<null | \"detach\" | \"relink\">(null);\n const [busy, setBusy] = React.useState(false);\n const detached = !!m.detached;\n const own = React.useMemo(() => parseObj(m.props), [m.props]);\n const missing = !ref || !!info?.missing;\n const name = info && !info.missing ? info.name : m.name || info?.name || \"Block\";\n const fieldKeys = new Set((info?.fields ?? []).map((f) => f.key));\n const edited = missing || detached ? 0 : Object.keys(overrides).filter((k) => fieldKeys.has(k)).length;\n const places = info?.places;\n const known = !!info || missing;\n // compared as instants, not strings: the same publish can be spelled two ways (precision, offset)\n const changed = detached && !missing && laterThan(info?.publishedAt, m.sourcePublishedAt);\n const state = detached ? `Detached${changed ? \", Shared version changed\" : \"\"}` : missing ? \"Missing block\" : edited || m.variant ? \"Edited here\" : \"Shared\";\n // V2 instance-ui: a required prop this place leaves empty marks the scope chip, never by colour alone\n const requiredEmpty = !missing && !detached && (info?.fields ?? []).some((f) => f.required && blank(f.key in overrides ? overrides[f.key] : f.value));\n const label = `${name} block${known ? `, ${state}` : \"\"}${known && !missing && !detached && places != null ? `, ${placesShort(places)}` : \"\"}${requiredEmpty ? `. ${REQUIRED_EMPTY}` : \"\"}`;\n const rows = detached ? copyRows(own, info?.fields, m.variant) : previewRows(missing, info?.fields, overrides, variant);\n // the picture is the component with its own values (the host's snapshot): drawn only where this place shows exactly\n // that. A separate copy, an edited place or another layout would be shown content it doesn't have, so those list\n // their values instead.\n const image = missing || detached || edited || variant ? null : info?.image || null;\n // V2 draws the component itself in the card, with this place's values (linked, edited or a separate copy): the host's\n // live renderer where it has one. Another layout lists its values (the renderer draws the component's own layout).\n const liveProps = React.useMemo(\n () => (detached ? own : { ...Object.fromEntries((info?.fields ?? []).flatMap((f) => (f.value !== undefined ? [[f.key, f.value]] : []))), ...overrides }),\n [detached, own, info?.fields, overrides],\n );\n const live = ComponentPreview && ref && info && !missing && !variant ? { Preview: ComponentPreview, ref } : null;\n const preview = live ? (\n <LivePreview Preview={live.Preview} componentId={live.ref} title={name} props={liveProps} rows={rows} />\n ) : image || rows.length ? (\n <PreviewWindow image={image} rows={rows} />\n ) : null;\n const canCopy = !!copyComponent && !!m.ref && !ctx.readOnly;\n const ro = !!ctx.readOnly;\n const linked = !missing && !detached;\n const open = useComponentPanel(el);\n const editing = !!open;\n const [cardEl, setCardEl] = React.useState<HTMLDivElement | null>(null);\n const cardRef = React.useCallback((n: HTMLDivElement | null) => {\n card.current = n;\n if (n) setCardEl(n);\n }, []);\n const openPanel = React.useCallback((focusKey?: string | null) => openComponentPanel(el, focusKey ?? null), [el]);\n const closePanel = React.useCallback(() => closeComponentPanel(el), [el]);\n const focusCard = React.useCallback(() => requestAnimationFrame(() => card.current?.focus({ preventScroll: true })), []);\n // removing the component closes its panel\n React.useEffect(() => () => closeComponentPanel(el), [el]);\n const swappable = useCatalogComponents()?.components ?? [];\n const [swapTo, setSwapTo] = React.useState<KitInsertableComponent | null>(null);\n const editAll = openComponent && m.ref && info && linked\n ? { label: places != null && places > 1 ? `Edit for all ${places} places` : \"Edit the shared block\", run: () => openComponent(m.ref!) }\n : undefined;\n const href = m.ref ? componentHref?.(m.ref, m.id) : undefined;\n const hasEdits = linked && (Object.keys(overrides).length > 0 || !!m.variant);\n\n /**\n * The change as ONE undo step (IslandCtx.step: the dock's toolbar Undo, this toast's Undo and ⌘Z in the body are one\n * undo), and the toast that offers it back.\n */\n const commit = (patch: (cur: ComponentModel) => ComponentModel, label: string, title: string, description: string) => {\n const before = el.__rt as ComponentModel | undefined;\n const undo = ctx.step\n ? ctx.step(label, () => (set(patch, label, false), el), before)\n : (set(patch, label), () => (ctx.undo?.() ? (true as const) : \"Changes made after it come first. Press ⌘Z to undo them.\"));\n toast?.(title, {\n description,\n action: {\n label: \"Undo\",\n onClick: () => {\n const r = undo();\n if (r !== true) ctx.notify(\"Nothing was undone\", r);\n },\n },\n });\n };\n\n /** V2 detachNow: this place keeps what readers see now and stops following the component, as one undo step. */\n const detach = async (title: string) => {\n if (!copyComponent || !m.ref || busy) return;\n setBusy(true);\n try {\n const copy = await copyComponent(m.ref, { overrides, ...(m.variant ? { variant: m.variant } : {}) });\n commit(\n (cur) => ({\n id: cur.id,\n ref: cur.ref,\n ...(cur.name !== undefined || info?.name ? { name: cur.name ?? info?.name } : {}),\n ...(cur.variant !== undefined ? { variant: cur.variant } : {}),\n detached: true,\n props: JSON.stringify(copy.props),\n ...(copy.blocks !== undefined ? { blocks: copy.blocks } : {}),\n ...(copy.sourcePublishedAt ? { sourcePublishedAt: copy.sourcePublishedAt } : {}),\n ...(cur.extra !== undefined ? { extra: cur.extra } : {}),\n }),\n \"Make a separate copy\",\n title,\n \"It keeps its content and no longer follows the shared block.\",\n );\n } catch (e) {\n ctx.notify(\"This place couldn't keep its own copy\", e instanceof Error ? e.message : String(e));\n } finally {\n setBusy(false);\n }\n };\n\n /** V2 instanceOps.relink: keep = what differs from the component becomes overrides; reset = the component's content. */\n const relink = (mode: \"keep\" | \"reset\") => {\n const kept = copyEdits(m, own, info?.fields);\n const n = Object.keys(kept).length;\n commit(\n (cur) => ({\n id: cur.id,\n ref: cur.ref,\n ...(cur.name !== undefined ? { name: info?.name ?? cur.name } : {}),\n ...(mode === \"keep\" && Object.keys(kept).length ? { overrides: JSON.stringify(kept) } : {}),\n ...(mode === \"keep\" && cur.variant !== undefined ? { variant: cur.variant } : {}),\n ...(cur.extra !== undefined ? { extra: cur.extra } : {}),\n }),\n \"Use shared version again\",\n `${name} is shared again`,\n mode === \"keep\" && n ? `${n} ${n === 1 ? \"edit\" : \"edits\"} kept here.` : \"It shows the block's content.\",\n );\n };\n\n /** V2 instanceOps.resetAll: this place's overrides and its layout go, as one undo step. */\n const resetAll = () =>\n commit(\n (cur) => {\n const { variant: _v, ...rest } = cur;\n return { ...rest, overrides: \"{}\" };\n },\n \"Reset all edits here\",\n `Back to the shared ${name}`,\n \"This place shows the block's content again.\",\n );\n\n /**\n * V2 instanceOps.swap, once the new component's fields are known (SwapResolver): this place's edits stay only where the\n * new component declares a field with that key; everything else is the new component's own content. One undo step.\n */\n const swap = (to: KitInsertableComponent, next: KitComponentInfo) => {\n const keys = new Set((next.fields ?? []).map((f) => f.key));\n const src = detached ? own : overrides;\n const kept = Object.fromEntries(Object.entries(src).filter(([k]) => keys.has(k)));\n const n = Object.keys(kept).length;\n commit(\n (cur) => ({ id: cur.id, ref: to.id, name: next.name || to.name, overrides: JSON.stringify(kept), ...(cur.extra !== undefined ? { extra: cur.extra } : {}) }),\n `Swap to ${to.name}`,\n `Swapped to ${to.name}`,\n n ? `Kept ${n} ${n === 1 ? \"edit\" : \"edits\"} made here.` : \"It shows the block's own content.\",\n );\n };\n\n const copyLink = () => {\n if (!href) return;\n void navigator.clipboard?.writeText(href).catch(() => {});\n toast?.success(\"Link copied\", { description: `Opens this page scrolled to the ${name}.` });\n };\n\n /** The panel's form writes this place: overrides (or the layout) as one undo step each, through the island's model. */\n const onOverrides = (next: Record<string, unknown>) => {\n const changed = [...new Set([...Object.keys(next), ...Object.keys(overrides)])].find((k) => !same(next[k], overrides[k]));\n // an object patch with one label per field: the editor's history merges a burst of typing into ONE step (V2 D54)\n set({ overrides: JSON.stringify(next) }, changed ? `Edit ${changed}` : \"Edit block properties\");\n };\n const onVariant = (variant: string | undefined) =>\n set(\n (cur) => {\n const { variant: _v, ...rest } = cur;\n return variant ? { ...rest, variant } : rest;\n },\n \"Change layout\",\n );\n\n /** V2 instance card keys, on the focused card itself (fields and the portalled panel keep their own). */\n const onKeyDown = (e: React.KeyboardEvent) => {\n if (e.defaultPrevented || e.target !== card.current) return;\n const mod = e.metaKey || e.ctrlKey;\n const k = eventKey(e);\n if (mod && k === \"z\") {\n e.preventDefault();\n e.stopPropagation();\n if (e.shiftKey) ctx.redo?.();\n else ctx.undo?.();\n return;\n }\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n openPanel();\n return;\n }\n if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n if (editing) closePanel();\n else ctx.exit(el);\n return;\n }\n if (ro) return;\n if (mod && k === \"d\" && ctx.duplicate) {\n e.preventDefault();\n e.stopPropagation();\n ctx.duplicate(el);\n } else if (e.altKey && (e.key === \"ArrowUp\" || e.key === \"ArrowDown\") && ctx.move) {\n e.preventDefault();\n ctx.move(el, e.key === \"ArrowUp\" ? -1 : 1);\n focusCard();\n } else if (e.key === \"Backspace\" || e.key === \"Delete\") {\n e.preventDefault();\n ctx.remove(el);\n }\n };\n\n const chip = (compact: boolean) =>\n detached ? (\n <>\n <DetachedChip name={name} compact={compact} />\n {changed ? <ChangedChip name={name} compact={compact} onReview={canCopy ? () => setDialog(\"relink\") : undefined} /> : null}\n </>\n ) : known ? (\n <StateChip missing={missing} places={places} edited={edited} layout={!!m.variant} requiredEmpty={requiredEmpty} compact={compact} />\n ) : null;\n\n return (\n <div\n ref={cardRef}\n role=\"group\"\n tabIndex={0}\n aria-label={label}\n aria-roledescription=\"component\"\n aria-haspopup=\"dialog\"\n aria-expanded={editing}\n aria-busy={busy || undefined}\n data-instance-card=\"\"\n data-rt-isolate=\"\"\n data-state={detached ? \"detached\" : missing ? \"missing\" : known ? \"linked\" : undefined}\n onKeyDown={onKeyDown}\n onClick={(e) => {\n // a click on the card (not on its controls) opens its properties, V2 instance card\n if (!e.currentTarget.contains(e.target as Node) || (e.target as HTMLElement).closest(\"button,a,[role=menuitem],[role=note],[role=alert]\")) return;\n // on a listed value, with that field focused (the live preview is inert, so it is found by position)\n openPanel(propKeyAt(e.currentTarget, e.clientX, e.clientY));\n }}\n className={cn(\n // V2 instance-card.tsx:223 transition-colors (the focus ring stays the kit's keyboard ring, DESIGN focus rule)\n \"group/inst relative cursor-pointer rounded-kit-lg border bg-kit-control-bg text-left focus-visible:outline-offset-2 transition-colors duration-150 motion-reduce:transition-none\",\n editing\n ? \"border-transparent shadow-[0_0_0_2px_var(--kit-accent)]\"\n : missing && !detached\n ? \"border-kit-warning-line\"\n : \"border-kit-line hover:border-kit-line-strong\",\n )}\n >\n {/* Strip (V2): drag grip (hover / focus, always on touch) · icon · name · scope chip · ⋯ */}\n <div className=\"flex h-9 select-none items-center gap-1.5 pl-1 pr-1\">\n {ro || !ctx.drag ? (\n <span className=\"w-1\" />\n ) : (\n <Tooltip content=\"Drag to move\">\n <button\n type=\"button\"\n aria-label={`Move ${name}`}\n tabIndex={-1}\n onPointerDown={(e) => ctx.drag?.(el, e)}\n className=\"flex h-7 w-4 shrink-0 cursor-grab touch-none pointer-coarse:size-11 items-center justify-center rounded-kit-sm text-kit-fg-4 opacity-0 transition-opacity duration-150 hover:text-kit-fg-2 active:cursor-grabbing motion-reduce:transition-none group-hover/inst:opacity-100 group-focus-within/inst:opacity-100 pointer-coarse:opacity-100 [&_svg]:size-3.5\"\n >\n <IconGripVertical stroke={1.5} />\n </button>\n </Tooltip>\n )}\n {info?.icon && IconGlyph ? (\n <span aria-hidden className=\"flex size-[15px] shrink-0 text-kit-fg-2 [&_svg]:size-full\">\n <IconGlyph name={info.icon} className=\"size-[15px]\" />\n </span>\n ) : (\n <IconComponents size={15} stroke={1.5} className=\"shrink-0 text-kit-fg-2\" aria-hidden />\n )}\n <span className=\"min-w-0 shrink truncate text-kit-sm font-medium text-kit-fg\">{name}</span>\n {chip(narrow)}\n <span className=\"flex-1\" />\n <Menu>\n <MenuTrigger\n render={\n <IconButton size=\"sm\" className=\"shrink-0\" label={`${name} actions`}>\n <IconDots stroke={1.5} />\n </IconButton>\n }\n />\n <MenuContent align=\"end\" className=\"w-64\">\n {ComponentSettings ? (\n <MenuItem icon={<IconAdjustmentsHorizontal stroke={1.5} />} onClick={() => openPanel()}>\n Edit properties\n </MenuItem>\n ) : null}\n {editAll ? (\n <MenuItem icon={<IconArrowUpRight stroke={1.5} />} onClick={editAll.run}>\n {editAll.label}\n </MenuItem>\n ) : null}\n {!ro && hasEdits ? (\n <MenuItem icon={<IconRestore stroke={1.5} />} onClick={resetAll}>\n Reset all edits here\n </MenuItem>\n ) : null}\n {canCopy && info && !missing && !detached ? (\n <MenuItem icon={<IconUnlink stroke={1.5} />} disabled={busy} onClick={() => setDialog(\"detach\")}>\n Make a separate copy\n </MenuItem>\n ) : null}\n {canCopy && missing && !detached ? (\n <MenuItem icon={<IconUnlink stroke={1.5} />} disabled={busy} onClick={() => void detach(\"Kept as a separate copy\")}>\n Keep as a separate copy\n </MenuItem>\n ) : null}\n {canCopy && info && !missing && detached ? (\n <MenuItem icon={<IconLink stroke={1.5} />} onClick={() => setDialog(\"relink\")}>\n Use shared version again\n </MenuItem>\n ) : null}\n {!ro && swappable.length ? (\n <MenuSub>\n <MenuSubTrigger icon={<IconReplace stroke={1.5} />}>Swap block</MenuSubTrigger>\n <MenuSubContent className=\"max-h-[320px] w-60 overflow-y-auto\">\n {swappable.map((c) => {\n const on = c.id === m.ref;\n return (\n <MenuItem key={c.id} icon={<IconComponents stroke={1.5} />} disabled={on || !!swapTo} onClick={() => setSwapTo(c)}>\n <span className=\"flex w-full items-center justify-between gap-2\">\n <span className=\"truncate\">{c.name}</span>\n {on ? <IconCheck className=\"size-3.5 shrink-0 text-kit-fg-2\" stroke={2} aria-label=\"Current\" /> : null}\n </span>\n </MenuItem>\n );\n })}\n </MenuSubContent>\n </MenuSub>\n ) : null}\n {preview ? (\n <MenuItem icon={collapsed ? <IconLayoutNavbarExpand stroke={1.5} /> : <IconLayoutNavbarCollapse stroke={1.5} />} onClick={() => setCollapsed(!collapsed)}>\n {collapsed ? \"Show preview\" : \"Collapse preview\"}\n </MenuItem>\n ) : null}\n <MenuSeparator />\n {!ro && ctx.duplicate ? (\n <MenuItem icon={<IconCopy stroke={1.5} />} shortcut=\"⌘D\" onClick={() => ctx.duplicate?.(el)}>\n Duplicate\n </MenuItem>\n ) : null}\n {!ro && ctx.move ? (\n <>\n <MenuItem icon={<IconArrowBarToUp stroke={1.5} />} shortcut=\"⌥↑\" disabled={!el.previousElementSibling} onClick={() => ctx.move?.(el, -1)}>\n Move up\n </MenuItem>\n <MenuItem icon={<IconArrowBarToDown stroke={1.5} />} shortcut=\"⌥↓\" disabled={!el.nextElementSibling} onClick={() => ctx.move?.(el, 1)}>\n Move down\n </MenuItem>\n </>\n ) : null}\n {href ? (\n <MenuItem icon={<IconLink stroke={1.5} />} onClick={copyLink}>\n Copy link\n </MenuItem>\n ) : null}\n {!ro ? (\n <>\n <MenuSeparator />\n <MenuItem danger icon={<IconTrash stroke={1.5} />} shortcut=\"⌫\" onClick={() => ctx.remove(el)}>\n Remove\n </MenuItem>\n </>\n ) : null}\n </MenuContent>\n </Menu>\n </div>\n {error ? (\n <div role=\"alert\" className=\"flex items-center gap-2 border-t border-kit-line-subtle px-3 py-2.5 text-kit-sm text-kit-fg-2\">\n <IconAlertTriangle className=\"size-4 shrink-0 text-kit-warning-fg\" stroke={1.5} aria-hidden />\n <span className=\"min-w-0 flex-1\">{error}</span>\n </div>\n ) : null}\n {missing && !detached && !loading ? (\n <div className=\"flex flex-wrap items-center gap-2 border-t border-kit-line-subtle px-3 py-2.5 text-kit-sm\" role=\"note\">\n <IconAlertTriangle className=\"size-4 shrink-0 text-kit-warning-fg\" stroke={1.5} aria-hidden />\n <span className=\"min-w-0 flex-1 text-kit-fg-2\">The original “{name}” was deleted. Readers see nothing in this place.</span>\n {ctx.readOnly ? null : (\n <span className=\"flex shrink-0 items-center gap-1.5\">\n {canCopy ? (\n <Button size=\"xs\" variant=\"secondary\" loading={busy} onClick={() => void detach(\"Kept as a separate copy\")}>\n Keep as a separate copy\n </Button>\n ) : null}\n <Button size=\"xs\" variant=\"danger-ghost\" onClick={() => ctx.remove(el)}>\n Remove\n </Button>\n </span>\n )}\n </div>\n ) : null}\n {collapsed ? null : preview}\n {canCopy ? (\n <>\n <DetachDialog\n open={dialog === \"detach\"}\n name={name}\n places={places}\n onClose={() => setDialog(null)}\n onConfirm={() => {\n setDialog(null);\n void detach(`Separate copy of ${name}`);\n }}\n />\n <RelinkDialog\n open={dialog === \"relink\"}\n name={name}\n kept={Object.keys(copyEdits(m, own, info?.fields)).length}\n onClose={() => setDialog(null)}\n onConfirm={(mode) => {\n setDialog(null);\n relink(mode);\n }}\n />\n </>\n ) : null}\n {swapTo ? (\n <SwapResolver\n use={use}\n to={swapTo}\n onReady={(next) => {\n setSwapTo(null);\n swap(swapTo, next);\n }}\n onFail={(why) => {\n setSwapTo(null);\n ctx.notify(`Couldn't swap to ${swapTo.name}`, why);\n }}\n />\n ) : null}\n {open ? (\n <ComponentPanel\n name={name}\n chip={chip(false)}\n anchor={cardEl}\n open={open}\n editAll={editAll}\n onClose={closePanel}\n focusBack={focusCard}\n settings={{\n componentId: m.ref ?? \"\",\n overrides,\n ...(m.variant ? { variant: m.variant } : {}),\n ...(detached ? { detached: { props: own } } : {}),\n // a separate copy keeps the values it was made with (its frozen blocks are drawn from them): read-only here\n readOnly: ro || detached || missing,\n onOverrides,\n onVariant,\n }}\n />\n ) : null}\n </div>\n );\n}\n\n/**\n * A separate copy's EDITS, which it keeps as overrides when it follows the component again: its values that differ from\n * the snapshot taken when the copy was made, never from the component as it is now (a republish since is not an edit\n * of this place; the owner saw \"2 fields stay as they are\" with nothing edited).\n *\n * A copy made here stores that snapshot: its values (`props`) with the blocks drawn from them (`blocks`), and no\n * surface edits a copy's values afterwards, so it has no edits. Copy markup from V2 stores no snapshot (no `blocks`):\n * its values that differ from the component's, on fields the component has (V2 instanceOps.relink).\n */\nfunction copyEdits(m: ComponentModel, own: Record<string, unknown>, fields: KitComponentField[] | undefined): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (m.blocks !== undefined) return out;\n for (const f of fields ?? []) if (f.key in own && !same(own[f.key], f.value)) out[f.key] = own[f.key];\n return out;\n}\n\nconst REQUIRED_EMPTY = \"Required field empty.\";\n/** Nothing an author would call filled in: no value, blank text, an empty list. */\nconst blank = (v: unknown) => v == null || (typeof v === \"string\" && !v.trim()) || (Array.isArray(v) && v.length === 0);\n\n/** V2 StateChip: 13px, neutral, not a pill; the missing chip is the one tinted state. */\nfunction StateChip({ missing, places, edited, layout, requiredEmpty, compact }: { missing: boolean; places?: number; edited: number; layout?: boolean; requiredEmpty?: boolean; compact: boolean }) {\n const base = CHIP;\n if (missing) {\n return (\n <Tooltip content=\"The block was deleted. Readers see nothing in this place.\">\n <span className={cn(base, \"bg-kit-warning-soft px-1.5 text-kit-warning-fg\")}>\n <IconAlertTriangle className=\"size-3.5 shrink-0\" stroke={1.5} aria-hidden />\n {compact ? <span className=\"sr-only\">Missing block</span> : \"Missing block\"}\n </span>\n </Tooltip>\n );\n }\n const count = places ? placesShort(places) : null;\n const tip = `Changes here apply only to this place. Edit the block to change ${places && places > 1 ? `all ${places}` : \"it everywhere\"}.${\n edited ? ` ${edited} ${edited === 1 ? \"field\" : \"fields\"} edited here.` : \"\"}${layout ? \" Its layout is set here.\" : \"\"}${requiredEmpty ? ` ${REQUIRED_EMPTY}` : \"\"\n }`;\n return (\n <Tooltip content={tip}>\n <span className={cn(base, \"px-1 text-kit-fg-2\")} tabIndex={-1}>\n {requiredEmpty ? <span data-required-empty className=\"size-1.5 shrink-0 rounded-full bg-kit-danger-fg\" aria-hidden /> : null}\n <IconLink className=\"size-3.5 shrink-0\" stroke={1.5} aria-hidden />\n {compact ? <span className=\"sr-only\">Shared{count ? `, ${count}` : \"\"}</span> : count ?? \"Shared\"}\n {!compact && count ? <span className=\"sr-only\">, shared</span> : null}\n {edited || layout ? (\n <>\n <span className=\"ml-1 size-1.5 shrink-0 rounded-full bg-kit-accent\" aria-hidden />\n {compact ? <span className=\"sr-only\">, edited here</span> : <span>Edited here</span>}\n </>\n ) : null}\n </span>\n </Tooltip>\n );\n}\n\nconst CHIP = \"inline-flex h-6 shrink-0 items-center gap-1 rounded-kit-md text-[13px] leading-none whitespace-nowrap\";\n\n/** V2 StateChip, detached: fg-3, the unlink glyph. */\nfunction DetachedChip({ name, compact }: { name: string; compact: boolean }) {\n return (\n <Tooltip content={`A separate copy. Changes to ${name} don't reach it.`}>\n <span className={cn(CHIP, \"px-1 text-kit-fg-3\")} tabIndex={-1}>\n <IconUnlink className=\"size-3.5 shrink-0\" stroke={1.5} aria-hidden />\n {compact ? <span className=\"sr-only\">Detached</span> : \"Detached\"}\n </span>\n </Tooltip>\n );\n}\n\n/** V2 StateChip, update: a quiet button that opens the way back to the shared version. */\nfunction ChangedChip({ name, compact, onReview }: { name: string; compact: boolean; onReview?: () => void }) {\n return (\n <Tooltip content={`${name} changed since this copy was made.`}>\n <button\n type=\"button\"\n onClick={onReview}\n disabled={!onReview}\n className={cn(CHIP, \"px-1 text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg disabled:hover:bg-transparent\")}\n >\n <IconRefresh className=\"size-3.5 shrink-0\" stroke={1.5} aria-hidden />\n {compact ? <span className=\"sr-only\">Shared version changed</span> : \"Shared version changed\"}\n </button>\n </Tooltip>\n );\n}\n\n/** V2 useInstanceDialogs \"detach\": confirm before this place stops following the component. */\nfunction DetachDialog({ open, name, places, onClose, onConfirm }: { open: boolean; name: string; places?: number; onClose: () => void; onConfirm: () => void }) {\n const others = places != null ? places - 1 : null;\n return (\n <Modal open={open} onOpenChange={(o) => !o && onClose()}>\n <ModalContent size=\"sm\">\n <ModalHeader title={`Make a separate copy of ${name}?`} description=\"This place keeps its current content and stops following the shared block.\" />\n {others != null ? (\n <ModalBody className=\"pt-2 text-kit-sm text-kit-fg-2\">\n {others > 0 ? `The other ${others === 1 ? \"place stays\" : `${others} places stay`} shared.` : \"No other place uses it.\"}\n </ModalBody>\n ) : null}\n <ModalFooter>\n <Button variant=\"ghost\" onClick={onClose}>\n Cancel\n </Button>\n <Button variant=\"primary\" autoFocus onClick={onConfirm}>\n Make a copy\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n );\n}\n\n/** V2 RelinkDialog: keep this place's edits as overrides, or take the component's content. */\nfunction RelinkDialog({ open, name, kept, onClose, onConfirm }: { open: boolean; name: string; kept: number; onClose: () => void; onConfirm: (mode: \"keep\" | \"reset\") => void }) {\n const [mode, setMode] = React.useState<\"keep\" | \"reset\">(\"keep\");\n React.useEffect(() => {\n if (open) setMode(\"keep\");\n }, [open]);\n const rows: { v: \"keep\" | \"reset\"; title: string; line: string }[] = [\n {\n v: \"keep\",\n title: \"Keep my edits here\",\n line: kept ? `${kept} ${kept === 1 ? \"field stays\" : \"fields stay\"} as ${kept === 1 ? \"it is\" : \"they are\"}; everything else follows ${name} again.` : `Nothing differs, so it simply follows ${name} again.`,\n },\n { v: \"reset\", title: `Use ${name}'s content`, line: \"Drops the edits made here. Undo is one click away.\" },\n ];\n return (\n <Modal open={open} onOpenChange={(o) => !o && onClose()}>\n <ModalContent size=\"sm\">\n <ModalHeader title={`Use the shared ${name} again?`} description=\"This place follows the shared block again.\" />\n <ModalBody className=\"pt-3\">\n <div\n role=\"radiogroup\"\n aria-label=\"Use shared version again\"\n className=\"flex flex-col divide-y divide-kit-line overflow-hidden rounded-kit-lg border border-kit-line\"\n onKeyDown={(e) => {\n // a radio group moves with the arrow keys (one tab stop, the checked row)\n if (![\"ArrowUp\", \"ArrowDown\", \"ArrowLeft\", \"ArrowRight\"].includes(e.key)) return;\n e.preventDefault();\n const next = mode === \"keep\" ? \"reset\" : \"keep\";\n setMode(next);\n (e.currentTarget.querySelector(`[data-mode=\"${next}\"]`) as HTMLElement | null)?.focus();\n }}\n >\n {rows.map((row) => (\n <button\n key={row.v}\n type=\"button\"\n role=\"radio\"\n data-mode={row.v}\n tabIndex={mode === row.v ? 0 : -1}\n aria-checked={mode === row.v}\n onClick={() => setMode(row.v)}\n className={cn(\"flex min-h-14 items-start gap-3 px-3 py-2.5 text-left transition-colors hover:bg-kit-hover\", mode === row.v && \"bg-kit-subtle\")}\n >\n <span className={cn(\"mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-full border\", mode === row.v ? \"border-kit-control-checked\" : \"border-kit-line-strong\")}>\n {mode === row.v ? <span className=\"size-2 rounded-full bg-kit-fg\" /> : null}\n </span>\n <span className=\"min-w-0\">\n <span className=\"block text-kit-sm font-medium text-kit-fg\">{row.title}</span>\n <span className=\"block text-kit-xs text-kit-fg-3\">{row.line}</span>\n </span>\n </button>\n ))}\n </div>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={onClose}>\n Cancel\n </Button>\n <Button variant=\"primary\" onClick={() => onConfirm(mode)}>\n Use shared version\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n );\n}\n\ninterface Row {\n key: string;\n label: string;\n text: string;\n}\n\n/**\n * What the window lists when there is no picture: each field's value as this place shows it (its override, else the\n * component's own), then the layout this place draws it in. A missing component has only what this place stored: its\n * overrides, named by their keys, and its layout.\n */\n/** A choice field's value as its option's label (BUG-8: a select whose values are ids listed the id); others as they are. */\nfunction chosen(f: KitComponentField, v: unknown): unknown {\n if (!f.options) return v;\n const label = (x: unknown) => f.options!.find((o) => o.value === x)?.label ?? x;\n return Array.isArray(v) ? v.map(label).join(\", \") : label(v);\n}\n\nfunction previewRows(missing: boolean, fields: KitComponentField[] | undefined, overrides: Record<string, unknown>, variant?: string): Row[] {\n const out: Row[] = [];\n if (missing || !fields) {\n for (const [key, v] of Object.entries(overrides)) {\n const text = readable(v);\n if (text) out.push({ key, label: key, text });\n }\n } else {\n for (const f of fields) {\n const text = readable(chosen(f, f.key in overrides ? overrides[f.key] : f.value));\n if (text) out.push({ key: f.key, label: f.label, text });\n }\n }\n if (variant) out.push({ key: \"__variant\", label: \"Layout\", text: variant });\n return out;\n}\n\n/**\n * A separate copy's values (V2 `props`) in the component's field order. A field the copy doesn't hold draws the\n * component's value for it, as V2's renderer does for a copy (it draws the def with `props`, defaults for the rest);\n * a value the component no longer has a field for follows, under its key. Then its layout.\n */\nfunction copyRows(own: Record<string, unknown>, fields: KitComponentField[] | undefined, variant?: string): Row[] {\n const out: Row[] = [];\n const push = (key: string, label: string, v: unknown) => {\n const text = readable(v);\n if (text) out.push({ key, label, text });\n };\n for (const f of fields ?? []) push(f.key, f.label, chosen(f, f.key in own ? own[f.key] : f.value));\n for (const [key, v] of Object.entries(own)) if (!fields?.some((f) => f.key === key)) push(key, key, v);\n if (variant) out.push({ key: \"__variant\", label: \"Layout\", text: variant });\n return out;\n}\n\n/**\n * The preview's frame: under the card's header, capped at PREVIEW_H (its top border inside, as V2's CappedPreview).\n * The cap lifts instantly on hover: a height animation is layout work every frame (canvas revamp V937).\n */\nconst PREVIEW_CHROME = \"group/cap relative max-h-[240px] overflow-hidden rounded-b-kit-lg border-t border-kit-line-subtle\";\n\n/**\n * V2 instance-card CappedPreview: at most 240px, faded at its foot when the content is taller; hover shows its full\n * height. Measured a frame after each resize, so a frame or picture that sizes itself late is read once settled.\n */\nfunction CappedPreview({ live, children }: { live?: boolean; children: React.ReactNode }) {\n const inner = React.useRef<HTMLDivElement>(null);\n const [tall, setTall] = React.useState(false);\n // a live frame is the site: on V2's light site paper in both themes; a listing or picture stays on the themed chrome\n const [site, setSite] = React.useState(false);\n React.useLayoutEffect(() => {\n const el = inner.current;\n if (!el) return;\n let raf = 0;\n const measure = () => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(() => {\n setTall(el.offsetHeight > PREVIEW_H + 1);\n setSite(!!el.querySelector(\"iframe\"));\n });\n };\n measure();\n const ro = typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(measure);\n ro?.observe(el);\n // the frame can mount without a size change (the shell keeps its remembered height), so a mount re-measures too\n const mo = typeof MutationObserver === \"undefined\" ? null : new MutationObserver(measure);\n mo?.observe(el, { childList: true, subtree: true });\n return () => {\n ro?.disconnect();\n mo?.disconnect();\n cancelAnimationFrame(raf);\n };\n }, []);\n return (\n <div\n data-instance-preview=\"\"\n data-live={live ? \"\" : undefined}\n data-tall={tall ? \"\" : undefined}\n data-site={site ? \"\" : undefined}\n className={cn(PREVIEW_CHROME, site ? \"bg-kit-site-paper\" : \"bg-kit-subtle\", tall && \"can-hover:hover:max-h-[2400px]\")}\n >\n <div ref={inner}>{children}</div>\n {/* V2's fade: inside the capped box, into its paper (the site paper under a live frame, else the chrome) */}\n {tall ? (\n <div\n aria-hidden\n className={cn(\n \"pointer-events-none absolute inset-x-0 bottom-0 h-6 bg-gradient-to-b from-transparent transition-opacity duration-150 ease-out can-hover:group-hover/cap:opacity-0 motion-reduce:transition-none\",\n site ? \"to-kit-site-paper\" : \"to-kit-subtle\",\n )}\n />\n ) : null}\n </div>\n );\n}\n\nfunction PreviewWindow({ image, rows }: { image: string | null; rows: Row[] }) {\n return (\n <CappedPreview>\n <PreviewBody image={image} rows={rows} />\n </CappedPreview>\n );\n}\n\n/**\n * The component drawn live by the host (KitServices.ComponentPreview), mounted once the card is on screen. Its height is\n * reserved from the start (PREVIEW_H), so the card never moves while it loads; where the host cannot draw it, the values\n * are listed under the reason.\n */\nfunction LivePreview({\n Preview,\n componentId,\n title,\n props,\n rows,\n}: {\n Preview: React.ComponentType<KitComponentPreviewProps>;\n componentId: string;\n title: string;\n props: Record<string, unknown>;\n rows: Row[];\n}) {\n const box = React.useRef<HTMLDivElement>(null);\n const [seen, setSeen] = React.useState(() => typeof IntersectionObserver === \"undefined\");\n React.useEffect(() => {\n const el = box.current;\n if (seen || !el) return;\n const io = new IntersectionObserver((entries) => {\n if (entries.some((e) => e.isIntersecting)) setSeen(true);\n });\n io.observe(el);\n return () => io.disconnect();\n }, [seen]);\n return (\n <CappedPreview live>\n <div ref={box}>\n {seen ? (\n <Preview componentId={componentId} title={title} props={props} fallback={(reason) => <PreviewBody image={null} rows={rows} note={reason} />} />\n ) : (\n <div aria-hidden style={{ height: PREVIEW_H }} />\n )}\n </div>\n </CappedPreview>\n );\n}\n\nfunction PreviewBody({ image, rows, note }: { image: string | null; rows: Row[]; note?: string }) {\n // a picture's height is unknown until it loads: the cap is held until then, so the card doesn't jump when it lands\n const [loaded, setLoaded] = React.useState(!image);\n return (\n <div style={!loaded ? { height: PREVIEW_H } : undefined}>\n {image ? (\n // the whole width, scaled to the card like V2's frame (top-left origin): never cropped at the sides\n <img src={image} alt=\"\" className=\"block h-auto w-full\" draggable={false} onLoad={() => setLoaded(true)} onError={() => setLoaded(true)} />\n ) : (\n <>\n {note ? <p className=\"px-4 pt-3 text-kit-xs text-kit-fg-3\">{note}</p> : null}\n <dl className=\"flex flex-col gap-3 px-4 py-3.5\">\n {rows.map((r) => (\n // a click on a listed value opens the panel on that field (the card reads it by position: propKeyAt)\n <div key={r.key} data-prop-key={r.key === \"__variant\" ? undefined : r.key} className=\"min-w-0\">\n <dt className=\"truncate text-kit-xs text-kit-fg-3\">{r.label}</dt>\n <dd className=\"mt-0.5 line-clamp-3 text-kit-sm text-kit-fg\">{r.text}</dd>\n </div>\n ))}\n </dl>\n </>\n )}\n </div>\n );\n}\n\n/** The listed value (`data-prop-key`) under a point of the card, else null. */\nfunction propKeyAt(root: HTMLElement, x: number, y: number): string | null {\n for (const row of root.querySelectorAll<HTMLElement>(\"[data-prop-key]\")) {\n const r = row.getBoundingClientRect();\n if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) return row.dataset.propKey ?? null;\n }\n return null;\n}\n\n/**\n * Swap component: the new component's fields come from the same lookup the card reads (KitServices.useComponentInfo, a\n * hook, so it is asked from a component of its own). Answers once, when they are known.\n */\nfunction SwapResolver({\n use, to, onReady, onFail,\n}: {\n use: UseComponentInfo;\n to: KitInsertableComponent;\n onReady: (info: KitComponentInfo) => void;\n onFail: (why: string) => void;\n}) {\n const { info, error } = use(to.id);\n const done = React.useRef(false);\n React.useEffect(() => {\n if (done.current) return;\n if (error) {\n done.current = true;\n onFail(error);\n } else if (info?.missing) {\n done.current = true;\n onFail(\"The library has no such block.\");\n } else if (info) {\n done.current = true;\n onReady(info);\n }\n });\n return null;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An embedded component's properties panel (V2 features/blocks/instance-panel.tsx, CPO D54): this place's settings in
|
|
3
|
+
* the kit FloatingPanel beside the text. One panel at a time: opening another card's panel refills it at the same spot
|
|
4
|
+
* and size, with no entrance animation.
|
|
5
|
+
*
|
|
6
|
+
* header (40px, the drag handle) name · scope chip · [Show in editor] (only while the card is out of view) · ×
|
|
7
|
+
* body the host's settings form (KitServices.ComponentSettings), else a sentence and
|
|
8
|
+
* "Edit for all N places"
|
|
9
|
+
*
|
|
10
|
+
* Opens from a click on the card, Enter on the focused card, ⋯ › Edit properties, or a fresh insert
|
|
11
|
+
* (`openComponentPanel`, which the editor calls before the card has mounted). Closes with Esc (menus and drafts first),
|
|
12
|
+
* ×, or removing the component; focus goes back to the card.
|
|
13
|
+
*/
|
|
14
|
+
import * as React from "react";
|
|
15
|
+
import type { KitComponentSettingsProps } from "../component-services";
|
|
16
|
+
import type { IslandEl } from "./dom";
|
|
17
|
+
interface PanelState {
|
|
18
|
+
el: IslandEl;
|
|
19
|
+
/** the field to focus on open; `nonce` lets the same field be asked for twice */
|
|
20
|
+
focusKey: string | null;
|
|
21
|
+
nonce: number;
|
|
22
|
+
/** another card's panel was open: refill in place, no entrance animation */
|
|
23
|
+
refill: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare function openComponentPanel(el: IslandEl, focusKey?: string | null): void;
|
|
26
|
+
/** Closes `el`'s panel (any panel when `el` is omitted). */
|
|
27
|
+
export declare function closeComponentPanel(el?: IslandEl): void;
|
|
28
|
+
/** The open panel when it is `el`'s, else null. */
|
|
29
|
+
export declare function useComponentPanel(el: IslandEl): PanelState | null;
|
|
30
|
+
export declare function ComponentPanel({ name, chip, anchor, open, settings, editAll, onClose, focusBack, }: {
|
|
31
|
+
name: string;
|
|
32
|
+
/** the card's scope chip (V2 StateChip) */
|
|
33
|
+
chip: React.ReactNode;
|
|
34
|
+
/** the card: the panel docks beside its column and follows it */
|
|
35
|
+
anchor: HTMLElement | null;
|
|
36
|
+
open: PanelState;
|
|
37
|
+
/** what the host's settings form edits; the panel fills in `focusKey` */
|
|
38
|
+
settings: Omit<KitComponentSettingsProps, "focusKey">;
|
|
39
|
+
/** "Edit for all N places", when the host can open the component */
|
|
40
|
+
editAll?: {
|
|
41
|
+
label: string;
|
|
42
|
+
run: () => void;
|
|
43
|
+
};
|
|
44
|
+
onClose: () => void;
|
|
45
|
+
focusBack: () => void;
|
|
46
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { useKitServices } from "../../context.js";
|
|
2
|
+
import { Button, IconButton } from "../../ui/button.js";
|
|
3
|
+
import { FloatingPanel } from "../../ui/floating-panel.js";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { IconArrowUpRight, IconCrosshair, IconX } from "@tabler/icons-react";
|
|
7
|
+
//#region src/controls/rich-text/component-panel.tsx
|
|
8
|
+
/**
|
|
9
|
+
* An embedded component's properties panel (V2 features/blocks/instance-panel.tsx, CPO D54): this place's settings in
|
|
10
|
+
* the kit FloatingPanel beside the text. One panel at a time: opening another card's panel refills it at the same spot
|
|
11
|
+
* and size, with no entrance animation.
|
|
12
|
+
*
|
|
13
|
+
* header (40px, the drag handle) name · scope chip · [Show in editor] (only while the card is out of view) · ×
|
|
14
|
+
* body the host's settings form (KitServices.ComponentSettings), else a sentence and
|
|
15
|
+
* "Edit for all N places"
|
|
16
|
+
*
|
|
17
|
+
* Opens from a click on the card, Enter on the focused card, ⋯ › Edit properties, or a fresh insert
|
|
18
|
+
* (`openComponentPanel`, which the editor calls before the card has mounted). Closes with Esc (menus and drafts first),
|
|
19
|
+
* ×, or removing the component; focus goes back to the card.
|
|
20
|
+
*/
|
|
21
|
+
var state = null;
|
|
22
|
+
var nonce = 0;
|
|
23
|
+
var subs = /* @__PURE__ */ new Set();
|
|
24
|
+
var publish = (next) => {
|
|
25
|
+
state = next;
|
|
26
|
+
subs.forEach((f) => f());
|
|
27
|
+
};
|
|
28
|
+
function openComponentPanel(el, focusKey = null) {
|
|
29
|
+
publish({
|
|
30
|
+
el,
|
|
31
|
+
focusKey,
|
|
32
|
+
nonce: ++nonce,
|
|
33
|
+
refill: !!state && state.el !== el
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/** Closes `el`'s panel (any panel when `el` is omitted). */
|
|
37
|
+
function closeComponentPanel(el) {
|
|
38
|
+
if (state && (!el || state.el === el)) publish(null);
|
|
39
|
+
}
|
|
40
|
+
/** The open panel when it is `el`'s, else null. */
|
|
41
|
+
function useComponentPanel(el) {
|
|
42
|
+
const s = React.useSyncExternalStore((cb) => (subs.add(cb), () => void subs.delete(cb)), () => state, () => state);
|
|
43
|
+
return s && s.el === el ? s : null;
|
|
44
|
+
}
|
|
45
|
+
function useInView(el) {
|
|
46
|
+
const [seen, setSeen] = React.useState(true);
|
|
47
|
+
React.useEffect(() => {
|
|
48
|
+
if (!el || typeof IntersectionObserver === "undefined") return;
|
|
49
|
+
const io = new IntersectionObserver((list) => setSeen(list.some((x) => x.isIntersecting)), { threshold: 0 });
|
|
50
|
+
io.observe(el);
|
|
51
|
+
return () => io.disconnect();
|
|
52
|
+
}, [el]);
|
|
53
|
+
return seen;
|
|
54
|
+
}
|
|
55
|
+
var FOCUSABLE = "input:not([type=hidden]), textarea, select, [contenteditable=true], button, [tabindex]:not([tabindex='-1'])";
|
|
56
|
+
function ComponentPanel({ name, chip, anchor, open, settings, editAll, onClose, focusBack }) {
|
|
57
|
+
const { ComponentSettings } = useKitServices();
|
|
58
|
+
const panel = React.useRef(null);
|
|
59
|
+
const titleId = React.useId();
|
|
60
|
+
const inView = useInView(anchor);
|
|
61
|
+
const container = anchor?.closest("[data-expanded-editor]") ?? null;
|
|
62
|
+
React.useEffect(() => panel.current?.announce(`${name} properties.`), [name]);
|
|
63
|
+
React.useEffect(() => {
|
|
64
|
+
const t = window.setTimeout(() => {
|
|
65
|
+
const root = panel.current?.el();
|
|
66
|
+
if (!root || root.contains(document.activeElement)) return;
|
|
67
|
+
const body = root.querySelector("[data-panel-body]");
|
|
68
|
+
const row = open.focusKey ? Array.from(body?.querySelectorAll("[data-field-key]") ?? []).find((r) => r.getAttribute("data-field-key") === open.focusKey) : null;
|
|
69
|
+
const list = Array.from((row ?? body)?.querySelectorAll(FOCUSABLE) ?? []);
|
|
70
|
+
(list.find((n) => n.getClientRects().length) ?? list[0] ?? root).focus({ preventScroll: true });
|
|
71
|
+
}, 60);
|
|
72
|
+
return () => window.clearTimeout(t);
|
|
73
|
+
}, [open.nonce]);
|
|
74
|
+
const close = () => (onClose(), focusBack());
|
|
75
|
+
return /* @__PURE__ */ jsx(FloatingPanel, {
|
|
76
|
+
ref: panel,
|
|
77
|
+
id: "component-properties",
|
|
78
|
+
labelledBy: titleId,
|
|
79
|
+
anchor,
|
|
80
|
+
container,
|
|
81
|
+
header: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
82
|
+
/* @__PURE__ */ jsx("span", {
|
|
83
|
+
id: titleId,
|
|
84
|
+
className: "min-w-0 shrink truncate text-kit-sm font-medium text-kit-fg",
|
|
85
|
+
children: name
|
|
86
|
+
}),
|
|
87
|
+
chip,
|
|
88
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
89
|
+
!inView && anchor ? /* @__PURE__ */ jsx(IconButton, {
|
|
90
|
+
size: "sm",
|
|
91
|
+
label: "Show in editor",
|
|
92
|
+
tooltip: "Show in editor",
|
|
93
|
+
onClick: () => anchor.scrollIntoView({
|
|
94
|
+
block: "center",
|
|
95
|
+
behavior: window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth"
|
|
96
|
+
}),
|
|
97
|
+
children: /* @__PURE__ */ jsx(IconCrosshair, { stroke: 1.5 })
|
|
98
|
+
}) : null,
|
|
99
|
+
/* @__PURE__ */ jsx(IconButton, {
|
|
100
|
+
size: "sm",
|
|
101
|
+
label: "Close properties",
|
|
102
|
+
tooltip: "Close",
|
|
103
|
+
onClick: close,
|
|
104
|
+
children: /* @__PURE__ */ jsx(IconX, { stroke: 1.5 })
|
|
105
|
+
})
|
|
106
|
+
] }),
|
|
107
|
+
onClose,
|
|
108
|
+
focusBack,
|
|
109
|
+
instant: open.refill,
|
|
110
|
+
sheetFooter: /* @__PURE__ */ jsx(Button, {
|
|
111
|
+
size: "sm",
|
|
112
|
+
variant: "primary",
|
|
113
|
+
onClick: close,
|
|
114
|
+
children: "Done"
|
|
115
|
+
}),
|
|
116
|
+
children: ComponentSettings ? /* @__PURE__ */ jsx("div", {
|
|
117
|
+
"data-component-settings": "",
|
|
118
|
+
className: "min-w-0 pb-3 pt-1",
|
|
119
|
+
children: /* @__PURE__ */ jsx(ComponentSettings, {
|
|
120
|
+
...settings,
|
|
121
|
+
focusKey: open.focusKey
|
|
122
|
+
})
|
|
123
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
124
|
+
className: "flex flex-col items-start gap-3 px-3 py-3 text-kit-sm text-kit-fg-2",
|
|
125
|
+
children: [/* @__PURE__ */ jsx("p", { children: "This place's fields are edited in the block." }), editAll ? /* @__PURE__ */ jsxs(Button, {
|
|
126
|
+
size: "sm",
|
|
127
|
+
variant: "secondary",
|
|
128
|
+
onClick: editAll.run,
|
|
129
|
+
children: [/* @__PURE__ */ jsx(IconArrowUpRight, {
|
|
130
|
+
stroke: 1.5,
|
|
131
|
+
className: "size-4",
|
|
132
|
+
"aria-hidden": true
|
|
133
|
+
}), editAll.label]
|
|
134
|
+
}) : null]
|
|
135
|
+
})
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
//#endregion
|
|
139
|
+
export { ComponentPanel, closeComponentPanel, openComponentPanel, useComponentPanel };
|
|
140
|
+
|
|
141
|
+
//# sourceMappingURL=component-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-panel.js","names":[],"sources":["../../../src/controls/rich-text/component-panel.tsx"],"sourcesContent":["/**\n * An embedded component's properties panel (V2 features/blocks/instance-panel.tsx, CPO D54): this place's settings in\n * the kit FloatingPanel beside the text. One panel at a time: opening another card's panel refills it at the same spot\n * and size, with no entrance animation.\n *\n * header (40px, the drag handle) name · scope chip · [Show in editor] (only while the card is out of view) · ×\n * body the host's settings form (KitServices.ComponentSettings), else a sentence and\n * \"Edit for all N places\"\n *\n * Opens from a click on the card, Enter on the focused card, ⋯ › Edit properties, or a fresh insert\n * (`openComponentPanel`, which the editor calls before the card has mounted). Closes with Esc (menus and drafts first),\n * ×, or removing the component; focus goes back to the card.\n */\nimport * as React from \"react\";\nimport { IconArrowUpRight, IconCrosshair, IconX } from \"@tabler/icons-react\";\nimport { useKitServices } from \"../../context\";\nimport { Button, IconButton } from \"../../ui/button\";\nimport { FloatingPanel, type FloatingPanelHandle } from \"../../ui/floating-panel\";\nimport type { KitComponentSettingsProps } from \"../component-services\";\nimport type { IslandEl } from \"./dom\";\n\n/* ── Which card's panel is open (one at a time), keyed by the island element so an insert can open it before the card mounts ── */\ninterface PanelState {\n el: IslandEl;\n /** the field to focus on open; `nonce` lets the same field be asked for twice */\n focusKey: string | null;\n nonce: number;\n /** another card's panel was open: refill in place, no entrance animation */\n refill: boolean;\n}\nlet state: PanelState | null = null;\nlet nonce = 0;\nconst subs = new Set<() => void>();\nconst publish = (next: PanelState | null) => {\n state = next;\n subs.forEach((f) => f());\n};\nexport function openComponentPanel(el: IslandEl, focusKey: string | null = null) {\n publish({ el, focusKey, nonce: ++nonce, refill: !!state && state.el !== el });\n}\n/** Closes `el`'s panel (any panel when `el` is omitted). */\nexport function closeComponentPanel(el?: IslandEl) {\n if (state && (!el || state.el === el)) publish(null);\n}\n/** The open panel when it is `el`'s, else null. */\nexport function useComponentPanel(el: IslandEl): PanelState | null {\n const s = React.useSyncExternalStore(\n (cb) => (subs.add(cb), () => void subs.delete(cb)),\n () => state,\n () => state,\n );\n return s && s.el === el ? s : null;\n}\n\nfunction useInView(el: HTMLElement | null) {\n const [seen, setSeen] = React.useState(true);\n React.useEffect(() => {\n if (!el || typeof IntersectionObserver === \"undefined\") return;\n const io = new IntersectionObserver((list) => setSeen(list.some((x) => x.isIntersecting)), { threshold: 0 });\n io.observe(el);\n return () => io.disconnect();\n }, [el]);\n return seen;\n}\n\nconst FOCUSABLE = \"input:not([type=hidden]), textarea, select, [contenteditable=true], button, [tabindex]:not([tabindex='-1'])\";\n\nexport function ComponentPanel({\n name, chip, anchor, open, settings, editAll, onClose, focusBack,\n}: {\n name: string;\n /** the card's scope chip (V2 StateChip) */\n chip: React.ReactNode;\n /** the card: the panel docks beside its column and follows it */\n anchor: HTMLElement | null;\n open: PanelState;\n /** what the host's settings form edits; the panel fills in `focusKey` */\n settings: Omit<KitComponentSettingsProps, \"focusKey\">;\n /** \"Edit for all N places\", when the host can open the component */\n editAll?: { label: string; run: () => void };\n onClose: () => void;\n focusBack: () => void;\n}) {\n const { ComponentSettings } = useKitServices();\n const panel = React.useRef<FloatingPanelHandle>(null);\n const titleId = React.useId();\n const inView = useInView(anchor);\n const container = anchor?.closest<HTMLElement>(\"[data-expanded-editor]\") ?? null;\n React.useEffect(() => panel.current?.announce(`${name} properties.`), [name]);\n React.useEffect(() => {\n // the panel mounts (and, inside the expanded editor, docks) over a few frames: focus lands on the field asked for,\n // else the first control in the body, never taken from somewhere the person already went inside it\n const t = window.setTimeout(() => {\n const root = panel.current?.el();\n if (!root || root.contains(document.activeElement)) return;\n const body = root.querySelector<HTMLElement>(\"[data-panel-body]\");\n const row = open.focusKey ? Array.from(body?.querySelectorAll<HTMLElement>(\"[data-field-key]\") ?? []).find((r) => r.getAttribute(\"data-field-key\") === open.focusKey) : null;\n const list = Array.from((row ?? body)?.querySelectorAll<HTMLElement>(FOCUSABLE) ?? []);\n (list.find((n) => n.getClientRects().length) ?? list[0] ?? root).focus({ preventScroll: true });\n }, 60);\n return () => window.clearTimeout(t);\n }, [open.nonce]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const close = () => (onClose(), focusBack());\n const header = (\n <>\n <span id={titleId} className=\"min-w-0 shrink truncate text-kit-sm font-medium text-kit-fg\">{name}</span>\n {chip}\n <span className=\"flex-1\" />\n {!inView && anchor ? (\n <IconButton size=\"sm\" label=\"Show in editor\" tooltip=\"Show in editor\" onClick={() => anchor.scrollIntoView({ block: \"center\", behavior: window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches ? \"auto\" : \"smooth\" })}>\n <IconCrosshair stroke={1.5} />\n </IconButton>\n ) : null}\n <IconButton size=\"sm\" label=\"Close properties\" tooltip=\"Close\" onClick={close}>\n <IconX stroke={1.5} />\n </IconButton>\n </>\n );\n return (\n <FloatingPanel\n ref={panel}\n id=\"component-properties\"\n labelledBy={titleId}\n anchor={anchor}\n container={container}\n header={header}\n onClose={onClose}\n focusBack={focusBack}\n instant={open.refill}\n sheetFooter={\n <Button size=\"sm\" variant=\"primary\" onClick={close}>\n Done\n </Button>\n }\n >\n {ComponentSettings ? (\n <div data-component-settings=\"\" className=\"min-w-0 pb-3 pt-1\">\n <ComponentSettings {...settings} focusKey={open.focusKey} />\n </div>\n ) : (\n <div className=\"flex flex-col items-start gap-3 px-3 py-3 text-kit-sm text-kit-fg-2\">\n <p>This place's fields are edited in the block.</p>\n {editAll ? (\n <Button size=\"sm\" variant=\"secondary\" onClick={editAll.run}>\n <IconArrowUpRight stroke={1.5} className=\"size-4\" aria-hidden />\n {editAll.label}\n </Button>\n ) : null}\n </div>\n )}\n </FloatingPanel>\n );\n}\n"],"mappings":"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"}
|
|
@@ -16,6 +16,5 @@ type Opened = {
|
|
|
16
16
|
*/
|
|
17
17
|
export declare function openValue(codec: KitRichTextCodec, value: unknown, at: Parameters<KitRichTextCodec["read"]>[1]): Opened;
|
|
18
18
|
export declare function RichTextControl(props: ControlProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
-
|
|
20
|
-
export declare function RichTextExpandAction({ path, field }: ControlProps): import("react/jsx-runtime").JSX.Element | null;
|
|
19
|
+
export declare function RichTextExpandAction({ path, field, value }: ControlProps): import("react/jsx-runtime").JSX.Element | null;
|
|
21
20
|
export {};
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { cn } from "../../lib/cn.js";
|
|
2
|
-
import { pathKey } from "../../lib/path.js";
|
|
3
2
|
import { useForm, useKitEnv, useKitServices } from "../../context.js";
|
|
3
|
+
import { pathKey } from "../../lib/path.js";
|
|
4
4
|
import { Tooltip } from "../../ui/overlay.js";
|
|
5
|
+
import { Textarea } from "../../ui/input.js";
|
|
5
6
|
import { resolveFrames } from "../../lib/frames.js";
|
|
6
7
|
import { LegacyFallback } from "../../engine/kit-field.js";
|
|
8
|
+
import { TEXT_FOCUS } from "../text.js";
|
|
9
|
+
import { UnknownValueNote } from "../unknown-value.js";
|
|
7
10
|
import { editorRoundTrip } from "./dom.js";
|
|
8
11
|
import { RichTextEditor } from "./editor.js";
|
|
12
|
+
import { paragraphsHtml, plainParagraphs, usePlainRichText } from "./plain.js";
|
|
9
13
|
import * as React from "react";
|
|
10
|
-
import { IconArrowsMaximize } from "@tabler/icons-react";
|
|
11
14
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
-
|
|
15
|
+
import { IconArrowsMaximize } from "@tabler/icons-react";
|
|
16
|
+
//#region src/controls/rich-text/control.tsx
|
|
13
17
|
/**
|
|
14
18
|
* Rich text field (V2 HEAD controls/richtext.tsx, CPO D49).
|
|
15
19
|
* - The editor stays in place: the document variant is the full editor in the column, the panel variant (inspector)
|
|
@@ -74,7 +78,7 @@ function openValue(codec, value, at) {
|
|
|
74
78
|
reason: `the stored text could not be read (${err instanceof Error ? err.message : String(err)})`
|
|
75
79
|
};
|
|
76
80
|
}
|
|
77
|
-
if (holdsPullQuote(read.seed) && !/data-rt="pullquote"/.test(read.html)) return {
|
|
81
|
+
if (holdsPullQuote(read.seed) && (!/data-rt="pullquote"/.test(read.html) || !read.features.includes("pullquote"))) return {
|
|
78
82
|
ok: false,
|
|
79
83
|
reason: "it holds a pull quote, which the standard editor edits"
|
|
80
84
|
};
|
|
@@ -114,6 +118,7 @@ function CodecRichText({ codec, field, value, onChange, readOnly, path, id, inva
|
|
|
114
118
|
const docKey = `${env.docId}:${pathKey(path)}`;
|
|
115
119
|
const open = useFullEditorKey() === docKey;
|
|
116
120
|
const crumbs = useExpandCrumbs(field.title);
|
|
121
|
+
const plainScope = usePlainRichText();
|
|
117
122
|
const at = React.useMemo(() => ({
|
|
118
123
|
field,
|
|
119
124
|
path
|
|
@@ -187,51 +192,88 @@ function CodecRichText({ codec, field, value, onChange, readOnly, path, id, inva
|
|
|
187
192
|
};
|
|
188
193
|
onChange(res.value);
|
|
189
194
|
};
|
|
190
|
-
|
|
195
|
+
const plain = plainScope && !read.losses.length ? plainParagraphs(html) : null;
|
|
196
|
+
if (plain !== null) return /* @__PURE__ */ jsxs("div", {
|
|
191
197
|
className: "flex min-w-0 flex-col gap-1.5",
|
|
192
|
-
children: [
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
placeholder: field.placeholder,
|
|
207
|
-
docKey,
|
|
208
|
-
id,
|
|
209
|
-
invalid: invalid || !!refusal,
|
|
210
|
-
features: read.features,
|
|
211
|
-
single: read.single,
|
|
212
|
-
allowNewTab: read.newTab,
|
|
213
|
-
components: insertable && !read.single && !readOnly ? insertable : void 0,
|
|
214
|
-
variant: env.variant === "document" ? "document" : "panel",
|
|
215
|
-
maxHeight: env.variant === "document" ? void 0 : 320,
|
|
216
|
-
expandCrumbs: crumbs,
|
|
217
|
-
expandedOpen: open,
|
|
218
|
-
onExpandedOpenChange: (o) => setFullEditor(o ? docKey : null),
|
|
219
|
-
onComment: env.onComment ? () => env.onComment(path, field) : void 0
|
|
220
|
-
}),
|
|
221
|
-
refusal ? /* @__PURE__ */ jsx("p", {
|
|
222
|
-
role: "alert",
|
|
223
|
-
className: "text-kit-xs text-kit-danger-fg",
|
|
224
|
-
children: refusal
|
|
225
|
-
}) : null
|
|
226
|
-
]
|
|
198
|
+
children: [/* @__PURE__ */ jsx(Textarea, {
|
|
199
|
+
id,
|
|
200
|
+
rows: 3,
|
|
201
|
+
value: plain,
|
|
202
|
+
readOnly,
|
|
203
|
+
"aria-invalid": invalid || !!refusal,
|
|
204
|
+
placeholder: field.placeholder,
|
|
205
|
+
onChange: (e) => write(paragraphsHtml(e.target.value)),
|
|
206
|
+
className: cn(TEXT_FOCUS, "leading-5")
|
|
207
|
+
}), refusal ? /* @__PURE__ */ jsx("p", {
|
|
208
|
+
role: "alert",
|
|
209
|
+
className: "text-kit-xs text-kit-danger-fg",
|
|
210
|
+
children: refusal
|
|
211
|
+
}) : null]
|
|
227
212
|
});
|
|
213
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
214
|
+
read.losses.length ? /* @__PURE__ */ jsxs("p", {
|
|
215
|
+
role: "status",
|
|
216
|
+
className: "mb-1.5 rounded-kit-md bg-kit-warning-soft px-2.5 py-1.5 text-kit-xs text-kit-warning-fg",
|
|
217
|
+
children: [
|
|
218
|
+
"Saved by an earlier editor. Editing here would drop ",
|
|
219
|
+
read.losses.join(", "),
|
|
220
|
+
". Nothing changes until you edit."
|
|
221
|
+
]
|
|
222
|
+
}) : null,
|
|
223
|
+
read.undeclared?.length && codec.remap ? /* @__PURE__ */ jsx("div", {
|
|
224
|
+
className: "mb-1.5",
|
|
225
|
+
children: /* @__PURE__ */ jsx(UnknownValueNote, {
|
|
226
|
+
items: read.undeclared,
|
|
227
|
+
onRemap: (key, to) => onChange(codec.remap(value, at, key, to)),
|
|
228
|
+
onRemove: (key) => onChange(codec.remap(value, at, key, null)),
|
|
229
|
+
readOnly
|
|
230
|
+
})
|
|
231
|
+
}) : null,
|
|
232
|
+
/* @__PURE__ */ jsx(RichTextEditor, {
|
|
233
|
+
value: html,
|
|
234
|
+
onChange: write,
|
|
235
|
+
readOnly,
|
|
236
|
+
placeholder: field.placeholder,
|
|
237
|
+
docKey,
|
|
238
|
+
id,
|
|
239
|
+
invalid: invalid || !!refusal,
|
|
240
|
+
features: read.features,
|
|
241
|
+
single: read.single,
|
|
242
|
+
allowNewTab: read.newTab,
|
|
243
|
+
components: insertable && !read.single && !readOnly ? insertable : void 0,
|
|
244
|
+
variant: env.variant === "document" ? "document" : "panel",
|
|
245
|
+
maxHeight: env.variant === "document" ? void 0 : 320,
|
|
246
|
+
expandCrumbs: crumbs,
|
|
247
|
+
expandedOpen: open,
|
|
248
|
+
onExpandedOpenChange: (o) => setFullEditor(o ? docKey : null),
|
|
249
|
+
onComment: env.onComment ? (quote) => env.onComment?.(path, field, quote) : void 0
|
|
250
|
+
}),
|
|
251
|
+
refusal ? /* @__PURE__ */ jsx("p", {
|
|
252
|
+
role: "alert",
|
|
253
|
+
className: "mt-1.5 text-kit-xs text-kit-danger-fg",
|
|
254
|
+
children: refusal
|
|
255
|
+
}) : null
|
|
256
|
+
] });
|
|
228
257
|
}
|
|
229
258
|
/** Label-row action (at rest): the field's toolbar holds the same button while it's open. */
|
|
230
|
-
function
|
|
259
|
+
function readsPlain(codec, value, field, path) {
|
|
260
|
+
try {
|
|
261
|
+
const read = codec.read(value, {
|
|
262
|
+
field,
|
|
263
|
+
path
|
|
264
|
+
});
|
|
265
|
+
return !read.losses.length && plainParagraphs(editorRoundTrip(read.html)) !== null;
|
|
266
|
+
} catch {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function RichTextExpandAction({ path, field, value }) {
|
|
231
271
|
const env = useKitEnv();
|
|
232
272
|
const { richText } = useKitServices();
|
|
233
273
|
const handed = useHandedOff(`${env.docId}:${pathKey(path)}`);
|
|
274
|
+
const plainScope = usePlainRichText();
|
|
234
275
|
if (env.variant === "document" || !richText || handed) return null;
|
|
276
|
+
if (plainScope && readsPlain(richText, value, field, path)) return null;
|
|
235
277
|
return /* @__PURE__ */ jsx(Tooltip, {
|
|
236
278
|
content: "Expand editor",
|
|
237
279
|
shortcut: "⌘↵",
|
|
@@ -249,6 +291,6 @@ function RichTextExpandAction({ path, field }) {
|
|
|
249
291
|
});
|
|
250
292
|
}
|
|
251
293
|
//#endregion
|
|
252
|
-
export { RichTextControl, RichTextExpandAction };
|
|
294
|
+
export { RichTextControl, RichTextExpandAction, openValue, setFullEditor };
|
|
253
295
|
|
|
254
296
|
//# sourceMappingURL=control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.js","names":[],"sources":["../../../src/controls/rich-text/control.tsx"],"sourcesContent":["/**\n * Rich text field (V2 HEAD controls/richtext.tsx, CPO D49).\n * - The editor stays in place: the document variant is the full editor in the column, the panel variant (inspector)\n * the same editor height-capped.\n * - Expanding (the toolbar's expand button, ⌘↵, or the expand icon in the field's label row at rest) opens the shared\n * ExpandedEditorModal: breadcrumb \"Section › Item › Field\", word count, Done. Esc closes and focus returns.\n *\n * STORAGE. The editor edits HTML; the stored value stays what production stores for the field, through the host's\n * codec (KitServices.richText, see ./codec.ts):\n * - read: stored value → the HTML the editor opens on (+ what the field accepts)\n * - write: edited HTML → the stored value, in the surface's own shape; a write that would drop something is refused,\n * named, and nothing is stored\n * - probe: a value the editor cannot carry unchanged (open → no edit → write ≠ stored) is not opened here at all: the\n * host's own control edits it (LegacyFallback), with the reason above it. Opening never writes.\n */\nimport * as React from \"react\";\nimport { IconArrowsMaximize } from \"@tabler/icons-react\";\nimport { cn } from \"../../lib/cn\";\nimport { useForm, useKitEnv, useKitServices } from \"../../context\";\nimport { resolveFrames } from \"../../lib/frames\";\nimport { pathKey } from \"../../lib/path\";\nimport type { ControlProps } from \"../../types\";\nimport { Tooltip } from \"../../ui/overlay\";\nimport { LegacyFallback } from \"../../engine/kit-field\";\nimport type { KitRichTextCodec, RichTextRead } from \"./codec\";\nimport { editorRoundTrip } from \"./dom\";\nimport { RichTextEditor } from \"./editor\";\nimport { paragraphsHtml, plainParagraphs, usePlainRichText } from \"./plain\";\nimport { Textarea } from \"../../ui/input\";\nimport { TEXT_FOCUS } from \"../text\";\nimport { UnknownValueNote } from \"../unknown-value\";\n\n/* ── which rich-text field (docKey) has its full editor open — shared with the label-row action ── */\nlet openKey: string | null = null;\nconst subs = new Set<() => void>();\nexport function setFullEditor(key: string | null) {\n openKey = key;\n subs.forEach((s) => s());\n}\nfunction useFullEditorKey() {\n return React.useSyncExternalStore(\n (cb) => {\n subs.add(cb);\n return () => subs.delete(cb);\n },\n () => openKey,\n () => openKey,\n );\n}\n\n/* ── fields whose value went to the host's own control: the label-row expand button is not theirs to draw ── */\nconst handedOff = new Set<string>();\nfunction setHandedOff(key: string, on: boolean) {\n if (handedOff.has(key) === on) return;\n if (on) handedOff.add(key);\n else handedOff.delete(key);\n subs.forEach((s) => s());\n}\nfunction useHandedOff(key: string) {\n return React.useSyncExternalStore(\n (cb) => {\n subs.add(cb);\n return () => subs.delete(cb);\n },\n () => handedOff.has(key),\n () => handedOff.has(key),\n );\n}\n\n/** The expanded editor's breadcrumb: the form's frames (root › drilled items) and this field. */\nfunction useExpandCrumbs(fieldTitle: string): string[] {\n const form = useForm();\n const env = useKitEnv();\n if (!form) return [env.docTitle, fieldTitle].filter(Boolean) as string[];\n const { frames } = resolveFrames(form.schema, form.value, form.path, form.resolveSchema);\n const titles = frames.filter((f) => f.kind !== \"history\").map((f, i) => (i === 0 ? env.docTitle || f.title : f.title));\n return [...titles, fieldTitle];\n}\n\n/** A stored block array, or the `{ content }` / `{ format, value }` envelope around one, holding a pull quote block. */\nconst holdsPullQuote = (seed: unknown): boolean =>\n Array.isArray(seed)\n ? seed.some((b) => !!b && typeof b === \"object\" && (b as { _type?: unknown })._type === \"pullQuote\")\n : !!seed && typeof seed === \"object\" && holdsPullQuote((seed as { content?: unknown; value?: unknown }).content ?? (seed as { value?: unknown }).value);\n\n/** What the control decided for one stored value. */\ntype Opened =\n | { ok: true; read: RichTextRead; html: string }\n | { ok: false; reason: string };\n\n/**\n * Open a stored value: read it, then prove the editor carries it unchanged (load → serialize → write === stored).\n * A codec that throws, or a value that does not survive, is handed to the host's own control with the reason.\n */\nexport function openValue(codec: KitRichTextCodec, value: unknown, at: Parameters<KitRichTextCodec[\"read\"]>[1]): Opened {\n let read: RichTextRead;\n try {\n read = codec.read(value, at);\n } catch (err) {\n return { ok: false, reason: `the stored text could not be read (${err instanceof Error ? err.message : String(err)})` };\n }\n // a pull quote (V2 D55 article block) opens as the editor's pull-quote island, but only when the codec renders the\n // stored block as its markup in a field that offers it: a codec that renders nothing for it, or a field with no place\n // for one (a single paragraph), would lose it, so the standard editor edits it\n if (holdsPullQuote(read.seed) && (!/data-rt=\"pullquote\"/.test(read.html) || !read.features.includes(\"pullquote\")))\n return { ok: false, reason: \"it holds a pull quote, which the standard editor edits\" };\n // tables and pull quotes are islands (V2 TableBlock, PullQuote); the probe below proves they survive unchanged\n const html = editorRoundTrip(read.html);\n try {\n const back = codec.write(html, at, value);\n if (back.losses.length) return { ok: false, reason: `this editor would drop ${back.losses.join(\", \")}` };\n if (!codec.same(back.value, read.seed)) return { ok: false, reason: \"it holds formatting this editor cannot keep\" };\n } catch (err) {\n return { ok: false, reason: `the text could not be checked (${err instanceof Error ? err.message : String(err)})` };\n }\n return { ok: true, read, html };\n}\n\nexport function RichTextControl(props: ControlProps) {\n const { richText } = useKitServices();\n if (!richText) return <LegacyFallback {...props} />;\n return <CodecRichText codec={richText} {...props} />;\n}\n\nfunction CodecRichText({ codec, field, value, onChange, readOnly, path, id, invalid }: ControlProps & { codec: KitRichTextCodec }) {\n const env = useKitEnv();\n const docKey = `${env.docId}:${pathKey(path)}`;\n const open = useFullEditorKey() === docKey;\n const crumbs = useExpandCrumbs(field.title);\n const plainScope = usePlainRichText();\n const at = React.useMemo(() => ({ field, path }), [field, path]);\n // the components this field may embed (More components): a hook with one identity for the form's life, so calling it\n // only when the host provides it keeps the hook order fixed\n const { useInsertableComponents } = useKitServices();\n const insertable = useInsertableComponents?.(at);\n /* our own last write: its value comes back as `value`, and the editor keeps the HTML it emitted (no reload, no probe) */\n const mine = React.useRef<{ value: unknown; html: string } | null>(null);\n const [refusal, setRefusal] = React.useState<string | null>(null);\n const opened = React.useMemo<Opened>(() => {\n if (mine.current && mine.current.value === value) {\n try {\n return { ok: true, read: codec.read(value, at), html: mine.current.html };\n } catch {\n /* judged afresh below, which names the failure */\n }\n }\n return openValue(codec, value, at);\n // `at` changes identity with the field object; the field's content is what matters\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [codec, value, JSON.stringify(field), pathKey(path)]);\n\n // close when this field goes away (block deselected, drilled elsewhere)\n React.useEffect(\n () => () => {\n if (openKey === docKey) setFullEditor(null);\n setHandedOff(docKey, false);\n },\n [docKey],\n );\n React.useLayoutEffect(() => {\n setHandedOff(docKey, !opened.ok);\n if (!opened.ok && openKey === docKey) setFullEditor(null);\n }, [docKey, opened.ok]);\n\n if (!opened.ok)\n return (\n <div className=\"flex min-w-0 flex-col gap-1.5\">\n <p role=\"note\" data-slot=\"kit-richtext-handoff\" className=\"rounded-kit-md bg-kit-subtle px-2.5 py-1.5 text-kit-xs text-kit-fg-2\">\n Edited with the standard editor: {opened.reason}.\n </p>\n <LegacyFallback field={field} value={value} onChange={onChange} readOnly={readOnly} path={path} id={id} invalid={invalid} />\n </div>\n );\n\n const { read, html } = opened;\n const write = (next: string) => {\n let res;\n try {\n res = codec.write(next, at, value);\n } catch (err) {\n setRefusal(`Not saved: the text could not be stored (${err instanceof Error ? err.message : String(err)}). Undo the last change with ⌘Z; leaving the field puts back the saved text.`);\n return;\n }\n if (res.losses.length) {\n setRefusal(`Not saved: this field cannot keep ${res.losses.join(\", \")}. Undo the last change with ⌘Z; leaving the field puts back the saved text.`);\n return;\n }\n setRefusal(null);\n if (codec.same(res.value, value)) return;\n mine.current = { value: res.value, html: next };\n onChange(res.value);\n };\n\n // The Values popover (PlainRichTextScope): plain paragraphs are V2's growing textarea (its `text` control), written\n // back through the same codec, one `<p>` per line. Anything richer keeps the editor below.\n const plain = plainScope && !read.losses.length ? plainParagraphs(html) : null;\n if (plain !== null)\n return (\n <div className=\"flex min-w-0 flex-col gap-1.5\">\n <Textarea\n id={id}\n rows={3}\n value={plain}\n readOnly={readOnly}\n aria-invalid={invalid || !!refusal}\n placeholder={field.placeholder}\n onChange={(e) => write(paragraphsHtml(e.target.value))}\n className={cn(TEXT_FOCUS, \"leading-5\")}\n />\n {refusal ? (\n <p role=\"alert\" className=\"text-kit-xs text-kit-danger-fg\">\n {refusal}\n </p>\n ) : null}\n </div>\n );\n\n /* V2 richtext.tsx:57: the editor sits in a plain <div>; the dash-only notes keep the 6px gap as their own margin */\n return (\n <div>\n {read.losses.length ? (\n <p role=\"status\" className=\"mb-1.5 rounded-kit-md bg-kit-warning-soft px-2.5 py-1.5 text-kit-xs text-kit-warning-fg\">\n Saved by an earlier editor. Editing here would drop {read.losses.join(\", \")}. Nothing changes until you edit.\n </p>\n ) : null}\n {read.undeclared?.length && codec.remap ? (\n <div className=\"mb-1.5\">\n <UnknownValueNote\n items={read.undeclared}\n onRemap={(key, to) => onChange(codec.remap!(value, at, key, to))}\n onRemove={(key) => onChange(codec.remap!(value, at, key, null))}\n readOnly={readOnly}\n />\n </div>\n ) : null}\n <RichTextEditor\n value={html}\n onChange={write}\n readOnly={readOnly}\n placeholder={field.placeholder}\n docKey={docKey}\n id={id}\n invalid={invalid || !!refusal}\n features={read.features}\n single={read.single}\n allowNewTab={read.newTab}\n components={insertable && !read.single && !readOnly ? insertable : undefined}\n variant={env.variant === \"document\" ? \"document\" : \"panel\"}\n maxHeight={env.variant === \"document\" ? undefined : 320}\n expandCrumbs={crumbs}\n expandedOpen={open}\n onExpandedOpenChange={(o) => setFullEditor(o ? docKey : null)}\n // select words → Comment in the toolbar: the host's comment popover opens on this field, quoting them\n onComment={env.onComment ? (quote) => env.onComment?.(path, field, quote) : undefined}\n />\n {refusal ? (\n <p role=\"alert\" className=\"mt-1.5 text-kit-xs text-kit-danger-fg\">\n {refusal}\n </p>\n ) : null}\n </div>\n );\n}\n\n/** Label-row action (at rest): the field's toolbar holds the same button while it's open. */\nfunction readsPlain(codec: KitRichTextCodec, value: unknown, field: ControlProps[\"field\"], path: ControlProps[\"path\"]) {\n try {\n const read = codec.read(value, { field, path });\n return !read.losses.length && plainParagraphs(editorRoundTrip(read.html)) !== null;\n } catch {\n return false; // the control names the failure itself\n }\n}\n\nexport function RichTextExpandAction({ path, field, value }: ControlProps) {\n const env = useKitEnv();\n const { richText } = useKitServices();\n const handed = useHandedOff(`${env.docId}:${pathKey(path)}`);\n const plainScope = usePlainRichText();\n // the host's own control (no codec, or a value handed to it) has its own full-screen button\n if (env.variant === \"document\" || !richText || handed) return null;\n // drawn as a plain textarea (V2's `text` control has no ⤢)\n if (plainScope && readsPlain(richText, value, field, path)) return null;\n return (\n <Tooltip content=\"Expand editor\" shortcut=\"⌘↵\">\n <button\n type=\"button\"\n aria-label={`Expand ${field.title}`}\n onClick={() => setFullEditor(`${env.docId}:${pathKey(path)}`)}\n className={cn(\n \"-my-0.5 hidden size-6 items-center justify-center rounded-kit-md text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\",\n \"group-hover/field:inline-flex group-focus-within/field:!hidden [@media(pointer:coarse)]:inline-flex\",\n )}\n >\n <IconArrowsMaximize className=\"size-3.5\" stroke={1.5} aria-hidden />\n </button>\n </Tooltip>\n );\n}\n"],"mappings":"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"}
|