@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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.js","names":[],"sources":["../../../src/kit/controls/rich-text/markdown.ts"],"sourcesContent":["/**\n * RICH TEXT · a small HTML ⇄ Markdown converter for the field's Markdown mode and for pasting (V2 HEAD\n * controls/rich-text/markdown.ts). Covers headings, bold/italic/strike/underline, inline code, links, images, lists,\n * quotes, code blocks, rules and paragraphs. Anything else is kept as one line of raw HTML, which the reverse direction\n * passes through untouched (and the field's own rules then decide whether it may stay).\n */\nimport { esc, escAttr, sanitize } from \"./dom\";\n\n/* ── HTML → Markdown ───────────────────────────────────────────────── */\nconst escText = (s: string) => s.replace(/([\\\\`*[\\]~])/g, \"\\\\$1\");\n\nfunction inline(node: Node, inCode = false): string {\n if (node.nodeType === 3) {\n const t = (node.textContent ?? \"\").replace(/ /g, \" \");\n return inCode ? t : escText(t.replace(/\\s+/g, \" \"));\n }\n if (node.nodeType !== 1) return \"\";\n const el = node as HTMLElement;\n const kids = () => Array.from(el.childNodes).map((c) => inline(c, inCode)).join(\"\");\n const wrap = (mark: string) => {\n const inner = kids();\n if (!inner.trim()) return inner;\n const lead = inner.match(/^\\s*/)![0];\n const trail = inner.match(/\\s*$/)![0];\n return `${lead}${mark}${inner.trim()}${mark}${trail}`;\n };\n switch (el.tagName) {\n case \"STRONG\":\n case \"B\":\n return wrap(\"**\");\n case \"EM\":\n case \"I\":\n return wrap(\"_\");\n case \"S\":\n case \"STRIKE\":\n case \"DEL\":\n return wrap(\"~~\");\n case \"U\":\n return `<u>${kids()}</u>`;\n case \"CODE\":\n return \"`\" + (el.textContent ?? \"\").replace(/`/g, \"\") + \"`\";\n case \"BR\":\n return \" \\n\";\n case \"IMG\":\n return ` ?? \"\"})`;\n case \"A\":\n // a link that carries more than its address (opens in a new tab) keeps its markup, so Markdown mode drops nothing\n if (el.hasAttribute(\"target\")) return el.outerHTML;\n return `[${kids()}](${el.getAttribute(\"href\") ?? \"\"})`;\n default:\n return kids();\n }\n}\n\nfunction list(el: HTMLElement): string | null {\n if (el.querySelector(\"ul ul, ul ol, ol ol, ol ul, li > p + p\")) return null;\n return Array.from(el.children)\n .filter((li) => li.tagName === \"LI\")\n .map((li, i) => (el.tagName === \"OL\" ? `${i + 1}. ` : \"- \") + inline(li).trim().replace(/ {2}\\n/g, \" \"))\n .join(\"\\n\");\n}\n\nexport function htmlToMarkdown(html: string): string {\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, \"text/html\");\n const out: string[] = [];\n for (const node of Array.from(doc.body.childNodes)) {\n if (node.nodeType === 3) {\n const t = inline(node).trim();\n if (t) out.push(t);\n continue;\n }\n if (node.nodeType !== 1) continue;\n const el = node as HTMLElement;\n const tag = el.tagName;\n const raw = () => out.push(el.outerHTML.replace(/\\n+/g, \" \"));\n if (/^H[1-6]$/.test(tag)) out.push(`${\"#\".repeat(Number(tag[1]))} ${inline(el).trim()}`);\n else if (tag === \"P\") {\n const s = inline(el).trim().replace(/^([#>]|\\d+\\.|[-+] |-{3})/, \"\\\\$1\");\n if (s) out.push(s);\n } else if (tag === \"UL\" || tag === \"OL\") {\n const l = list(el);\n if (l === null) raw();\n else out.push(l);\n } else if (tag === \"BLOCKQUOTE\") {\n const paras = el.querySelector(\"p,div\") ? Array.from(el.children).map((c) => inline(c).trim()) : [inline(el).trim()];\n out.push(paras.filter(Boolean).map((p) => p.split(\"\\n\").map((l) => `> ${l}`).join(\"\\n\")).join(\"\\n>\\n\"));\n } else if (tag === \"PRE\") out.push(\"```\\n\" + (el.textContent ?? \"\").replace(/\\n$/, \"\") + \"\\n```\");\n else if (tag === \"HR\") out.push(\"---\");\n else if (tag === \"FIGURE\" && el.querySelector(\":scope > img\")) {\n const img = el.querySelector(\"img\")!;\n const cap = el.querySelector(\"figcaption\")?.textContent?.trim();\n out.push(` ?? \"\"}${cap ? ` \"${cap.replace(/\"/g, \"'\")}\"` : \"\"})`);\n } else raw();\n }\n return out.join(\"\\n\\n\") + (out.length ? \"\\n\" : \"\");\n}\n\n/* ── Markdown → HTML ───────────────────────────────────────────────── */\nconst safeHref = (h: string) => (/^\\s*(javascript|vbscript|data:text)/i.test(h) ? \"#\" : h);\n\nexport function inlineMd(src: string): string {\n const slots: string[] = [];\n const hold = (html: string) => `\\u0000${slots.push(html) - 1}\\u0000`;\n let s = src.replace(/\\\\([\\\\`*_[\\]~#>+\\-.!])/g, (_, c: string) => hold(esc(c)));\n s = s.replace(/`([^`]+)`/g, (_, c: string) => hold(`<code>${esc(c)}</code>`));\n s = s.replace(/<a [^>]*>.*?<\\/a>/g, (m) => hold(m));\n s = esc(s);\n s = s.replace(/<(\\/?)u>/g, \"<$1u>\");\n s = s.replace(/!\\[([^\\]]*)\\]\\(([^)\\s]+)\\)/g, (_, a: string, u: string) => hold(`<img src=\"${escAttr(safeHref(u))}\" alt=\"${escAttr(a)}\">`));\n s = s.replace(/\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/g, (_, t: string, u: string) => `<a href=\"${escAttr(safeHref(u))}\">${t}</a>`);\n s = s.replace(/\\*\\*([^*]+?)\\*\\*/g, \"<strong>$1</strong>\");\n s = s.replace(/__([^_]+?)__/g, \"<strong>$1</strong>\");\n s = s.replace(/(^|[^\\w*])\\*([^*\\s][^*]*?)\\*(?!\\*)/g, \"$1<em>$2</em>\");\n s = s.replace(/(^|[^\\w])_([^_\\s][^_]*?)_(?!\\w)/g, \"$1<em>$2</em>\");\n s = s.replace(/~~([^~]+?)~~/g, \"<s>$1</s>\");\n s = s.replace(/ {2,}\\n/g, \"<br>\").replace(/\\n/g, \" \");\n return s.replace(/\\u0000(\\d+)\\u0000/g, (_, i: string) => slots[Number(i)]);\n}\n\nconst RAW_BLOCK = /^<\\/?(div|table|figure|details|ul|ol|p|h[1-6]|blockquote|pre|hr|section|aside)\\b/i;\nconst RE = {\n fence: /^\\s*```/,\n heading: /^(#{1,6})\\s+(.*?)\\s*#*\\s*$/,\n hr: /^\\s*(-{3,}|\\*{3,}|_{3,})\\s*$/,\n image: /^!\\[([^\\]]*)\\]\\(([^)\\s]+)(?:\\s+\"([^\"]*)\")?\\)\\s*$/,\n quote: /^\\s*>/,\n ul: /^\\s*[-*+]\\s+(.*)$/,\n ol: /^\\s*\\d+[.)]\\s+(.*)$/,\n};\nconst startsBlock = (l: string) => RE.fence.test(l) || RE.heading.test(l) || RE.hr.test(l) || RE.quote.test(l) || RE.ul.test(l) || RE.ol.test(l) || RAW_BLOCK.test(l.trim());\n\n/** Throws on Markdown it cannot read (e.g. an unclosed code fence). */\nexport function markdownToHtml(md: string): string {\n const lines = md.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\");\n const out: string[] = [];\n let i = 0;\n while (i < lines.length) {\n const line = lines[i];\n if (!line.trim()) {\n i++;\n continue;\n }\n if (RE.fence.test(line)) {\n const code: string[] = [];\n i++;\n while (i < lines.length && !RE.fence.test(lines[i])) code.push(lines[i++]);\n if (i >= lines.length) throw new Error(\"Unclosed code block\");\n i++;\n out.push(`<pre>${esc(code.join(\"\\n\"))}</pre>`);\n continue;\n }\n if (RAW_BLOCK.test(line.trim())) {\n const raw: string[] = [];\n while (i < lines.length && lines[i].trim()) raw.push(lines[i++]);\n out.push(raw.join(\" \"));\n continue;\n }\n let m = line.match(RE.heading);\n if (m) {\n out.push(`<h${m[1].length}>${inlineMd(m[2])}</h${m[1].length}>`);\n i++;\n continue;\n }\n if (RE.hr.test(line)) {\n out.push(\"<hr>\");\n i++;\n continue;\n }\n m = line.match(RE.image);\n if (m) {\n // an image keeps no caption in production rich text: a title becomes the line under it, never dropped\n out.push(`<figure><img src=\"${escAttr(safeHref(m[2]))}\" alt=\"${escAttr(m[1])}\"></figure>${m[3] ? `<p>${esc(m[3])}</p>` : \"\"}`);\n i++;\n continue;\n }\n if (RE.quote.test(line)) {\n const q: string[] = [];\n while (i < lines.length && RE.quote.test(lines[i])) q.push(lines[i++].replace(/^\\s*> ?/, \"\"));\n out.push(`<blockquote>${q.join(\"\\n\").split(/\\n\\s*\\n/).map(inlineMd).join(\"<br><br>\")}</blockquote>`);\n continue;\n }\n if (RE.ul.test(line) || RE.ol.test(line)) {\n const ordered = !RE.ul.test(line);\n const re = ordered ? RE.ol : RE.ul;\n const items: string[] = [];\n while (i < lines.length && re.test(lines[i])) items.push(`<li>${inlineMd(lines[i++].match(re)![1])}</li>`);\n out.push(ordered ? `<ol>${items.join(\"\")}</ol>` : `<ul>${items.join(\"\")}</ul>`);\n continue;\n }\n const para: string[] = [];\n while (i < lines.length && lines[i].trim() && (para.length === 0 || !startsBlock(lines[i]))) para.push(lines[i++]);\n out.push(`<p>${inlineMd(para.join(\"\\n\"))}</p>`);\n }\n return sanitize(out.join(\"\"));\n}\n\n/** Does pasted plain text look like Markdown worth converting into blocks? */\nexport const looksLikeMarkdown = (t: string) => /\\n\\s*\\n/.test(t) || /^(#{1,6}\\s|[-*+]\\s|\\d+[.)]\\s|>\\s|```|---)/m.test(t) || /\\*\\*[^*]+\\*\\*|\\[[^\\]]+\\]\\([^)]+\\)/.test(t);\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ops.js","names":[],"sources":["../../../src/kit/controls/rich-text/ops.ts"],"sourcesContent":["/**\n * RICH TEXT · pure DOM block operations on the editor surface (V2 HEAD controls/rich-text/ops.ts; no React, no\n * emitting). The editor wraps each one, then serializes and emits the new value.\n */\nimport { closestBlock, cloneModel, createIsland, defaultModel, esc, placeCaret, textBeforeCaret, topBlock, type IslandEl, type IslandKind, type IslandModels } from \"./dom\";\nimport type { RichTextFeature } from \"./codec\";\nimport type { BasicId } from \"./catalog\";\n\nconst emptyP = () => {\n const p = document.createElement(\"p\");\n p.innerHTML = \"<br>\";\n return p;\n};\nconst isWritable = (el: Element | null): el is HTMLElement => !!el && !el.hasAttribute(\"data-rt-island\") && el.tagName !== \"HR\";\n\n/** The writable line after a block, created when the block is last or followed by another rich block. */\nexport function ensureLineAfter(b: Element): HTMLElement {\n const next = b.nextElementSibling;\n if (isWritable(next)) return next;\n const p = emptyP();\n b.after(p);\n return p;\n}\n\nexport function duplicateBlock(b: HTMLElement): HTMLElement {\n let c: HTMLElement;\n if (b.hasAttribute(\"data-rt-island\")) {\n const k = b.getAttribute(\"data-rt-island\") as IslandKind;\n c = createIsland(k, cloneModel(k, (b as IslandEl).__rt as never));\n } else {\n c = b.cloneNode(true) as HTMLElement;\n c.removeAttribute(\"data-hint\");\n }\n b.after(c);\n return c;\n}\n\n/** Moves a block one step, keeping the caret where it was. Returns false at the edge. */\nexport function moveBlock(b: HTMLElement, dir: -1 | 1): boolean {\n const sib = dir < 0 ? b.previousElementSibling : b.nextElementSibling;\n if (!sib) return false;\n const s = window.getSelection();\n // ranges are live (a move collapses them), so keep the raw caret position\n const at = s && s.rangeCount ? { n: s.getRangeAt(0).startContainer, o: s.getRangeAt(0).startOffset } : null;\n const host = document.activeElement as HTMLElement | null;\n if (dir < 0) sib.before(b);\n else sib.after(b);\n if (at && s && b.contains(at.n)) {\n host?.focus({ preventScroll: true });\n const r = document.createRange();\n r.setStart(at.n, Math.min(at.o, at.n.nodeType === 3 ? (at.n as Text).length : at.n.childNodes.length));\n r.collapse(true);\n s.removeAllRanges();\n s.addRange(r);\n }\n return true;\n}\n\n/** Text / Heading / Quote / Code. Returns the new element, or null when nothing changed. */\nexport function turnInto(root: HTMLElement, b: HTMLElement | null, tag: string): HTMLElement | null {\n if (!b || b.parentNode !== root || b.hasAttribute(\"data-rt-island\") || b.tagName === \"HR\") return null;\n if (b.tagName.toLowerCase() === tag) return null;\n const inner =\n b.tagName === \"UL\" || b.tagName === \"OL\"\n ? Array.from(b.children).map((c) => c.innerHTML).join(\"<br>\")\n : b.tagName === \"PRE\"\n ? esc(b.textContent ?? \"\").replace(/\\n/g, \"<br>\")\n : b.innerHTML;\n const n = document.createElement(tag);\n n.innerHTML = tag === \"pre\" ? esc((b.textContent ?? \"\").replace(//g, \"\")) || \"<br>\" : inner || \"<br>\";\n b.replaceWith(n);\n root.focus({ preventScroll: true });\n placeCaret(n);\n return n;\n}\n\n/** An empty paragraph at the caret to build a block from (reuses the current one when it is empty). */\nexport function takeEmptyBlock(root: HTMLElement): HTMLElement {\n const s = window.getSelection();\n const anchor = s && s.rangeCount && root.contains(s.anchorNode) ? s.anchorNode : null;\n const li = anchor ? closestBlock(root, anchor) : null;\n let b = topBlock(root, anchor);\n if (li && li.tagName === \"LI\" && !li.textContent?.trim()) {\n const list = li.parentElement!;\n li.remove();\n if (!list.children.length) {\n const p = emptyP();\n list.replaceWith(p);\n b = p;\n } else b = list;\n }\n root.focus({ preventScroll: true });\n if (b && b.tagName === \"P\" && !b.textContent?.replace(//g, \"\").trim() && !b.querySelector(\"img\")) {\n b.innerHTML = \"<br>\";\n placeCaret(b);\n return b;\n }\n // an empty heading, quote or code line (e.g. \"/\" typed on one) is reused too, so no empty block is left behind\n if (b && /^(H[1-6]|BLOCKQUOTE|PRE)$/.test(b.tagName) && !b.textContent?.replace(//g, \"\").trim()) {\n const p = emptyP();\n b.replaceWith(p);\n placeCaret(p);\n return p;\n }\n const p = emptyP();\n if (b) b.after(p);\n else root.append(p);\n placeCaret(p);\n return p;\n}\n\nexport function insertIsland<K extends IslandKind>(root: HTMLElement, kind: K, model: IslandModels[K] = defaultModel(kind)): IslandEl {\n const target = takeEmptyBlock(root);\n const isl = createIsland(kind, model);\n isl.__rtFocus = true;\n target.before(isl);\n // keep the document tidy: reuse the line that already follows instead of leaving an empty one\n const next = target.nextElementSibling;\n if (isWritable(next)) {\n target.remove();\n placeCaret(next, false);\n } else placeCaret(target);\n return isl;\n}\n\n/** Inserts a basic block at the caret. */\nexport function insertBasic(root: HTMLElement, id: BasicId) {\n switch (id) {\n case \"p\":\n takeEmptyBlock(root);\n return;\n case \"h1\": case \"h2\": case \"h3\": case \"h4\": case \"h5\": case \"h6\":\n turnInto(root, takeEmptyBlock(root), id);\n return;\n case \"quote\":\n turnInto(root, takeEmptyBlock(root), \"blockquote\");\n return;\n case \"code\":\n turnInto(root, takeEmptyBlock(root), \"pre\");\n return;\n case \"ul\": case \"ol\": {\n const t = takeEmptyBlock(root);\n const l = document.createElement(id);\n l.innerHTML = \"<li><br></li>\";\n t.replaceWith(l);\n placeCaret(l.firstElementChild!);\n return;\n }\n case \"hr\": {\n const t = takeEmptyBlock(root);\n t.before(document.createElement(\"hr\"));\n placeCaret(t);\n return;\n }\n case \"image\": case \"table\": case \"pullquote\": case \"takeaways\": case \"callout\": case \"toggle\": case \"video\": case \"file\":\n insertIsland(root, id);\n return;\n }\n}\n\n/**\n * \"# \", \"> \", \"- \", \"1. \" and \"---\" at the start of a paragraph, each only when the field accepts what it makes.\n * Returns true when it converted.\n */\nexport function liveMarkdown(root: HTMLElement, data: string | null, allows: (f: RichTextFeature) => boolean = () => true): boolean {\n const s = window.getSelection();\n if (!s || !s.rangeCount || !s.isCollapsed) return false;\n const blk = topBlock(root, s.anchorNode);\n if (!blk || blk.tagName !== \"P\") return false;\n const before = textBeforeCaret(blk)?.replace(/ /g, \" \");\n if (before == null) return false;\n if (data === \"-\" && before === \"---\" && (blk.textContent ?? \"\").replace(/ /g, \" \") === \"---\") {\n if (!allows(\"hr\")) return false;\n const p = emptyP();\n blk.replaceWith(document.createElement(\"hr\"), p);\n placeCaret(p);\n return true;\n }\n if (data !== \" \") return false;\n const h = before.match(/^(#{1,6}) $/);\n let tag = h ? `h${h[1].length}` : before === \"> \" ? \"blockquote\" : null;\n let list = before === \"- \" || before === \"* \" ? \"ul\" : /^1[.)] $/.test(before) ? \"ol\" : null;\n if (tag && !allows(tag as RichTextFeature)) tag = null;\n if (list && !allows(list as RichTextFeature)) list = null;\n if (!tag && !list) return false;\n const r = document.createRange();\n r.selectNodeContents(blk);\n r.setEnd(s.anchorNode!, s.anchorOffset);\n r.deleteContents();\n const html = blk.textContent || blk.querySelector(\"img\") ? blk.innerHTML : \"<br>\";\n let target: HTMLElement;\n if (tag) {\n target = document.createElement(tag);\n target.innerHTML = html;\n blk.replaceWith(target);\n } else {\n const l = document.createElement(list!);\n target = document.createElement(\"li\");\n target.innerHTML = html;\n l.append(target);\n blk.replaceWith(l);\n }\n placeCaret(target, false);\n return true;\n}\n\n/** `text` typed between backticks becomes inline code. */\nexport function liveInlineCode(): boolean {\n const s = window.getSelection();\n if (!s || !s.rangeCount || !s.isCollapsed) return false;\n const r = s.getRangeAt(0);\n if (r.startContainer.nodeType !== 3 || r.startContainer.parentElement?.closest(\"code,pre\")) return false;\n const node = r.startContainer as Text;\n const m = node.data.slice(0, r.startOffset).match(/`([^`\\n]+)`$/);\n if (!m) return false;\n const del = document.createRange();\n del.setStart(node, r.startOffset - m[0].length);\n del.setEnd(node, r.startOffset);\n del.deleteContents();\n const code = document.createElement(\"code\");\n code.textContent = m[1];\n del.insertNode(code);\n const next = code.nextSibling;\n if (next && next.nodeType === 3 && next.textContent) {\n const c = document.createRange();\n c.setStart(next, 0);\n c.collapse(true);\n s.removeAllRanges();\n s.addRange(c);\n } else {\n const after = document.createTextNode(\"\");\n code.after(after);\n placeCaret(after);\n }\n return true;\n}\n\n/* ── What a field accepts, applied to HTML that arrives from outside (paste, Markdown) ── */\nconst MARK_FEATURE: Record<string, RichTextFeature> = {\n STRONG: \"bold\", B: \"bold\", EM: \"italic\", I: \"italic\", U: \"underline\", S: \"strike\", STRIKE: \"strike\", DEL: \"strike\", CODE: \"code\", A: \"link\",\n};\nconst BLOCK_FEATURE: Record<string, RichTextFeature> = {\n H1: \"h1\", H2: \"h2\", H3: \"h3\", H4: \"h4\", H5: \"h5\", H6: \"h6\", BLOCKQUOTE: \"blockquote\", UL: \"ul\", OL: \"ol\", PRE: \"pre\", HR: \"hr\", FIGURE: \"image\", IMG: \"image\",\n};\nconst FEATURE_WORD: Partial<Record<RichTextFeature, string>> = {\n image: \"images\", hr: \"dividers\", pre: \"code blocks\", ul: \"bulleted lists\", ol: \"numbered lists\", blockquote: \"quotes\", link: \"links\",\n};\n\n/**\n * HTML with every element the field does not accept turned into what it does: a heading / quote / code block becomes a\n * paragraph, a list becomes one paragraph per item, a mark or link is unwrapped to its text, a divider or image is\n * removed. `dropped` names what was taken out entirely (said to the author, never silent).\n */\nexport function restrictHtml(html: string, allows: (f: RichTextFeature) => boolean): { html: string; dropped: string[] } {\n if (!html) return { html, dropped: [] };\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, \"text/html\");\n const dropped = new Set<string>();\n const walk = (el: Element) => {\n for (const ch of Array.from(el.children)) {\n walk(ch);\n const mark = MARK_FEATURE[ch.tagName];\n const block = BLOCK_FEATURE[ch.tagName];\n if (mark && !allows(mark)) ch.replaceWith(...Array.from(ch.childNodes));\n else if (block && !allows(block)) {\n if (block === \"hr\" || block === \"image\") {\n dropped.add(FEATURE_WORD[block]!);\n ch.remove();\n } else if (block === \"ul\" || block === \"ol\") {\n const ps = Array.from(ch.children).map((li) => {\n const p = doc.createElement(\"p\");\n p.innerHTML = li.innerHTML;\n return p;\n });\n ch.replaceWith(...ps);\n } else {\n const p = doc.createElement(\"p\");\n p.innerHTML = block === \"pre\" ? esc(ch.textContent ?? \"\").replace(/\\n/g, \"<br>\") : ch.innerHTML;\n ch.replaceWith(p);\n }\n }\n }\n };\n walk(doc.body);\n return { html: doc.body.innerHTML, dropped: [...dropped] };\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"toolbar.js","names":[],"sources":["../../../src/kit/controls/rich-text/toolbar.tsx"],"sourcesContent":["/**\n * RICH TEXT · the field toolbar (V2 HEAD controls/rich-text/toolbar.tsx, production order):\n * Style ▾ | B I U S | • 1. | Link, Clear formatting, Comment | ▾ more | + Insert ····· Markdown · Open full editor\n * The overflow is a chevron next to the formatting, never a second \"⋯\" (the field's label row owns the one ⋯ menu).\n * It takes no room at rest (h-0, inert, aria-hidden) and slides open to 32px when the field is in use. Items fold into\n * \"More formatting options\" as the field narrows. A control whose element the field does not accept is not drawn.\n */\nimport * as React from \"react\";\nimport {\n IconArrowsMaximize, IconBlockquote, IconBold, IconCheck, IconChevronDown, IconClearFormatting, IconCode, IconH1, IconH2, IconH3, IconH4, IconH5,\n IconH6, IconItalic, IconLink, IconList, IconListNumbers, IconMarkdown, IconMarkdownOff, IconMessage, IconPilcrow, IconPlus, IconStrikethrough,\n IconTerminal2, IconUnderline,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../lib/cn\";\nimport { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Popover, PopoverTrigger, Tooltip } from \"../../ui/overlay\";\nimport { InsertMenuContent, type CatalogItem } from \"./catalog\";\nimport type { RichTextFeature } from \"./codec\";\n\nexport interface Fmt {\n bold: boolean;\n italic: boolean;\n underline: boolean;\n strike: boolean;\n ul: boolean;\n ol: boolean;\n /** lower-case tag of the caret's top-level block, or \"island\" */\n block: string;\n hasSel: boolean;\n onLink: boolean;\n}\nexport const EMPTY_FMT: Fmt = { bold: false, italic: false, underline: false, strike: false, ul: false, ol: false, block: \"p\", hasSel: false, onLink: false };\n\nexport type MarkCmd = \"bold\" | \"italic\" | \"underline\" | \"strikeThrough\";\nexport const MARK_FEATURE: Record<MarkCmd, RichTextFeature> = { bold: \"bold\", italic: \"italic\", underline: \"underline\", strikeThrough: \"strike\" };\n\nexport const STYLES: { tag: string; label: string; short: string; icon: React.ReactNode }[] = [\n { tag: \"p\", label: \"Text\", short: \"Text\", icon: <IconPilcrow stroke={1.5} /> },\n { tag: \"h1\", label: \"Heading 1\", short: \"H1\", icon: <IconH1 stroke={1.5} /> },\n { tag: \"h2\", label: \"Heading 2\", short: \"H2\", icon: <IconH2 stroke={1.5} /> },\n { tag: \"h3\", label: \"Heading 3\", short: \"H3\", icon: <IconH3 stroke={1.5} /> },\n { tag: \"h4\", label: \"Heading 4\", short: \"H4\", icon: <IconH4 stroke={1.5} /> },\n { tag: \"h5\", label: \"Heading 5\", short: \"H5\", icon: <IconH5 stroke={1.5} /> },\n { tag: \"h6\", label: \"Heading 6\", short: \"H6\", icon: <IconH6 stroke={1.5} /> },\n { tag: \"blockquote\", label: \"Quote\", short: \"Quote\", icon: <IconBlockquote stroke={1.5} /> },\n];\n/** The block styles a field accepts (Text always). */\nexport const stylesFor = (allows: (f: RichTextFeature) => boolean) => STYLES.filter((s) => s.tag === \"p\" || allows(s.tag as RichTextFeature));\n\nconst keepCaret = (e: React.MouseEvent) => e.preventDefault();\n\nexport function ToolButton({\n label,\n tip,\n icon,\n onClick,\n active,\n disabled,\n shortcut,\n children,\n className,\n}: {\n label: string;\n tip?: string;\n icon: React.ReactNode;\n onClick?: () => void;\n active?: boolean;\n disabled?: boolean;\n shortcut?: string;\n children?: React.ReactNode;\n className?: string;\n}) {\n return (\n <Tooltip content={tip ?? label} shortcut={shortcut}>\n <button\n type=\"button\"\n aria-label={label}\n aria-pressed={active}\n aria-disabled={disabled || undefined}\n onMouseDown={keepCaret}\n onClick={() => !disabled && onClick?.()}\n className={cn(\n \"flex h-7 min-w-7 shrink-0 items-center justify-center gap-1 rounded-kit-md px-1.5 text-kit-sm text-kit-fg-2 transition-colors hover:bg-kit-hover hover:text-kit-fg [&_svg]:size-4\",\n active && \"bg-kit-selected text-kit-fg\",\n disabled && \"opacity-40 hover:bg-transparent hover:text-kit-fg-2\",\n className,\n )}\n >\n {icon}\n {children}\n </button>\n </Tooltip>\n );\n}\n\n/** \"Block style\" dropdown. Compact trigger: Text / H1…H6 / Quote. */\nexport function StyleMenu({\n block,\n styles,\n onPick,\n onOpenChange,\n disabled,\n className,\n}: {\n block: string;\n styles: typeof STYLES;\n onPick: (tag: string) => void;\n onOpenChange?: (o: boolean) => void;\n disabled?: boolean;\n className?: string;\n}) {\n const cur = STYLES.find((s) => s.tag === block);\n return (\n <Menu onOpenChange={onOpenChange}>\n <Tooltip content=\"Block style\">\n <MenuTrigger\n disabled={disabled}\n aria-label=\"Block style\"\n onMouseDown={keepCaret}\n className={cn(\n \"flex h-7 shrink-0 items-center gap-1 rounded-kit-md pl-2 pr-1.5 text-kit-sm font-medium text-kit-fg hover:bg-kit-hover disabled:opacity-40 data-[popup-open]:bg-kit-hover\",\n !cur && \"text-kit-fg-2\",\n className,\n )}\n >\n {cur?.short ?? \"Text\"}\n <IconChevronDown className=\"size-3.5 text-kit-fg-3\" stroke={1.5} aria-hidden />\n </MenuTrigger>\n </Tooltip>\n <MenuContent className=\"w-48\" finalFocus={false}>\n {styles.map((s) => (\n <MenuItem key={s.tag} icon={s.icon} onClick={() => onPick(s.tag)}>\n <span className=\"flex w-full items-center justify-between\">\n {s.label}\n {block === s.tag ? <IconCheck className=\"size-3.5 text-kit-fg-2\" stroke={2} aria-hidden /> : null}\n </span>\n </MenuItem>\n ))}\n </MenuContent>\n </Menu>\n );\n}\n\nconst Sep = () => <span aria-hidden className=\"mx-1 h-4 w-px shrink-0 bg-kit-line\" />;\n\nexport function FormatToolbar({\n open,\n sticky,\n stickyTop = 0,\n width,\n dense,\n fmt,\n md,\n allows,\n hideFullscreen,\n insertOpen,\n setInsertOpen,\n onMenuOpen,\n onStyle,\n onMark,\n onList,\n onLink,\n onClear,\n onComment,\n onInlineCode,\n onCodeBlock,\n onInsert,\n keepFocusOnInsertClose,\n onFullscreen,\n onMarkdown,\n saveSel,\n}: {\n open: boolean;\n sticky: boolean;\n stickyTop?: number;\n width: number;\n dense: boolean;\n fmt: Fmt;\n md: boolean;\n allows: (f: RichTextFeature) => boolean;\n hideFullscreen?: boolean;\n insertOpen: boolean;\n setInsertOpen: (o: boolean) => void;\n onMenuOpen: (name: \"style\" | \"more\", o: boolean) => void;\n onStyle: (tag: string) => void;\n onMark: (cmd: MarkCmd) => void;\n onList: (kind: \"ul\" | \"ol\") => void;\n onLink: () => void;\n onClear: () => void;\n onComment?: () => void;\n onInlineCode: () => void;\n onCodeBlock: () => void;\n onInsert: (it: CatalogItem) => void;\n keepFocusOnInsertClose: () => boolean;\n onFullscreen: () => void;\n onMarkdown: () => void;\n saveSel: () => void;\n}) {\n const w = width - (dense ? 40 : 0);\n const foldUS = w < 430;\n const foldLists = w < 480;\n const foldMd = w < 400;\n const foldClear = w < 360;\n const insertLabel = w >= 590;\n const off = md;\n const styles = stylesFor(allows);\n const marks = ([\"underline\", \"strikeThrough\"] as const).filter((m) => allows(MARK_FEATURE[m]));\n const lists = ([\"ul\", \"ol\"] as const).filter((l) => allows(l));\n const linkTip = fmt.hasSel || fmt.onLink ? \"Link\" : \"Link (select some text first)\";\n const commentTip = fmt.hasSel ? \"Comment\" : \"Comment (select some text first)\";\n const check = (on: boolean) => (on ? <IconCheck className=\"ml-auto size-3.5 text-kit-fg-2\" stroke={2} aria-hidden /> : null);\n const listIcon = (l: \"ul\" | \"ol\") => (l === \"ul\" ? <IconList stroke={1.5} /> : <IconListNumbers stroke={1.5} />);\n const listLabel = (l: \"ul\" | \"ol\") => (l === \"ul\" ? \"Bulleted list\" : \"Numbered list\");\n const markIcon = (m: \"underline\" | \"strikeThrough\") => (m === \"underline\" ? <IconUnderline stroke={1.5} /> : <IconStrikethrough stroke={1.5} />);\n const markLabel = (m: \"underline\" | \"strikeThrough\") => (m === \"underline\" ? \"Underline\" : \"Strikethrough\");\n const more = (foldUS && marks.length) || (foldLists && lists.length) || foldClear || foldMd || allows(\"code\") || allows(\"pre\");\n\n return (\n <div\n className={cn(\"overflow-clip rounded-t-kit-lg transition-[height] duration-150 ease-out\", open ? \"h-8 pointer-coarse:h-11\" : \"h-0\", sticky && open && \"sticky z-[4]\")}\n style={sticky && open ? { top: stickyTop } : undefined}\n inert={!open}\n aria-hidden={!open}\n >\n <div\n role=\"toolbar\"\n aria-label=\"Text formatting\"\n onMouseDown={(e) => {\n if (!(e.target as HTMLElement).closest(\"button\")) e.preventDefault();\n }}\n className={cn(\"flex h-full items-center gap-0.5 border-b border-kit-line bg-kit-subtle px-1 transition-opacity duration-[120ms] ease-out\", open ? \"opacity-100\" : \"opacity-0\")}\n >\n {styles.length > 1 ? (\n <>\n <StyleMenu block={fmt.block} styles={styles} onPick={onStyle} disabled={off} onOpenChange={(o) => onMenuOpen(\"style\", o)} />\n <Sep />\n </>\n ) : null}\n {allows(\"bold\") ? <ToolButton label=\"Bold\" icon={<IconBold stroke={1.5} />} shortcut=\"⌘B\" active={fmt.bold} disabled={off} onClick={() => onMark(\"bold\")} /> : null}\n {allows(\"italic\") ? <ToolButton label=\"Italic\" icon={<IconItalic stroke={1.5} />} shortcut=\"⌘I\" active={fmt.italic} disabled={off} onClick={() => onMark(\"italic\")} /> : null}\n {foldUS\n ? null\n : marks.map((m) => (\n <ToolButton key={m} label={markLabel(m)} icon={markIcon(m)} shortcut={m === \"underline\" ? \"⌘U\" : undefined} active={m === \"underline\" ? fmt.underline : fmt.strike} disabled={off} onClick={() => onMark(m)} />\n ))}\n {foldLists || !lists.length ? null : (\n <>\n <Sep />\n {lists.map((l) => (\n <ToolButton key={l} label={listLabel(l)} icon={listIcon(l)} active={fmt[l]} disabled={off} onClick={() => onList(l)} />\n ))}\n </>\n )}\n <Sep />\n {allows(\"link\") ? (\n <ToolButton label=\"Link\" tip={linkTip} icon={<IconLink stroke={1.5} />} shortcut={fmt.hasSel || fmt.onLink ? \"⌘K\" : undefined} active={fmt.onLink} disabled={off || !(fmt.hasSel || fmt.onLink)} onClick={onLink} />\n ) : null}\n {foldClear ? null : <ToolButton label=\"Clear formatting\" icon={<IconClearFormatting stroke={1.5} />} disabled={off} onClick={onClear} />}\n {onComment ? <ToolButton label=\"Comment\" tip={commentTip} icon={<IconMessage stroke={1.5} />} disabled={off || !fmt.hasSel} onClick={onComment} /> : null}\n {more ? (\n <Menu onOpenChange={(o) => onMenuOpen(\"more\", o)}>\n <Tooltip content=\"More formatting\">\n <MenuTrigger\n aria-label=\"More formatting options\"\n onMouseDown={(e) => {\n e.preventDefault();\n saveSel();\n }}\n className=\"flex h-7 w-5 shrink-0 items-center justify-center rounded-kit-md text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg data-[popup-open]:bg-kit-hover data-[popup-open]:text-kit-fg [&_svg]:size-3.5\"\n >\n <IconChevronDown stroke={1.5} aria-hidden />\n </MenuTrigger>\n </Tooltip>\n <MenuContent align=\"start\" className=\"w-56\" finalFocus={false}>\n {foldUS\n ? marks.map((m) => (\n <MenuItem key={m} disabled={off} icon={markIcon(m)} shortcut={m === \"underline\" ? \"⌘U\" : undefined} onClick={() => onMark(m)}>\n <span className=\"flex w-full items-center\">\n {markLabel(m)}\n {check(m === \"underline\" ? fmt.underline : fmt.strike)}\n </span>\n </MenuItem>\n ))\n : null}\n {foldLists\n ? lists.map((l) => (\n <MenuItem key={l} disabled={off} icon={listIcon(l)} onClick={() => onList(l)}>\n {listLabel(l)}\n </MenuItem>\n ))\n : null}\n {foldClear ? (\n <MenuItem disabled={off} icon={<IconClearFormatting stroke={1.5} />} onClick={onClear}>\n Clear formatting\n </MenuItem>\n ) : null}\n {foldMd ? (\n <MenuItem icon={md ? <IconMarkdownOff stroke={1.5} /> : <IconMarkdown stroke={1.5} />} onClick={onMarkdown}>\n {md ? \"Return to rich text\" : \"View and edit as Markdown\"}\n </MenuItem>\n ) : null}\n {(foldUS && marks.length) || (foldLists && lists.length) || foldClear || foldMd ? <MenuSeparator /> : null}\n {allows(\"code\") ? (\n <MenuItem disabled={off} icon={<IconCode stroke={1.5} />} shortcut=\"⌘E\" onClick={onInlineCode}>\n Inline code\n </MenuItem>\n ) : null}\n {allows(\"pre\") ? (\n <MenuItem disabled={off} icon={<IconTerminal2 stroke={1.5} />} onClick={onCodeBlock}>\n Code\n </MenuItem>\n ) : null}\n </MenuContent>\n </Menu>\n ) : null}\n <Sep />\n <Popover open={insertOpen} onOpenChange={setInsertOpen}>\n <Tooltip content=\"Insert a block\">\n <PopoverTrigger\n disabled={off}\n aria-label=\"Insert\"\n onMouseDown={() => saveSel()}\n className=\"flex h-7 shrink-0 items-center gap-1 rounded-kit-md px-1.5 text-kit-sm text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg disabled:opacity-40 data-[popup-open]:bg-kit-hover data-[popup-open]:text-kit-fg [&_svg]:size-4\"\n >\n <IconPlus stroke={1.5} aria-hidden />\n {insertLabel ? \"Insert\" : null}\n </PopoverTrigger>\n </Tooltip>\n {insertOpen ? <InsertMenuContent allows={allows} onInsert={onInsert} keepFocusOnClose={keepFocusOnInsertClose} /> : null}\n </Popover>\n\n <span className=\"min-w-1 flex-1\" />\n\n {foldMd ? null : (\n <ToolButton label={md ? \"Return to rich text\" : \"View and edit as Markdown\"} icon={md ? <IconMarkdownOff stroke={1.5} /> : <IconMarkdown stroke={1.5} />} active={md} onClick={onMarkdown} />\n )}\n {hideFullscreen ? null : <ToolButton label=\"Expand editor\" icon={<IconArrowsMaximize stroke={1.5} />} shortcut=\"⌘↵\" onClick={onFullscreen} />}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
package/controls/scale.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scale.js","names":[],"sources":["../../src/kit/controls/scale.tsx"],"sourcesContent":["/**\n * SCALE — one control, two modes (CPO D41), in the designer's CAPSULE: a muted 32px capsule, a soft fill to the value,\n * a 3px bar thumb at the fill's end (always right of the label), the label inside on the left (panels) and the value\n * inside on the right. Drag anywhere to slide (always snaps to the steps), ←→ / Home / End / PageUp / PageDown.\n * · Fixed only (default): steps snap; the readout shows the token (\"Large\"), its tooltip the size (88px); scrub it sideways.\n * · Fixed + custom (`allowCustom`): DIRECT edit, no mode switch — one click on the value puts the caret there with the\n * value selected; double-click anywhere or just start typing on the focused capsule does the same. \"24\", \"24px\", \"5%\",\n * \"xl\" apply live; Enter / Tab / blur commit, Esc reverts. The unit is plain suffix text (parsed from what you type;\n * with several units, clicking it cycles them). While typing, token chips under the capsule pick a step in one click;\n * ↑↓ step the tokens. A custom value shows a small accent dot and sits proportionally between its tokens.\n * Used by the Block Kit number control (`field.scale`, or the legacy `layout: \"slider\"`) and by the Visuals panels.\n *\n * Port of V2 HEAD 9829bf1 kit/controls/scale.tsx. V2 tokens map to the kit's (bg-muted → bg-kit-muted, --ring-focus →\n * the kit focus ring). V2's native `title=` hints become kit tooltips (the dashboard bans native title tooltips); the\n * custom value keeps ONE tooltip mounted and closes it while typing, so the input never remounts mid-edit.\n * Values are stored as they are (adapters/values.ts scaleToProd): a number, a token step's string, or { value, unit }.\n */\nimport * as React from \"react\";\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\";\nimport { Tooltip } from \"../ui/overlay\";\nimport { TooltipLayer, TooltipRoot } from \"../ui/tooltip-root\";\nimport { cn } from \"../lib/cn\";\nimport {\n customPx, customRules, defaultUnit, formatNumber, isCustomValue, isTokenScale, nearestTokenIndex, parseScaleInput, rangeOf, resolveScale, roundTo,\n scaleHint, UNIT_NAMES, validateCustom, fieldScale,\n} from \"../schema/scale\";\nimport type { ScaleCustomValue, ScaleSchema, ScaleUnit, ScaleValue } from \"../schema/types\";\nimport type { ControlProps } from \"../types\";\n\nexport interface ScaleSliderProps {\n scale: ScaleSchema;\n value: unknown;\n onChange: (v: ScaleValue) => void;\n /** Accessible name (the field title). */\n label: string;\n /** id for the primary control: the input when custom is allowed, otherwise the slider thumb. */\n id?: string;\n disabled?: boolean;\n readOnly?: boolean;\n invalid?: boolean;\n /** an error from outside (schema validation, a design-system demo); a parse error from typing wins */\n error?: string;\n /** \"form\" (Block Kit: label above, tick labels under the track) · \"panel\" (inspector row: inline scrub label). */\n density?: \"form\" | \"panel\";\n /** panel: show the label inline on the left (it scrubs). */\n inlineLabel?: boolean;\n icon?: React.ReactNode;\n /** panel: extra classes for the inline label. */\n labelClassName?: string;\n /** a unit word that isn't a CSS unit (\"items\", \"s\") — shown after numbers */\n suffix?: string;\n /** readout for range values (legacy `format`) */\n format?: (n: number) => string;\n onBlur?: () => void;\n /** Enter committed a typed value (custom fields) or was pressed on a fixed capsule — hosts like the canvas popover close on it */\n onEnter?: () => void;\n /** start in edit mode with the value selected (the canvas badge → in-place edit) */\n autoEdit?: boolean;\n /** Tab / Shift+Tab while typing: commit, then the host moves to the next / previous size (canvas popover sides) */\n onTab?: (dir: 1 | -1) => void;\n className?: string;\n}\n\nconst clamp = (n: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, n));\n\n/** Horizontal scrubbing (Figma-style) on any element: drag → whole steps; click without moving → onClick. */\nfunction useScrub(onSteps: (delta: number, e: PointerEvent | React.PointerEvent) => void, pxPerStep: number, onClick?: () => void) {\n const st = React.useRef<{ x: number; moved: boolean; last: number } | null>(null);\n return {\n onPointerDown(e: React.PointerEvent) {\n if (e.button !== 0) return;\n e.preventDefault();\n (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);\n st.current = { x: e.clientX, moved: false, last: 0 };\n },\n onPointerMove(e: React.PointerEvent) {\n const s = st.current;\n if (!s) return;\n const dx = e.clientX - s.x;\n if (!s.moved && Math.abs(dx) < 3) return;\n s.moved = true;\n const steps = Math.trunc(dx / pxPerStep);\n if (steps !== s.last) {\n onSteps(steps - s.last, e);\n s.last = steps;\n }\n },\n onPointerUp() {\n const s = st.current;\n st.current = null;\n if (s && !s.moved) onClick?.();\n },\n onPointerCancel() {\n st.current = null;\n },\n };\n}\n\nexport function ScaleSlider({\n scale,\n value,\n onChange,\n label,\n id,\n disabled,\n readOnly,\n invalid,\n error: externalError,\n inlineLabel,\n icon,\n labelClassName,\n suffix,\n format,\n onBlur,\n onEnter,\n autoEdit,\n onTab,\n className,\n}: ScaleSliderProps) {\n const uid = React.useId();\n const errId = `scale-err-${uid}`; // must NOT start with the field id: FieldShell strips its own `${id}-…` ids\n const tokens = isTokenScale(scale) ? scale.steps : null;\n const range = rangeOf(scale);\n const custom = customRules(scale);\n const r = resolveScale(scale, value, suffix);\n const isCustom = isCustomValue(value);\n const inert = disabled || readOnly;\n\n /* ── position on the track (0..1); -1 = can't place (custom % on a px scale) ── */\n const count = tokens ? tokens.length : 0;\n const nearest = isCustom ? (tokens ? nearestTokenIndex(scale, value as ScaleCustomValue) : -1) : -1;\n let pos: number;\n if (tokens) {\n const i = isCustom ? nearest : r.index ?? 0;\n pos = i < 0 ? -1 : count > 1 ? i / (count - 1) : 0;\n } else {\n const lo = range!.min;\n const hi = range!.max;\n const n = isCustom\n ? (value as ScaleCustomValue).unit === defaultUnit(scale)\n ? (value as ScaleCustomValue).value\n : NaN\n : typeof value === \"number\"\n ? value\n : lo;\n pos = Number.isNaN(n) ? -1 : (clamp(n, lo, hi) - lo) / (hi - lo || 1);\n }\n const step = range?.step ?? 1;\n\n /* ── value moves ── */\n const tokenAt = (i: number) => tokens![clamp(i, 0, count - 1)].value;\n const currentIndex = () => (isCustom ? Math.max(0, nearest) : r.index ?? 0);\n const numAt = (n: number) => roundTo(clamp(n, range!.min, range!.max), step);\n const currentNum = () => (typeof value === \"number\" ? value : isCustom && pos >= 0 ? (value as ScaleCustomValue).value : range!.min);\n const fromFraction = (f: number): ScaleValue => (tokens ? tokenAt(Math.round(f * (count - 1))) : numAt(range!.min + f * (range!.max - range!.min)));\n const nudgeScale = (d: number): ScaleValue => (tokens ? tokenAt(currentIndex() + d) : numAt(currentNum() + d * step));\n const backToScale = (): ScaleValue => (tokens ? tokenAt(nearest >= 0 ? nearest : Math.floor((count - 1) / 2)) : numAt(currentNum()));\n const commit = (v: ScaleValue) => {\n if (inert) return;\n if (JSON.stringify(v) !== JSON.stringify(value)) onChange(v);\n };\n\n /* ── custom values sit proportionally between the tokens they fall between (px interpolation) ── */\n let between: [number, number] | null = null;\n if (tokens && isCustom) {\n const px = customPx(value as ScaleCustomValue);\n const pts = tokens.map((t, i) => ({ i, px: t.px })).filter((t): t is { i: number; px: number } => t.px != null);\n if (px != null && pts.length >= 2) {\n let f = -1;\n if (px <= pts[0].px) f = pts[0].i;\n else if (px >= pts[pts.length - 1].px) f = pts[pts.length - 1].i;\n else\n for (let k = 0; k < pts.length - 1; k++) {\n const a = pts[k];\n const b = pts[k + 1];\n if (px >= a.px && px <= b.px) {\n f = a.i + ((px - a.px) / Math.max(1, b.px - a.px)) * (b.i - a.i);\n between = [a.i, b.i];\n break;\n }\n }\n pos = f < 0 ? -1 : count > 1 ? f / (count - 1) : 0;\n }\n }\n\n /* ── geometry: the fill starts AFTER the inline label, so the thumb never sits on the label ── */\n const trackRef = React.useRef<HTMLDivElement>(null);\n const thumbRef = React.useRef<HTMLDivElement>(null);\n const labelRef = React.useRef<HTMLSpanElement>(null);\n const [labelW, setLabelW] = React.useState(28);\n const valueRef = React.useRef<HTMLSpanElement>(null);\n const [valueW, setValueW] = React.useState(40);\n React.useLayoutEffect(() => {\n const el = valueRef.current;\n if (!el) return;\n const measure = () => setValueW(Math.ceil(el.getBoundingClientRect().width));\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, [custom]);\n React.useLayoutEffect(() => {\n const el = labelRef.current;\n if (!el) return setLabelW(28);\n const measure = () => setLabelW(Math.max(28, Math.ceil(el.getBoundingClientRect().width) + 4));\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, [inlineLabel, label]);\n const [dragging, setDragging] = React.useState(false);\n /* keyboard-only ring: follows the app's data-input-modality (D29), never after a click */\n const [kbFocus, setKbFocus] = React.useState(false);\n const fracFromX = (x: number) => {\n const rect = trackRef.current!.getBoundingClientRect();\n return clamp((x - rect.left - labelW) / Math.max(1, rect.width - labelW), 0, 1);\n };\n\n /* ── direct edit (custom fields): click the value, double-click anywhere, or just type ── */\n const inputRef = React.useRef<HTMLInputElement>(null);\n const [draft, setDraft] = React.useState<string | null>(null);\n const [typedError, setError] = React.useState<string | null>(null);\n const error = typedError ?? externalError ?? null;\n const [unitHint, setUnitHint] = React.useState<ScaleUnit | undefined>(undefined);\n const [editing, setEditing] = React.useState(false);\n const editStart = React.useRef<unknown>(value);\n const justBegan = React.useRef(false); // the click that opened editing must not drop a caret over the selection\n const shownUnit: ScaleUnit | undefined = unitHint ?? (isCustom ? (value as ScaleCustomValue).unit : defaultUnit(scale) ?? custom?.units[0]);\n const fixedText = r.kind === \"number\" && format && typeof value === \"number\" ? format(value) : r.label;\n const valueText = isCustom ? formatNumber((value as ScaleCustomValue).value) : r.kind === \"token\" ? r.label : r.kind === \"number\" ? formatNumber(value as number) : \"\";\n const inputText = draft ?? valueText;\n const tokenOnly = !isCustom && r.kind === \"token\"; // unit suffix is meaningless next to \"Medium\"\n\n const beginEdit = (seed?: string) => {\n if (inert || !custom) return;\n if (!editing) editStart.current = value;\n setEditing(true);\n setError(null);\n const el = inputRef.current;\n if (!el) return;\n el.focus({ preventScroll: true }); // synchronous: the next keystrokes land in the input\n if (seed != null) {\n setDraft(seed);\n applyText(seed);\n requestAnimationFrame(() => inputRef.current?.setSelectionRange(seed.length, seed.length));\n } else {\n el.select();\n justBegan.current = true;\n }\n };\n const endEdit = (how: \"commit\" | \"revert\", focusThumb: boolean) => {\n if (how === \"revert\") commit(editStart.current as ScaleValue);\n setDraft(null);\n setError(null);\n setUnitHint(undefined);\n setEditing(false);\n if (focusThumb) thumbRef.current?.focus({ preventScroll: true });\n };\n /** Applies what's typed LIVE when it parses; otherwise shows the reason and keeps the last good value. */\n function applyText(text: string, showError = false) {\n if (!text.trim()) return setError(null);\n const res = parseScaleInput(scale, text, unitHint);\n if (res.ok) {\n setError(null);\n commit(res.value);\n return true;\n }\n // half-typed (\"x\" on the way to \"xl\") stays quiet; the reason shows when you try to commit\n setError(showError ? res.error : null);\n return false;\n }\n /** ↑↓ while editing: step the tokens (from a custom value, the next token in that direction). */\n const stepTokens = (dir: 1 | -1, e: { shiftKey: boolean }) => {\n if (tokens && isCustom) {\n const lo = between ? between[0] : nearest;\n const hi = between ? between[1] : nearest;\n commit(tokenAt(dir > 0 ? (between ? hi : nearest + 1) : between ? lo : nearest - 1));\n } else commit(nudgeScale(dir * (!tokens && e.shiftKey ? 10 : 1)));\n setDraft(null);\n setError(null);\n };\n /* keep the field's text in sync with outside changes (drag, undo) while not typing: adjusted during render when the\n value changes (V2 did this in an effect keyed on `value`) */\n const valueKey = JSON.stringify(value ?? null);\n const [seenValue, setSeenValue] = React.useState(valueKey);\n if (seenValue !== valueKey) {\n setSeenValue(valueKey);\n if (draft == null && !externalError && typedError !== null) setError(null);\n }\n\n const unitsList = custom?.units ?? [];\n const cycleUnit = () => {\n if (inert || unitsList.length < 2) return;\n const cur = shownUnit && unitsList.includes(shownUnit) ? shownUnit : unitsList[0];\n const next = unitsList[(unitsList.indexOf(cur) + 1) % unitsList.length];\n setUnitHint(next);\n if (isCustom) {\n const cv: ScaleCustomValue = { value: (value as ScaleCustomValue).value, unit: next };\n // 720px → % would be out of range: keep the value, select the number and let the next keystrokes be in the new unit\n if (validateCustom(scale, cv)) beginEdit();\n else {\n setError(null);\n commit(cv);\n }\n } else beginEdit();\n };\n\n const onTrackKey = (e: React.KeyboardEvent) => {\n if (inert) return;\n /* just start typing: a digit, a dot or a letter opens the value with that character */\n if (custom && !e.metaKey && !e.ctrlKey && !e.altKey && e.key.length === 1 && /[0-9.a-z%]/i.test(e.key)) {\n e.preventDefault();\n beginEdit(e.key);\n return;\n }\n if (e.key === \"Enter\" && onEnter) {\n e.preventDefault();\n onEnter();\n return;\n }\n const big = tokens ? 2 : Math.max(1, Math.round((range!.max - range!.min) / step / 10));\n const mult = e.shiftKey && !tokens ? 10 : 1;\n let next: ScaleValue | null = null;\n if (e.key === \"ArrowRight\" || e.key === \"ArrowUp\") next = isCustom ? (tokens ? tokenAt(between ? between[1] : nearest + 1) : backToScale()) : nudgeScale(mult);\n else if (e.key === \"ArrowLeft\" || e.key === \"ArrowDown\") next = isCustom ? (tokens ? tokenAt(between ? between[0] : nearest - 1) : backToScale()) : nudgeScale(-mult);\n else if (e.key === \"PageUp\") next = nudgeScale(big);\n else if (e.key === \"PageDown\") next = nudgeScale(-big);\n else if (e.key === \"Home\") next = tokens ? tokenAt(0) : range!.min;\n else if (e.key === \"End\") next = tokens ? tokenAt(count - 1) : range!.max;\n if (next == null) return;\n e.preventDefault();\n commit(next);\n };\n\n /* aria-describedby: add/remove our error id without clobbering the ids FieldShell wires (help, ⓘ, issue). */\n React.useEffect(() => {\n for (const el of [inputRef.current, thumbRef.current]) {\n if (!el) continue;\n const own = (el.getAttribute(\"aria-describedby\") ?? \"\").split(\" \").filter((t) => t && t !== errId);\n const next = error ? [...own, errId] : own;\n if (next.length) el.setAttribute(\"aria-describedby\", next.join(\" \"));\n else el.removeAttribute(\"aria-describedby\");\n }\n }, [error, errId, editing]);\n\n React.useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- autoEdit focuses the input on mount (a DOM sync), once\n if (autoEdit) beginEdit();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n /* fixed fields: scrub the readout sideways (Figma-style) */\n const scrubPx = tokens ? 16 : Math.max(3, Math.min(12, 160 / ((range!.max - range!.min) / step)));\n const readoutScrub = useScrub((delta, e) => !inert && commit(nudgeScale(delta * (!tokens && e.shiftKey ? 10 : 1))), scrubPx);\n\n const betweenText = isCustom\n ? tokens && between\n ? `Custom value · between ${tokens[between[0]].label} and ${tokens[between[1]].label}`\n : tokens && nearest >= 0\n ? `Custom value · near ${tokens[nearest].label}`\n : \"Custom value\"\n : undefined;\n const pct = Math.max(0, pos);\n const fillW = `calc(${labelW}px + (100% - ${labelW}px) * ${pct})`;\n const tooltip = r.kind === \"token\" && r.css ? scaleHint(r) : betweenText;\n const presets = custom ? scale.presets ?? [] : [];\n const showChips = editing && ((!!tokens && count <= 9) || presets.length > 0);\n\n return (\n <div className={cn(\"min-w-0\", className)} data-scale-mode={custom ? \"custom\" : \"fixed\"}>\n <div\n ref={trackRef}\n onPointerDown={(e) => {\n if (inert || e.button !== 0) return;\n if ((e.target as HTMLElement).closest(\"[data-scale-value]\")) return; // the value area edits, it doesn't scrub\n e.preventDefault();\n (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);\n setDragging(true);\n setKbFocus(false);\n if (editing) endEdit(\"commit\", false);\n commit(fromFraction(fracFromX(e.clientX)));\n thumbRef.current?.focus({ preventScroll: true });\n }}\n onPointerMove={(e) => dragging && commit(fromFraction(fracFromX(e.clientX)))}\n onPointerUp={() => setDragging(false)}\n onPointerCancel={() => setDragging(false)}\n onDoubleClick={() => beginEdit()}\n className={cn(\n \"group/cap relative flex h-8 w-full touch-none select-none items-center overflow-hidden rounded-kit-md bg-kit-muted transition-[background-color,box-shadow]\",\n inert ? \"cursor-not-allowed\" : \"cursor-ew-resize hover:bg-kit-hover\",\n disabled && \"opacity-50\",\n /* neutral, keyboard-only ring (never after a click); a quiet 1px inner line while typing; red only for an error */\n kbFocus && !editing && !error && \"shadow-[0_0_0_2px_var(--kit-surface),0_0_0_4px_var(--kit-focus-ring)]\",\n editing && !error && \"shadow-[inset_0_0_0_1px_var(--kit-line-strong)]\",\n error && \"shadow-[inset_0_0_0_1px_var(--kit-danger)]\",\n )}\n >\n {pos >= 0 ? (\n <div\n aria-hidden\n className={cn(\n \"absolute inset-y-0 left-0 rounded-l-kit-md bg-[color-mix(in_oklab,var(--kit-fg)_9%,transparent)]\",\n !dragging && \"motion-safe:transition-[width] motion-safe:duration-75\",\n )}\n style={{ width: fillW }}\n />\n ) : null}\n {/* thumb = the designer's 3px bar at the fill's end — always right of the label; it is the focusable slider */}\n <div\n ref={thumbRef}\n id={custom ? undefined : id}\n role=\"slider\"\n tabIndex={disabled ? -1 : 0}\n aria-label={label}\n aria-valuemin={tokens ? 0 : range!.min}\n aria-valuemax={tokens ? count - 1 : range!.max}\n aria-valuenow={tokens ? currentIndex() : clamp(currentNum(), range!.min, range!.max)}\n aria-valuetext={r.spoken}\n aria-disabled={disabled || undefined}\n aria-readonly={readOnly || undefined}\n aria-invalid={(!custom && invalid) || undefined}\n aria-orientation=\"horizontal\"\n onKeyDown={(e) => {\n setKbFocus(true);\n onTrackKey(e);\n }}\n onFocus={() => setKbFocus(document.documentElement.dataset.inputModality === \"keyboard\")}\n onBlur={() => {\n setKbFocus(false);\n onBlur?.();\n }}\n className={cn(\n \"absolute top-1/2 z-[1] h-4 w-[3px] -translate-x-full -translate-y-1/2 rounded-full bg-kit-fg-3 opacity-0 outline-none focus-visible:!shadow-none focus-visible:!outline-none\",\n !inert && \"group-hover/cap:opacity-100\",\n \"focus-visible:opacity-100\",\n dragging && \"opacity-100\",\n (pos < 0 || editing) && \"!opacity-0\",\n !dragging && \"motion-safe:transition-[left,opacity] motion-safe:duration-75\",\n )}\n style={{ left: `min(calc(${fillW} - 4px), calc(100% - ${valueW}px - 2px))` /* never on the label, never on the value */ }}\n />\n {inlineLabel ? (\n <span ref={labelRef} className={cn(\"pointer-events-none relative z-[2] flex min-w-0 shrink items-center gap-1.5 pl-3 pr-1 text-kit-xs text-kit-fg-2 [&_svg]:size-3.5\", labelClassName)}>\n {icon}\n <span className=\"truncate\">{label}</span>\n </span>\n ) : null}\n <span className=\"flex-1\" />\n\n {/* value — inside the capsule on the right */}\n {custom ? (\n /* one tooltip stays mounted and closes while typing, so the input never remounts mid-edit */\n <StableTip content={tooltip} off={editing}>\n <span\n ref={valueRef}\n data-scale-value\n onPointerDown={(e) => {\n if (inert || e.button !== 0) return;\n e.stopPropagation();\n if (!editing) {\n e.preventDefault();\n beginEdit(); // one click: caret in place, the value selected\n }\n }}\n onMouseUp={(e) => {\n if (!justBegan.current) return;\n justBegan.current = false;\n e.preventDefault();\n inputRef.current?.select();\n }}\n onMouseDown={(e) => {\n // the browser's own mousedown focus would pull focus back off the input we just focused\n if (!editing || e.target !== inputRef.current) e.preventDefault();\n }}\n className={cn(\"relative z-[2] flex h-full shrink-0 items-center gap-1 pl-2 pr-3\", !inert && \"cursor-text\")}\n >\n {isCustom && !editing ? <span aria-hidden className=\"size-1.5 shrink-0 rounded-full bg-kit-accent\" /> : null}\n <input\n ref={inputRef}\n id={id}\n inputMode=\"text\"\n autoComplete=\"off\"\n spellCheck={false}\n aria-label={`${label} value`}\n aria-description={betweenText}\n aria-invalid={!!error || invalid || undefined}\n readOnly={readOnly}\n disabled={disabled}\n tabIndex={-1}\n value={inputText}\n size={1}\n style={{ width: `${Math.max(1, inputText.length) + 0.5}ch` }}\n onFocus={() => {\n if (!editing) beginEdit();\n }}\n onBlur={() => {\n if (!editing) return;\n if (draft != null && draft.trim() && !parseScaleInput(scale, draft, unitHint).ok) endEdit(\"revert\", false);\n else endEdit(\"commit\", false);\n onBlur?.();\n }}\n onChange={(e) => {\n setDraft(e.target.value);\n applyText(e.target.value);\n }}\n onWheel={(e) => e.currentTarget.blur()}\n onKeyDown={(e) => {\n e.stopPropagation();\n if (e.key === \"Tab\" && onTab) {\n e.preventDefault();\n if (draft != null && !applyText(draft, true)) return; // stay and fix it\n endEdit(\"commit\", false);\n onTab(e.shiftKey ? -1 : 1);\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n if (draft != null && !applyText(draft, true)) return; // stay and fix it\n endEdit(\"commit\", true);\n onEnter?.();\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n endEdit(\"revert\", true);\n } else if (e.key === \"ArrowUp\" || e.key === \"ArrowDown\") {\n e.preventDefault();\n stepTokens(e.key === \"ArrowUp\" ? 1 : -1, e);\n }\n }}\n className={cn(\n \"h-6 min-w-0 bg-transparent p-0 text-right text-kit-xs tabular-nums text-kit-fg outline-none placeholder:text-kit-fg-4 focus:shadow-none focus-visible:shadow-none focus-visible:outline-none selection:bg-kit-selected\",\n isCustom || editing ? \"font-normal\" : \"font-medium\",\n !editing && \"pointer-events-none\",\n )}\n />\n {!tokenOnly || editing ? (\n unitsList.length > 1 ? (\n <Tooltip content={`Units: ${unitsList.join(\", \")} — click to switch, or type one (24%)`}>\n <button\n type=\"button\"\n tabIndex={-1}\n disabled={inert}\n onPointerDown={(e) => {\n e.stopPropagation();\n e.preventDefault(); // keep the caret in the value\n }}\n onClick={cycleUnit}\n aria-label={`Unit: ${shownUnit ? UNIT_NAMES[shownUnit] : \"none\"}. Switch unit`}\n className=\"rounded-kit-xs text-kit-xs text-kit-fg-3 transition-colors hover:text-kit-fg\"\n >\n {shownUnit}\n </button>\n </Tooltip>\n ) : (\n <span aria-hidden className=\"text-kit-xs text-kit-fg-3\">{shownUnit}</span>\n )\n ) : null}\n </span>\n </StableTip>\n ) : (\n <Tooltip content={tooltip}>\n <span\n ref={valueRef}\n aria-hidden\n {...(inert ? {} : readoutScrub)}\n className={cn(\"relative z-[2] whitespace-nowrap pl-2 pr-3 text-kit-xs font-medium tabular-nums text-kit-fg\", !inert && \"cursor-ew-resize\")}\n >\n {fixedText}\n </span>\n </Tooltip>\n )}\n </div>\n\n {/* quick tokens while typing — one click picks a step and leaves edit mode */}\n {showChips ? (\n <div role=\"group\" aria-label={`${label} steps`} className=\"mt-1 flex flex-wrap items-center gap-0.5\">\n {(tokens && count <= 9 ? tokens : []).map((t, i) => {\n const on = !isCustom && r.index === i;\n return (\n <Tooltip key={t.value} content={t.px != null ? `${t.title ?? t.label} · ${t.px}px` : t.css ? `${t.title ?? t.label} · ${t.css}` : t.title}>\n <button\n type=\"button\"\n tabIndex={-1}\n aria-pressed={on}\n onPointerDown={(e) => e.preventDefault() /* keep the caret until the click lands */}\n onClick={() => {\n commit(t.value);\n endEdit(\"commit\", true);\n }}\n className={cn(\n \"h-5 rounded-kit-sm px-1.5 text-kit-2xs transition-colors\",\n on ? \"bg-kit-selected font-medium text-kit-fg\" : \"text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\",\n )}\n >\n {shortToken(t.label)}\n </button>\n </Tooltip>\n );\n })}\n {/* developer presets: extra quick picks after the steps, behind a hairline */}\n {presets.length ? (\n <>\n {tokens && count <= 9 ? <span aria-hidden className=\"mx-1 h-3 w-px bg-kit-line-strong\" /> : null}\n {presets.map((p, i) => {\n const pr = resolveScale(scale, p.value, suffix);\n const on = JSON.stringify(p.value) === JSON.stringify(value);\n return (\n <Tooltip key={`preset-${i}`} content={p.label ? `${p.label} · ${pr.label}` : pr.label}>\n <button\n type=\"button\"\n tabIndex={-1}\n aria-pressed={on}\n onPointerDown={(e) => e.preventDefault()}\n onClick={() => {\n commit(p.value);\n endEdit(\"commit\", true);\n }}\n className={cn(\"h-5 rounded-kit-sm px-1.5 text-kit-2xs tabular-nums transition-colors\", on ? \"bg-kit-selected font-medium text-kit-fg\" : \"text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\")}\n >\n {pr.label}\n </button>\n </Tooltip>\n );\n })}\n </>\n ) : null}\n </div>\n ) : null}\n {error ? (\n <p id={errId} role=\"status\" aria-live=\"polite\" className=\"mt-1 text-kit-xs text-kit-danger-fg\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\n/**\n * A tooltip whose trigger never changes tree shape: `off` (typing) or no content keeps it closed instead of unwrapping\n * the child, which would remount the input inside it and drop the caret.\n */\nfunction StableTip({ content, off, children }: { content?: string; off?: boolean; children: React.ReactElement }) {\n const closed = off || !content;\n return (\n <TooltipRoot open={closed ? false : undefined}>\n <TooltipPrimitive.Trigger delay={350} render={children} />\n <TooltipLayer>\n <span className=\"line-clamp-[8] min-w-0 whitespace-normal [overflow-wrap:anywhere]\">{content}</span>\n </TooltipLayer>\n </TooltipRoot>\n );\n}\n\n/** \"Medium\" → \"M\", \"Extra large\"/\"XL\" → \"XL\", \"Full bleed\" stays readable. */\nfunction shortToken(label: string) {\n const map: Record<string, string> = { None: \"0\", Small: \"S\", Medium: \"M\", Large: \"L\" };\n return map[label] ?? label;\n}\n\n/** Block Kit adapter: `field.scale` (or legacy `layout: \"slider\"` + numeric). */\nexport function ScaleControl({ field, value, onChange, readOnly, id, invalid, onBlur }: ControlProps) {\n const scale = fieldScale(field)!;\n const unit = field.numeric?.unit;\n const suffix = unit && ![\"px\", \"%\", \"rem\", \"em\", \"vw\", \"vh\"].includes(unit) ? unit : undefined;\n return (\n <ScaleSlider\n scale={scale}\n value={value ?? field.initialValue}\n onChange={(v) => onChange(v)}\n label={field.title}\n id={id}\n readOnly={readOnly}\n invalid={invalid}\n suffix={suffix}\n onBlur={onBlur}\n density=\"form\"\n />\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"slot-register.js","names":[],"sources":["../../src/kit/controls/slot-register.ts"],"sourcesContent":["/**\n * Lane L3: a component slot (a json field the host marks `componentSlot`) draws the slot control; every other json\n * field keeps the json editor. Imported after json-register (kit barrel), so it wraps the registered json control.\n */\nimport { createElement } from \"react\";\nimport type { ControlProps } from \"../types\";\nimport { CONTROLS } from \"../engine/kit-field\";\nimport { JsonControl } from \"./json\";\nimport { ComponentSlotControl } from \"./slot\";\n\nconst Json = CONTROLS.json ?? JsonControl;\nCONTROLS.json = function JsonOrSlotControl(props: ControlProps) {\n return createElement(props.field.componentSlot ? ComponentSlotControl : Json, props);\n};\n"],"mappings":";;;;;;;;;AAUA,IAAM,OAAO,SAAS,QAAQ;AAC9B,SAAS,OAAO,SAAS,kBAAkB,OAAqB;AAC9D,QAAO,cAAc,MAAM,MAAM,gBAAgB,uBAAuB,MAAM,MAAM"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
//#region src/kit/controls/slot-services.ts
|
|
2
|
-
var isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
3
|
-
var isItem = (v) => isObj(v) && typeof v.componentId === "string" && v.componentId !== "";
|
|
4
|
-
/**
|
|
5
|
-
* A stored slot value as its instances (`slotItems`, the one reading of a slot value): a list is its items, a single
|
|
6
|
-
* `{ componentId }` is a list of one, a detached `{ componentId: "" }` is none. A non-empty list with no instance and no
|
|
7
|
-
* V2 child is the component's own child blocks (the inherited value), not something to drop.
|
|
8
|
-
*/
|
|
9
|
-
function readSlot(value) {
|
|
10
|
-
if (Array.isArray(value)) {
|
|
11
|
-
const items = value.filter(isItem);
|
|
12
|
-
const rest = value.filter((v) => !isItem(v));
|
|
13
|
-
const v2 = rest.filter((v) => isObj(v) && v.componentId === void 0 && ("_type" in v || "_key" in v));
|
|
14
|
-
const inherited = items.length === 0 && v2.length === 0 && rest.length > 0;
|
|
15
|
-
return {
|
|
16
|
-
items,
|
|
17
|
-
inherited,
|
|
18
|
-
unreadable: inherited ? 0 : rest.length
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
return {
|
|
22
|
-
items: isItem(value) ? [value] : [],
|
|
23
|
-
inherited: false,
|
|
24
|
-
unreadable: 0
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
/** Write a multiple slot: the items as they are (no `_key` the engine's list helpers add, which prod never stores). */
|
|
28
|
-
function slotList(items) {
|
|
29
|
-
return items.filter(isItem).map((it) => {
|
|
30
|
-
if (!("_key" in it)) return it;
|
|
31
|
-
const { _key, ...rest } = it;
|
|
32
|
-
return rest;
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
//#endregion
|
|
36
|
-
export { readSlot, slotList };
|
|
37
|
-
|
|
38
|
-
//# sourceMappingURL=slot-services.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"slot-services.js","names":[],"sources":["../../src/kit/controls/slot-services.ts"],"sourcesContent":["/**\n * Component slots (lane L3): the services the slot control reads and the reading of a stored slot value, declared as\n * augmentations so context.tsx and schema/types.ts stay untouched by this lane.\n *\n * A prod `slot` prop holds component instances, not V2 blocks:\n * single `{ componentId, overrides? }` (a detached slot is `{ componentId: \"\" }`)\n * multiple `[{ componentId, overrides?, style?, window? }, …]`; a single object reads as a list of one\n * The host marks such a field with `componentSlot` (the dock reads it off the prop's config) and the slot control draws\n * it; the value is written back in exactly that shape, each item spread with the keys this control does not show.\n *\n * useSlotCatalog → a React HOOK: the components this slot may take, with the SERVER's insertability verdicts\n * (GET /components/section-catalog) already turned into words, and the name of any component id\n * SlotChild → the host's editor for one child's own props (its overrides), drawn under the child's row\n */\nimport type { ComponentType } from \"react\";\n\n/** One component the slot picker lists. `insertable: false` always carries `reason`, a sentence the picker shows. */\nexport interface KitSlotEntry {\n id: string;\n title: string;\n /** the section family (\"Hero\"), shown as the picker's group */\n category?: string | null;\n description?: string | null;\n icon?: string;\n insertable: boolean;\n reason?: string;\n}\n\nexport interface KitSlotCatalog {\n entries: KitSlotEntry[];\n loading?: boolean;\n /** a whole sentence naming what failed (\"Sections couldn't be loaded: …\") */\n error?: string;\n /** a sentence under the picker's list naming what can never fill a slot and why (built-in sections) */\n note?: string;\n /** a component id's name; `missing` when the project has no such component (deleted, or another project's) */\n nameOf: (componentId: string) => { title: string; missing?: boolean } | undefined;\n}\n\nexport interface KitSlotChildProps {\n componentId: string;\n title: string;\n overrides: Record<string, unknown>;\n onChange: (next: Record<string, unknown>) => void;\n readOnly?: boolean;\n /** how many slots deep this child sits (1 for a top-level slot's child) */\n depth: number;\n}\n\n/** The slot's own rules, mirrored from the prop's config so a save is not refused (BE slot-values.ts). */\nexport interface KitComponentSlot {\n multiple: boolean;\n /** config.componentIds: the only components it takes (empty or absent: any) */\n componentIds?: string[];\n /** config.minItems (multiple only) */\n min: number;\n /** config.maxItems, defaulted to 12 and capped at 50 (multiple only; a single slot holds one) */\n max: number;\n}\n\ndeclare module \"../context\" {\n interface KitServices {\n useSlotCatalog?: (req: { componentIds?: string[] }) => KitSlotCatalog;\n SlotChild?: ComponentType<KitSlotChildProps>;\n }\n}\n\ndeclare module \"../schema/types\" {\n interface FieldSchema {\n /** a component slot (prod `slot` prop): drawn by the slot control instead of the json editor */\n componentSlot?: KitComponentSlot;\n }\n}\n\n/** SLOT_MAX_ITEMS / SLOT_ITEMS_CAP (@bettercms-ai/types): the default and the hard cap of a multiple slot. */\nexport const SLOT_MAX_ITEMS = 12;\nexport const SLOT_ITEMS_CAP = 50;\n/** The renderers' nesting cap: past it a tree renders as nothing, so the editor refuses to nest further. */\nexport const SLOT_DEPTH_MAX = 10;\n\nexport interface KitSlotItem {\n componentId: string;\n overrides?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface SlotReading {\n items: KitSlotItem[];\n /** the value is the component's own content (its child blocks), shown until an item is added */\n inherited: boolean;\n /** entries this control can't read and would drop on a write (V2 block children, malformed rows) */\n unreadable: number;\n}\n\nconst isObj = (v: unknown): v is Record<string, unknown> => !!v && typeof v === \"object\" && !Array.isArray(v);\nconst isItem = (v: unknown): v is KitSlotItem => isObj(v) && typeof v.componentId === \"string\" && v.componentId !== \"\";\n\n/**\n * A stored slot value as its instances (`slotItems`, the one reading of a slot value): a list is its items, a single\n * `{ componentId }` is a list of one, a detached `{ componentId: \"\" }` is none. A non-empty list with no instance and no\n * V2 child is the component's own child blocks (the inherited value), not something to drop.\n */\nexport function readSlot(value: unknown): SlotReading {\n if (Array.isArray(value)) {\n const items = value.filter(isItem);\n const rest = value.filter((v) => !isItem(v));\n const v2 = rest.filter((v) => isObj(v) && v.componentId === undefined && (\"_type\" in v || \"_key\" in v));\n const inherited = items.length === 0 && v2.length === 0 && rest.length > 0;\n return { items, inherited, unreadable: inherited ? 0 : rest.length };\n }\n return { items: isItem(value) ? [value] : [], inherited: false, unreadable: 0 };\n}\n\n/** Write a multiple slot: the items as they are (no `_key` the engine's list helpers add, which prod never stores). */\nexport function slotList(items: unknown[]): KitSlotItem[] {\n return items.filter(isItem).map((it) => {\n if (!(\"_key\" in it)) return it;\n const { _key, ...rest } = it;\n void _key;\n return rest as KitSlotItem;\n });\n}\n"],"mappings":";AA8FA,IAAM,SAAS,MAA6C,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,EAAE;AAC7G,IAAM,UAAU,MAAiC,MAAM,EAAE,IAAI,OAAO,EAAE,gBAAgB,YAAY,EAAE,gBAAgB;;;;;;AAOpH,SAAgB,SAAS,OAA6B;AACpD,KAAI,MAAM,QAAQ,MAAM,EAAE;EACxB,MAAM,QAAQ,MAAM,OAAO,OAAO;EAClC,MAAM,OAAO,MAAM,QAAQ,MAAM,CAAC,OAAO,EAAE,CAAC;EAC5C,MAAM,KAAK,KAAK,QAAQ,MAAM,MAAM,EAAE,IAAI,EAAE,gBAAgB,KAAA,MAAc,WAAW,KAAK,UAAU,GAAG;EACvG,MAAM,YAAY,MAAM,WAAW,KAAK,GAAG,WAAW,KAAK,KAAK,SAAS;AACzE,SAAO;GAAE;GAAO;GAAW,YAAY,YAAY,IAAI,KAAK;GAAQ;;AAEtE,QAAO;EAAE,OAAO,OAAO,MAAM,GAAG,CAAC,MAAM,GAAG,EAAE;EAAE,WAAW;EAAO,YAAY;EAAG;;;AAIjF,SAAgB,SAAS,OAAiC;AACxD,QAAO,MAAM,OAAO,OAAO,CAAC,KAAK,OAAO;AACtC,MAAI,EAAE,UAAU,IAAK,QAAO;EAC5B,MAAM,EAAE,MAAM,GAAG,SAAS;AAE1B,SAAO;GACP"}
|
package/controls/slot.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"slot.js","names":[],"sources":["../../src/kit/controls/slot.tsx"],"sourcesContent":["/**\n * COMPONENT SLOT — a prop that holds component instances (prod `slot`), on the engine's slot surface (engine/slot.tsx,\n * V2 HEAD 9829bf1): the block rows (icon tile, name, ⋯ menu, drag to reorder) and the compact searchable picker.\n *\n * What differs from V2's block slot is where the rows come from and what they store:\n * - the picker lists the host's slot catalog (`useSlotCatalog`): the project's components with the SERVER's\n * insertability verdict for each; one that can't go here stays in the list, disabled, with the reason under its name;\n * - a row opens in place and edits that child's own props through the host's `SlotChild`;\n * - the value is written in the stored shape (slot-services.ts): one `{ componentId, overrides? }`, or a list of them\n * for a multiple slot, every item spread back with the keys this control does not show (style, window).\n *\n * Refusals are said in words, never by an inert control: no catalog service, an unreadable stored value, the nesting cap.\n */\nimport * as React from \"react\";\nimport { IconPlus, IconSearch } from \"@tabler/icons-react\";\nimport { useKitServices } from \"../context\";\nimport { KitIcon } from \"../lib/icons\";\nimport { cn } from \"../lib/cn\";\nimport { Button } from \"../ui/button\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../ui/overlay\";\nimport { RowList, useListOps, type RowModel } from \"../engine/array\";\nimport type { FieldSchema } from \"../schema/types\";\nimport type { ControlProps } from \"../types\";\nimport { readSlot, slotList, SLOT_DEPTH_MAX, type KitComponentSlot, type KitSlotEntry, type KitSlotItem } from \"./slot-services\";\n\n/** How many slots deep the control sits: the host's SlotChild editor sits inside a provider one level down. */\nexport const SlotDepthContext = React.createContext(0);\n\nconst count = (n: number) => `${n} component${n === 1 ? \"\" : \"s\"}`;\nconst NO_CATALOG = { entries: [] as KitSlotEntry[], nameOf: () => undefined };\n\n/** A note in words, labelable and focusable (the field label's `for` lands on it). */\nfunction SlotNote({ id, children, tone = \"muted\" }: { id?: string; children: React.ReactNode; tone?: \"muted\" | \"warning\" }) {\n return (\n <output\n id={id}\n role=\"note\"\n tabIndex={id ? 0 : undefined}\n className={cn(\n \"block rounded-kit-sm text-kit-xs outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-kit-focus-ring focus-visible:[outline-style:solid] [html[data-input-modality=pointer]_&]:focus-visible:outline-none\",\n tone === \"warning\" ? \"text-kit-warning-fg\" : \"text-kit-fg-3\",\n )}\n >\n {children}\n </output>\n );\n}\n\nexport function ComponentSlotControl({ field, value, onChange, readOnly, id, path }: ControlProps) {\n const slot: KitComponentSlot = field.componentSlot ?? { multiple: false, min: 0, max: 1 };\n const depth = React.useContext(SlotDepthContext);\n const { useSlotCatalog, SlotChild } = useKitServices();\n // a hook service: one identity for the life of the form, so it is called on every render or never\n const catalog = useSlotCatalog ? useSlotCatalog({ componentIds: slot.componentIds }) : null; // eslint-disable-line react-hooks/rules-of-hooks\n const read = readSlot(value);\n const items = read.items;\n const max = slot.multiple ? slot.max : 1;\n const [openId, setOpenId] = React.useState<string | null>(null);\n const nameOf = (componentId: string) => (catalog ?? NO_CATALOG).nameOf(componentId) ?? { title: catalog?.loading ? \"Loading…\" : componentId };\n const locked = readOnly || read.unreadable > 0;\n\n /* writes: the stored shape, never a `_key` (useListOps' duplicate adds one) */\n const write = (next: unknown[]) => {\n setOpenId(null);\n if (slot.multiple) return onChange(slotList(next));\n const [first] = slotList(next);\n onChange(first ?? { componentId: \"\" });\n };\n const opsField: FieldSchema = { ...field, validation: { ...field.validation, min: slot.multiple ? slot.min : 0, max } };\n const ops = useListOps(opsField, path, items, write);\n if (depth >= SLOT_DEPTH_MAX) return <SlotNote id={id}>Nested component limit reached. A slot this deep would render as nothing, so it can’t hold more components here.</SlotNote>;\n const pick = (componentId: string) => {\n if (!slot.multiple) {\n const cur = items[0];\n // a different component's overrides are keyed by the old component's props: dropped, never half-applied\n onChange(cur && cur.componentId === componentId ? cur : { componentId });\n setOpenId(null);\n return;\n }\n if (items.length >= max) return;\n onChange([...items, { componentId }]);\n setOpenId(`i${items.length}`);\n };\n const setOverrides = (index: number, overrides: Record<string, unknown>) => {\n const next = items.map((it, i) => (i === index ? { ...it, overrides } : it));\n if (slot.multiple) onChange(next);\n else onChange({ componentId: next[0].componentId, overrides });\n };\n\n const rows: RowModel[] = items.map((it, i) => {\n const name = nameOf(it.componentId);\n const entry = catalog?.entries.find((e) => e.id === it.componentId);\n return {\n id: `i${i}`,\n index: i,\n item: it,\n path: [...path, i],\n preview: { title: name.missing ? \"Missing component\" : name.title, icon: entry?.icon ?? \"box\", empty: false },\n extra: name.missing ? \"Deleted, or not in this project. Replace or remove it.\" : (entry?.category ?? `Component ${i + 1} of ${items.length}`),\n };\n });\n\n const picker = catalog ? (\n <SlotPicker\n entries={catalog.entries}\n loading={catalog.loading}\n error={catalog.error}\n note={catalog.note}\n current={slot.multiple ? undefined : items[0]?.componentId}\n label={slot.multiple ? \"Add component\" : items.length ? \"Replace component\" : \"Choose a component\"}\n disabled={locked || (slot.multiple && items.length >= max)}\n onPick={pick}\n />\n ) : null;\n\n return (\n <div className=\"flex min-w-0 flex-col gap-1.5\" data-slot=\"kit-component-slot\">\n {read.unreadable > 0 ? (\n <SlotNote tone=\"warning\">\n {read.unreadable === 1 ? \"One child here isn't a component instance\" : `${read.unreadable} children here aren't component instances`} (blocks written by another editor). This editor\n would drop {read.unreadable === 1 ? \"it\" : \"them\"} on save, so the slot is shown read-only and its value is kept.\n </SlotNote>\n ) : null}\n {read.inherited && items.length === 0 ? <SlotNote>Shows the component’s own content until a component is added here.</SlotNote> : null}\n <div id={id} tabIndex={-1} className=\"min-w-0 outline-none\">\n <RowList\n field={opsField}\n rows={rows}\n readOnly={locked}\n layout=\"list\"\n mode=\"inline\"\n openId={openId}\n onOpen={(r) => setOpenId(openId === r.id ? null : r.id)}\n onCloseInline={() => setOpenId(null)}\n ops={ops}\n renderInline={(r) => {\n const it = r.item as KitSlotItem;\n const title = r.preview.title;\n if (nameOf(it.componentId).missing) return <SlotNote>This component no longer exists, so its props can’t be edited. Replace it or remove it.</SlotNote>;\n if (!SlotChild) return <SlotNote>This editor can’t open {title}’s own props.</SlotNote>;\n return (\n <SlotDepthContext.Provider value={depth + 1}>\n <SlotChild\n componentId={it.componentId}\n title={title}\n overrides={it.overrides && typeof it.overrides === \"object\" ? it.overrides : {}}\n onChange={(o) => setOverrides(r.index, o)}\n readOnly={locked}\n depth={depth + 1}\n />\n </SlotDepthContext.Provider>\n );\n }}\n leading={(r) => (\n <span className=\"flex size-7 shrink-0 items-center justify-center rounded-kit-md border border-kit-line bg-kit-control-bg text-kit-fg-2 shadow-kit-xs\">\n <KitIcon name={r.preview.icon} className=\"size-4\" />\n </span>\n )}\n emptyLabel={slot.multiple ? \"No components yet. Add one to start composing.\" : \"No component yet. Choose one to fill this slot.\"}\n addButton={picker ?? <SlotNote>No component library is connected to this editor, so {field.title} can’t be changed here.</SlotNote>}\n />\n </div>\n {slot.multiple ? (\n <span className=\"text-kit-xs text-kit-fg-3\">\n {items.length >= max ? `This slot holds at most ${count(max)}.` : slot.min > 0 ? `Between ${slot.min} and ${count(max)}.` : `Up to ${count(max)}.`}\n {slot.min > 0 && items.length > 0 && items.length <= slot.min ? ` It needs at least ${slot.min}, so none can be removed.` : \"\"}\n </span>\n ) : null}\n </div>\n );\n}\n\n/**\n * The compact block picker (engine/slot.tsx BlockPicker), over the slot catalog: grouped by family, searchable, ↵ adds.\n * A component the server says can't go here is listed disabled with its reason in place of the description.\n */\nexport function SlotPicker({\n entries,\n loading,\n error,\n note,\n current,\n label,\n disabled,\n onPick,\n}: {\n entries: KitSlotEntry[];\n loading?: boolean;\n error?: string;\n note?: string;\n current?: string;\n label: string;\n disabled?: boolean;\n onPick: (componentId: string) => void;\n}) {\n const [open, setOpen] = React.useState(false);\n const [q, setQ] = React.useState(\"\");\n const [active, setActive] = React.useState(0);\n const listId = React.useId();\n const list = entries.filter((b) => !q || `${b.title} ${b.category ?? \"\"} ${b.description ?? \"\"}`.toLowerCase().includes(q.toLowerCase()));\n const cats = Array.from(new Set(list.map((b) => b.category || \"Components\")));\n const flat = cats.flatMap((c) => list.filter((b) => (b.category || \"Components\") === c));\n const choose = (b: KitSlotEntry | undefined) => {\n if (!b || !b.insertable) return;\n onPick(b.id);\n setOpen(false);\n setQ(\"\");\n };\n const optionId = (i: number) => `${listId}-${i}`;\n return (\n <Popover\n open={open}\n onOpenChange={(o) => {\n setOpen(o);\n setQ(\"\");\n setActive(0);\n }}\n >\n <PopoverTrigger render={<Button size=\"sm\" variant=\"ghost\" className=\"text-kit-fg-2\" leftIcon={<IconPlus stroke={1.5} />} disabled={disabled} />}>{label}</PopoverTrigger>\n <PopoverContent className=\"w-[300px] p-0\" align=\"start\">\n <label className=\"flex h-10 items-center gap-2 border-b border-kit-line px-3 text-kit-fg-3\">\n <IconSearch className=\"size-4 shrink-0\" stroke={1.5} aria-hidden />\n <input\n autoFocus\n value={q}\n onChange={(e) => {\n setQ(e.target.value);\n setActive(0);\n }}\n onKeyDown={(e) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActive((a) => (a + 1) % Math.max(1, flat.length));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive((a) => (a - 1 + flat.length) % Math.max(1, flat.length));\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n choose(flat[active]);\n }\n }}\n placeholder=\"Search components\"\n aria-label=\"Search components\"\n role=\"combobox\"\n aria-expanded\n aria-controls={listId}\n aria-activedescendant={flat.length ? optionId(Math.min(active, flat.length - 1)) : undefined}\n className=\"h-full min-w-0 flex-1 bg-transparent text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3\"\n />\n </label>\n <div id={listId} className=\"max-h-80 overflow-y-auto p-1\" role=\"listbox\" aria-label=\"Components\" aria-busy={loading || undefined}>\n {loading && entries.length === 0 ? (\n <p role=\"status\" className=\"px-3 py-6 text-center text-kit-sm text-kit-fg-3\">\n Loading components…\n </p>\n ) : null}\n {!loading && !error && flat.length === 0 ? <p className=\"px-3 py-6 text-center text-kit-sm text-kit-fg-3\">{entries.length ? \"No components match\" : \"This project has no components that can go here yet.\"}</p> : null}\n {error ? (\n <p role=\"alert\" className=\"px-3 py-3 text-kit-xs text-kit-danger-fg\">\n {error}\n </p>\n ) : null}\n {cats.map((c) => (\n <div key={c} role=\"group\" aria-label={c} className=\"pb-1\">\n <div aria-hidden className=\"px-2 pb-1 pt-1.5 text-kit-2xs font-medium text-kit-fg-3\">\n {c}\n </div>\n {list\n .filter((b) => (b.category || \"Components\") === c)\n .map((b) => {\n const i = flat.indexOf(b);\n return (\n <div\n key={b.id}\n id={optionId(i)}\n role=\"option\"\n aria-selected={b.id === current}\n aria-disabled={!b.insertable || undefined}\n onMouseEnter={() => setActive(i)}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => choose(b)}\n className={cn(\"flex w-full items-center gap-2.5 rounded-kit-md p-1.5 text-left\", b.insertable ? \"cursor-pointer\" : \"cursor-not-allowed\", i === active && \"bg-kit-hover\")}\n >\n <span className={cn(\"flex size-8 shrink-0 items-center justify-center rounded-kit-md border border-kit-line bg-kit-surface text-kit-fg-2 shadow-kit-xs\", !b.insertable && \"opacity-50\")}>\n <KitIcon name={b.icon ?? \"box\"} className=\"size-4\" />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className={cn(\"block truncate text-kit-sm\", b.insertable ? \"text-kit-fg\" : \"text-kit-fg-3\")}>{b.title}</span>\n {!b.insertable && b.reason ? (\n <span className=\"block text-kit-xs text-kit-fg-3\">{b.reason}</span>\n ) : b.description ? (\n <span className=\"block truncate text-kit-xs text-kit-fg-3\">{b.description}</span>\n ) : null}\n </span>\n </div>\n );\n })}\n </div>\n ))}\n </div>\n {note ? <p className=\"border-t border-kit-line px-3 py-2 text-kit-xs text-kit-fg-3\">{note}</p> : null}\n <div data-hint=\"shortcuts\" className=\"border-t border-kit-line px-3 py-1.5 text-kit-2xs text-kit-fg-3\">\n ↵ add · type to search\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/kit/controls/table/index.ts"],"sourcesContent":["/**\n * Data table: registers the control and its label-row action (one line each, so lanes merge cleanly).\n * Imported for its side effect by the kit entry; import the parts themselves by path.\n */\nimport { ACTIONS, CONTROLS } from \"../../engine/kit-field\";\nimport { TableControl, TableFullScreenAction } from \"./table\";\n\nCONTROLS.table = TableControl;\nACTIONS.table = TableFullScreenAction;\n"],"mappings":";;;;;;;AAOA,SAAS,QAAQ;AACjB,QAAQ,QAAQ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prod.js","names":[],"sources":["../../../src/kit/controls/table/prod.ts"],"sourcesContent":["/**\n * The production side of a data table, for the schema adapter (adapters/schema.ts) to call when it reads one:\n *\n * - a component `table` prop with `config.mode: \"data\"` (BE @bettercms-ai/types component.ts; prop-fields.ts\n * isDataTable) holds ONE TableValue, with the table field's options beside `mode` in its `config`;\n * - a content-model `table` field (BE content-model.ts) holds the same value, its options in `config`.\n *\n * A `table` prop with no mode (or `\"rows\"` / `\"types\"`) is the older array of rows and is NOT this value.\n * Only the option keys the backend defines are read, each only when it has the type the backend reads, so a stray key\n * never turns into a setting the backend would not honour.\n */\nimport { TABLE_COLUMN_TYPES, type TableColumnType, type TableFieldOptions, type TableJsonLdType, type TableResponsive, type TableSettingsOptions } from \"../../schema/table\";\n\nconst isObj = (v: unknown): v is Record<string, unknown> => !!v && typeof v === \"object\" && !Array.isArray(v);\nconst COLUMN_TYPES = new Set<string>(TABLE_COLUMN_TYPES.map((t) => t.value));\nconst PHONES = new Set<string>([\"scroll\", \"stack\", \"cards\"]);\nconst JSONLD = new Set<string>([\"ItemList\", \"Dataset\", \"Offers\"]);\nconst SETTING_FLAGS = [\"headers\", \"totals\", \"highlight\", \"sticky\", \"sort\", \"search\"] as const;\n\n/** BE isDataTable: a `table` prop or sub-field holding one TableValue. */\nexport const isDataTableProp = (p: { type?: unknown; config?: unknown }): boolean => p.type === \"table\" && isObj(p.config) && p.config.mode === \"data\";\n\n/** The field options a data table's `config` carries, as the kit's `FieldSchema.table`. */\nexport function tableOptionsFromConfig(config: unknown): TableFieldOptions {\n if (!isObj(config)) return {};\n const o: TableFieldOptions = {};\n const strs = (v: unknown, ok: Set<string>) => (Array.isArray(v) ? v.filter((x): x is string => typeof x === \"string\" && ok.has(x)) : undefined);\n const columnTypes = strs(config.columnTypes, COLUMN_TYPES);\n if (columnTypes) o.columnTypes = columnTypes as TableColumnType[];\n for (const k of [\"lockColumns\", \"requireCaption\", \"allowGroups\", \"allowFootnotes\", \"allowNote\"] as const) if (typeof config[k] === \"boolean\") o[k] = config[k] as boolean;\n for (const k of [\"minRows\", \"maxRows\", \"maxColumns\"] as const) {\n const n = config[k];\n if (typeof n === \"number\" && Number.isInteger(n) && n >= 0) o[k] = n;\n }\n if (isObj(config.settings)) {\n const s: TableSettingsOptions = {};\n for (const k of SETTING_FLAGS) if (typeof config.settings[k] === \"boolean\") s[k] = config.settings[k] as boolean;\n const phones = strs(config.settings.phones, PHONES);\n if (phones) s.phones = phones as TableResponsive[];\n o.settings = s;\n }\n const jsonLd = strs(config.jsonLd, JSONLD);\n if (jsonLd) o.jsonLd = jsonLd as TableJsonLdType[];\n return o;\n}\n\n/** The `config` a data-table prop is written with (the inverse of tableOptionsFromConfig). */\nexport function tableConfigFromOptions(o: TableFieldOptions | undefined): Record<string, unknown> {\n return { mode: \"data\", ...(o ? JSON.parse(JSON.stringify(o)) : {}) };\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAM,SAAS,MAA6C,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,EAAE;AAC7G,IAAM,eAAe,IAAI,IAAY,mBAAmB,KAAK,MAAM,EAAE,MAAM,CAAC;AAC5E,IAAM,SAAS,IAAI,IAAY;CAAC;CAAU;CAAS;CAAQ,CAAC;AAC5D,IAAM,SAAS,IAAI,IAAY;CAAC;CAAY;CAAW;CAAS,CAAC;AACjE,IAAM,gBAAgB;CAAC;CAAW;CAAU;CAAa;CAAU;CAAQ;CAAS;;AAGpF,IAAa,mBAAmB,MAAqD,EAAE,SAAS,WAAW,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO,SAAS;;AAGhJ,SAAgB,uBAAuB,QAAoC;AACzE,KAAI,CAAC,MAAM,OAAO,CAAE,QAAO,EAAE;CAC7B,MAAM,IAAuB,EAAE;CAC/B,MAAM,QAAQ,GAAY,OAAqB,MAAM,QAAQ,EAAE,GAAG,EAAE,QAAQ,MAAmB,OAAO,MAAM,YAAY,GAAG,IAAI,EAAE,CAAC,GAAG,KAAA;CACrI,MAAM,cAAc,KAAK,OAAO,aAAa,aAAa;AAC1D,KAAI,YAAa,GAAE,cAAc;AACjC,MAAK,MAAM,KAAK;EAAC;EAAe;EAAkB;EAAe;EAAkB;EAAY,CAAW,KAAI,OAAO,OAAO,OAAO,UAAW,GAAE,KAAK,OAAO;AAC5J,MAAK,MAAM,KAAK;EAAC;EAAW;EAAW;EAAa,EAAW;EAC7D,MAAM,IAAI,OAAO;AACjB,MAAI,OAAO,MAAM,YAAY,OAAO,UAAU,EAAE,IAAI,KAAK,EAAG,GAAE,KAAK;;AAErE,KAAI,MAAM,OAAO,SAAS,EAAE;EAC1B,MAAM,IAA0B,EAAE;AAClC,OAAK,MAAM,KAAK,cAAe,KAAI,OAAO,OAAO,SAAS,OAAO,UAAW,GAAE,KAAK,OAAO,SAAS;EACnG,MAAM,SAAS,KAAK,OAAO,SAAS,QAAQ,OAAO;AACnD,MAAI,OAAQ,GAAE,SAAS;AACvB,IAAE,WAAW;;CAEf,MAAM,SAAS,KAAK,OAAO,QAAQ,OAAO;AAC1C,KAAI,OAAQ,GAAE,SAAS;AACvB,QAAO;;;AAIT,SAAgB,uBAAuB,GAA2D;AAChG,QAAO;EAAE,MAAM;EAAQ,GAAI,IAAI,KAAK,MAAM,KAAK,UAAU,EAAE,CAAC,GAAG,EAAE;EAAG"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"refs.js","names":[],"sources":["../../../src/kit/controls/table/refs.ts"],"sourcesContent":["/**\n * Reference cells: what a `reference` column's cell may point at, found through the HOST (the kit never fetches).\n *\n * A reference cell stores `{ ref, label?, href? }` (BE table-value.ts TableRef): the id of a page or an entry. Its column's\n * `refTo` narrows the targets (\"page\", and collections by content-model id or slug); with no `refTo` V2 offers pages. The\n * backend checks the id exists and is a kind `refTo` allows (`reference_target_not_allowed`), so the picker only lists\n * what the same rule accepts: the host answers through POST /content/reference-options with the configs\n * `tableRefConfigs(refTo)` names.\n *\n * Host contract (a KitServices key, provided by src/features/dock-v2 and the /style-guide/kit sandbox):\n *\n * tableRefSearch(req) → Promise<TableRefOption[]>\n *\n * Absent → the picker says, in words, that this view cannot search pages or entries (stored cells still show).\n */\nimport * as React from \"react\";\nimport { useKitServices } from \"../../context\";\nimport type { TableRef } from \"../../schema/table\";\n\nexport interface TableRefOption {\n /** page or entry id: what the cell stores as `ref` */\n id: string;\n title: string;\n /** \"Blog post · my-slug\", \"Page\" */\n subtitle?: string;\n /** the public path, stored as the cell's `href` so the published table links without a read */\n href?: string;\n}\nexport interface TableRefSearchRequest {\n /** the column's `refTo` (null = pages, as V2) */\n refTo: string[] | null;\n q: string;\n signal: AbortSignal;\n}\nexport type TableRefSearch = (req: TableRefSearchRequest) => Promise<TableRefOption[]>;\nexport interface TableKitServices {\n tableRefSearch?: TableRefSearch;\n}\ndeclare module \"../../context\" {\n interface KitServices {\n /** Search pages and entries for a table's reference cells (see above). Absent → the picker names why it can't. */\n tableRefSearch?: TableRefSearch;\n }\n}\n\n/**\n * The POST /content/reference-options `config` bodies one column's `refTo` needs (the host sends each and merges the\n * answers): pages through `targets: [\"page\"]`, each collection through `contentModelId`.\n */\nexport function tableRefConfigs(refTo: string[] | null | undefined): Record<string, unknown>[] {\n const to = refTo?.length ? refTo : [\"page\"];\n const out: Record<string, unknown>[] = [];\n if (to.includes(\"page\")) out.push({ targets: [\"page\"] });\n for (const id of to) if (id !== \"page\" && id) out.push({ contentModelId: id });\n return out;\n}\n\n/** The words a stored reference shows: what a read resolved onto it, its stored label, else its id. */\nexport function refLabel(r: TableRef & { resolved?: { title?: string } }): string {\n return r.resolved?.title || r.label || r.ref;\n}\n\nexport type RefSearchState =\n | { status: \"unavailable\" }\n | { status: \"loading\" }\n | { status: \"ready\"; options: TableRefOption[] }\n | { status: \"error\"; message: string };\n\n/** Search while `open`, 200ms after the last keystroke; a newer query aborts the older one. */\nexport function useRefSearch(open: boolean, refTo: string[] | null, q: string): RefSearchState {\n const search = useKitServices().tableRefSearch;\n const key = refTo?.join(\",\") ?? \"\";\n const ask = `${key}\\u0000${q.trim()}`;\n // the answer, tagged with the question it answers: a different question reads as loading until its own answer lands\n const [answer, setAnswer] = React.useState<{ ask: string; state: RefSearchState } | null>(null);\n React.useEffect(() => {\n if (!search || !open) return;\n const ctl = new AbortController();\n const t = window.setTimeout(() => {\n search({ refTo: key ? key.split(\",\") : null, q: q.trim(), signal: ctl.signal }).then(\n (options) => !ctl.signal.aborted && setAnswer({ ask, state: { status: \"ready\", options } }),\n (e: unknown) => !ctl.signal.aborted && setAnswer({ ask, state: { status: \"error\", message: e instanceof Error && e.message ? e.message : \"The search did not answer.\" } }),\n );\n }, 200);\n return () => {\n ctl.abort();\n window.clearTimeout(t);\n };\n }, [search, open, key, q, ask]);\n if (!search) return { status: \"unavailable\" };\n return answer?.ask === ask ? answer.state : { status: \"loading\" };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA0DA,SAAgB,SAAS,GAAyD;AAChF,QAAO,EAAE,UAAU,SAAS,EAAE,SAAS,EAAE;;;AAU3C,SAAgB,aAAa,MAAe,OAAwB,GAA2B;CAC7F,MAAM,SAAS,gBAAgB,CAAC;CAChC,MAAM,MAAM,OAAO,KAAK,IAAI,IAAI;CAChC,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,MAAM;CAEnC,MAAM,CAAC,QAAQ,aAAa,MAAM,SAAwD,KAAK;AAC/F,OAAM,gBAAgB;AACpB,MAAI,CAAC,UAAU,CAAC,KAAM;EACtB,MAAM,MAAM,IAAI,iBAAiB;EACjC,MAAM,IAAI,OAAO,iBAAiB;AAChC,UAAO;IAAE,OAAO,MAAM,IAAI,MAAM,IAAI,GAAG;IAAM,GAAG,EAAE,MAAM;IAAE,QAAQ,IAAI;IAAQ,CAAC,CAAC,MAC7E,YAAY,CAAC,IAAI,OAAO,WAAW,UAAU;IAAE;IAAK,OAAO;KAAE,QAAQ;KAAS;KAAS;IAAE,CAAC,GAC1F,MAAe,CAAC,IAAI,OAAO,WAAW,UAAU;IAAE;IAAK,OAAO;KAAE,QAAQ;KAAS,SAAS,aAAa,SAAS,EAAE,UAAU,EAAE,UAAU;KAA8B;IAAE,CAAC,CAC3K;KACA,IAAI;AACP,eAAa;AACX,OAAI,OAAO;AACX,UAAO,aAAa,EAAE;;IAEvB;EAAC;EAAQ;EAAM;EAAK;EAAG;EAAI,CAAC;AAC/B,KAAI,CAAC,OAAQ,QAAO,EAAE,QAAQ,eAAe;AAC7C,QAAO,QAAQ,QAAQ,MAAM,OAAO,QAAQ,EAAE,QAAQ,WAAW"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stored.js","names":[],"sources":["../../../src/kit/controls/table/stored.ts"],"sourcesContent":["/**\n * The table value as the backend stores it (BE `packages/types/src/table-value.ts`, a `table` field or a `table` prop with\n * `config.mode: \"data\"`). The editor works on `normalizeTable(value)`, which fills keys the stored value may not have\n * (`id`, empty `columnGroups` / `rowGroups` / `footnotes`). Writing those back would change a value nobody edited, so\n * `storedTable` hands back exactly what the person changed:\n *\n * - keys normalize invented (an `id`, an empty list the stored value did not carry) are dropped again;\n * - `undefined` keys (a switch turned off: `highlight`, `sortable`, `notes`…) are removed, as JSON would remove them;\n * - a reference cell's `resolved` (what a read writes onto it) is never written back (BE normalizeTableValue drops it too).\n *\n * The backend refuses any key it does not know (`table_value_invalid`), so nothing else is added here.\n */\nimport { TABLE_COLUMN_TYPES, isTableValue, type TableValue } from \"../../schema/table\";\n\nconst LISTS = [\"columnGroups\", \"rowGroups\", \"footnotes\"] as const;\n\n/** A JSON copy without `undefined` keys (what the save would send), and without a reference cell's read-only `resolved`. */\nfunction plain<T>(v: T): T {\n return JSON.parse(JSON.stringify(v, (k, x) => (k === \"resolved\" ? undefined : x))) as T;\n}\n\n/** `next` as the backend stores it, given the value it was loaded from (`prev`; undefined for a new table). */\nexport function storedTable(next: TableValue, prev: unknown): TableValue {\n const out = plain(next) as TableValue & Record<string, unknown>;\n const was = isTableValue(prev) ? (prev as unknown as Record<string, unknown>) : null;\n if (was) {\n if (!(\"id\" in was) && out.id !== undefined) delete out.id;\n for (const k of LISTS) if (!(k in was) && Array.isArray(out[k]) && (out[k] as unknown[]).length === 0) delete out[k];\n // normalize reads a column type it does not know (or none) as \"text\": unless the person picked another type, the\n // stored one is written back as it was\n const prevCols = new Map((Array.isArray(was.columns) ? was.columns : []).filter((c): c is Record<string, unknown> => !!c && typeof c === \"object\").map((c) => [c._key, c] as const));\n for (const col of out.columns as unknown as Record<string, unknown>[]) {\n const p = prevCols.get(col._key);\n if (!p || col.type !== \"text\" || TABLE_COLUMN_TYPES.some((t) => t.value === p.type)) continue;\n if (p.type === undefined) delete col.type;\n else col.type = p.type;\n }\n } else {\n for (const k of LISTS) if (Array.isArray(out[k]) && (out[k] as unknown[]).length === 0) delete out[k];\n }\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,IAAM,QAAQ;CAAC;CAAgB;CAAa;CAAY;;AAGxD,SAAS,MAAS,GAAS;AACzB,QAAO,KAAK,MAAM,KAAK,UAAU,IAAI,GAAG,MAAO,MAAM,aAAa,KAAA,IAAY,EAAG,CAAC;;;AAIpF,SAAgB,YAAY,MAAkB,MAA2B;CACvE,MAAM,MAAM,MAAM,KAAK;CACvB,MAAM,MAAM,aAAa,KAAK,GAAI,OAA8C;AAChF,KAAI,KAAK;AACP,MAAI,EAAE,QAAQ,QAAQ,IAAI,OAAO,KAAA,EAAW,QAAO,IAAI;AACvD,OAAK,MAAM,KAAK,MAAO,KAAI,EAAE,KAAK,QAAQ,MAAM,QAAQ,IAAI,GAAG,IAAK,IAAI,GAAiB,WAAW,EAAG,QAAO,IAAI;EAGlH,MAAM,WAAW,IAAI,KAAK,MAAM,QAAQ,IAAI,QAAQ,GAAG,IAAI,UAAU,EAAE,EAAE,QAAQ,MAAoC,CAAC,CAAC,KAAK,OAAO,MAAM,SAAS,CAAC,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,CAAU,CAAC;AACpL,OAAK,MAAM,OAAO,IAAI,SAAiD;GACrE,MAAM,IAAI,SAAS,IAAI,IAAI,KAAK;AAChC,OAAI,CAAC,KAAK,IAAI,SAAS,UAAU,mBAAmB,MAAM,MAAM,EAAE,UAAU,EAAE,KAAK,CAAE;AACrF,OAAI,EAAE,SAAS,KAAA,EAAW,QAAO,IAAI;OAChC,KAAI,OAAO,EAAE;;OAGpB,MAAK,MAAM,KAAK,MAAO,KAAI,MAAM,QAAQ,IAAI,GAAG,IAAK,IAAI,GAAiB,WAAW,EAAG,QAAO,IAAI;AAErG,QAAO"}
|