@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
package/context.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../src/kit/context.tsx"],"sourcesContent":["/**\n * Kit runtime contexts (V2 HEAD 9829bf1 kit/context.tsx).\n *\n * - KitServices — pluggable app services (media library picker, upload sink, toast, AI rewrite, comment threads).\n * Hosts register theirs once (`registerKitServices`) or provide them (`KitServicesProvider`); the kit\n * never imports a feature. A service that is absent hides the surface that needs it.\n * - KitEnv — the editing environment a control renders in: variant (panel | document), doc identity, site\n * palette, permissions, presence, comments. Has safe defaults so a control can render alone.\n * - FormApi — present only inside <SchemaForm>: value, writes, navigation, issues, baselines, history.\n */\nimport * as React from \"react\";\nimport type { Cap } from \"./schema/sources\";\nimport type { FieldAccess, FieldPath, FieldSchema, TypeSchema } from \"./schema/types\";\nimport type { KitIssue } from \"./lib/validate\";\nimport type { ControlProps } from \"./types\";\nimport type { LinkTarget } from \"./controls/link\";\n\n/* ── Services ─────────────────────────────────────────────────────────── */\n/** The media asset a picker hands back (the host's media library row, narrowed to what the kit reads). */\nexport interface KitMediaAsset {\n id: string;\n url: string;\n name?: string;\n alt?: string;\n kind?: \"image\" | \"video\" | \"file\" | \"svg\";\n width?: number;\n height?: number;\n size?: number;\n}\nexport interface KitMediaPickerProps {\n open: boolean;\n onOpenChange: (v: boolean) => void;\n onPick: (assets: KitMediaAsset[]) => void;\n multiple?: boolean;\n accept?: (\"image\" | \"video\" | \"file\" | \"svg\")[];\n}\nexport interface KitToastOptions {\n /** the second line under the message (V2 sonner `description`) */\n description?: string;\n action?: { label: string; onClick: () => void };\n duration?: number;\n icon?: React.ReactNode;\n}\n/** The host's toaster. The kit has no toast dependency (V2 re-exported sonner's). */\nexport interface KitToast {\n (message: string, opts?: KitToastOptions): void;\n success: (message: string, opts?: KitToastOptions) => void;\n}\n/** Rewrite with AI presets (V2 lib/ai.ts). The host's `aiRewrite` service produces the text. */\nexport type AiPreset = \"improve\" | \"shorter\" | \"longer\" | \"simplify\" | \"grammar\" | \"translate\";\nexport const AI_PRESETS: { id: AiPreset; label: string }[] = [\n { id: \"improve\", label: \"Improve\" },\n { id: \"shorter\", label: \"Shorter\" },\n { id: \"longer\", label: \"Longer\" },\n { id: \"simplify\", label: \"Simplify\" },\n { id: \"grammar\", label: \"Fix spelling & grammar\" },\n { id: \"translate\", label: \"Translate to Spanish\" },\n];\n/** The in-place field comments popover (V2 FieldThreads over the comments store), drawn by the host. */\nexport interface KitFieldCommentsProps {\n docId: string;\n /** pathKey of the field (\"items.1.answer\") */\n fieldKey: string;\n label: string;\n /** the field's text, first 80 characters */\n quote?: string;\n onClose: () => void;\n /** \"Open in panel\": set when the host has a comments panel (`env.onComment`) */\n onOpenPanel?: () => void;\n}\n/* The popover around FieldComments keeps itself open on Escape while focus is on an element marked `data-esc-owner`\n (V2 guardEscape): the composer marks its input so Escape clears or blurs the draft instead of losing it. */\nexport interface KitServices {\n /** The media library picker. */\n MediaPicker?: React.ComponentType<KitMediaPickerProps>;\n /** Called after an upload so the host can file the assets into its media library. */\n onUploaded?: (assets: KitMediaAsset[]) => void;\n /**\n * Image placements keep their edits BESIDE the url (`${name}Alt` · `${name}Focal` · `${name}Crop` ·\n * `${name}Decorative`) instead of turning the value into an object — the Visuals block model.\n */\n imageSiblings?: boolean;\n /** Real metadata for an image url (the host's media library), so captions never show placeholders. */\n resolveImage?: (url: string) => { name?: string; width?: number; height?: number; size?: number } | undefined;\n /** The host's full image editor (crop, rotate, focal, alt…), opened in place. */\n editImage?: (req: { docId: string; path: FieldPath; title: string }) => void;\n /** The project's forms for `reference: { to: [\"form\"] }` (the host's Forms store). */\n forms?: () => { id: string; title: string; subtitle: string }[];\n /** Toasts for Copy / Paste / Reset / AI (each with Undo). Absent → the action still runs, silently. */\n toast?: KitToast;\n /** Rewrite with AI. Absent → the ⋯ menu offers no rewrite. `attempt` counts \"Try again\" presses. */\n aiRewrite?: (text: string, preset: AiPreset, attempt: number) => string | Promise<string>;\n /** In-place field comments. Absent and no `env.onComment` → the field shows no add-comment control. */\n FieldComments?: React.ComponentType<KitFieldCommentsProps>;\n /**\n * A React hook: open (unresolved) threads on one field, read from the same store FieldComments draws (V2 counted\n * `useBlockThreads(docId, key)`). Used while the host has no `env.onComment`; absent → SchemaForm `comments` counts.\n */\n useFieldCommentCount?: (docId: string, fieldKey: string) => number;\n /**\n * The host's own control for a type (a FieldRenderer arm in the dashboard), drawn for a stored value a kit control\n * hands off because it cannot carry it unchanged (rich text, LegacyFallback). Bare inside the kit FieldShell, which\n * owns the label row and the help; the box is tagged `data-kit-legacy`. Absent → the field says why in words.\n */\n LegacyControl?: React.ComponentType<ControlProps>;\n /**\n * A React HOOK: the project's pages and CMS items a link can point at (controls/link.tsx). The host passes the same\n * function for the life of the form (it is called on every render of a link control). Absent → the link picker says\n * page search isn't available and takes a typed path. `error` is a whole sentence naming what failed (\"Pages couldn't\n * be loaded: …\", \"Items from Blog couldn't be loaded: …\"); the picker shows it under whatever did load.\n */\n useLinkTargets?: () => { targets: LinkTarget[]; loading?: boolean; error?: string };\n}\nlet registry: KitServices = {};\nconst listeners = new Set<() => void>();\n/** Register app services once at module load (e.g. the Content feature registers its media library). */\nexport function registerKitServices(s: KitServices) {\n registry = { ...registry, ...s };\n listeners.forEach((l) => l());\n}\nconst ServicesCtx = React.createContext<KitServices | null>(null);\nexport function KitServicesProvider({ value, children }: { value: KitServices; children: React.ReactNode }) {\n return <ServicesCtx.Provider value={value}>{children}</ServicesCtx.Provider>;\n}\nexport function useKitServices(): KitServices {\n const local = React.useContext(ServicesCtx);\n const global = React.useSyncExternalStore(\n (cb) => {\n listeners.add(cb);\n return () => listeners.delete(cb);\n },\n () => registry,\n () => registry,\n );\n return local ? { ...global, ...local } : global;\n}\n\n/** A host header element a top-level field (by path key) renders its actions into, instead of a label row. */\nexport const FieldHeaderSlot = React.createContext<{ key: string; el: HTMLElement } | null>(null);\n\n/* ── Environment ──────────────────────────────────────────────────────── */\nexport type KitVariant = \"panel\" | \"document\";\nexport interface KitPeer {\n id?: string;\n name: string;\n avatar?: string;\n /** presence colour (avatar ring, field border, caret flag) */\n color?: string;\n /** \"editing\" (soft lock + border) or \"viewing\" */\n status?: \"editing\" | \"viewing\";\n}\nexport interface Swatch {\n name: string;\n value: string;\n token?: string;\n}\n\n/** V2's demo site palette (Caldera). Hosts pass the project's brand palette through `env.palette`. */\nexport const SITE_PALETTE: Swatch[] = [\n { name: \"Ember\", value: \"#E0663B\", token: \"brand.ember\" },\n { name: \"Ochre\", value: \"#D97706\", token: \"brand.ochre\" },\n { name: \"Moss\", value: \"#4F6B4A\", token: \"brand.moss\" },\n { name: \"Lake\", value: \"#2563EB\", token: \"accent.lake\" },\n { name: \"Dusk\", value: \"#7C3AED\", token: \"accent.dusk\" },\n { name: \"Berry\", value: \"#DB2777\", token: \"accent.berry\" },\n { name: \"Char\", value: \"#1E1B18\", token: \"neutral.900\" },\n { name: \"Slate\", value: \"#4B5563\", token: \"neutral.600\" },\n { name: \"Bone\", value: \"#E7E0D6\", token: \"neutral.200\" },\n { name: \"Paper\", value: \"#F6F1EA\", token: \"neutral.50\" },\n];\n\nexport interface KitEnv {\n variant: KitVariant;\n /** Identity of the document/block being edited (rich-text sync, comments, history). */\n docId: string;\n /** The document's title — slug generation. */\n docTitle?: string;\n /** Public URL prefix for slug previews, e.g. \"caldera.bettercms.site/journal/\". */\n urlPrefix?: string;\n /** The document has been published (slug changes warn about the old address). */\n isPublished?: boolean;\n palette: Swatch[];\n /** The whole form is read-only for the lens (the host's content.edit rule, a generated twin…). */\n readOnly: boolean;\n /**\n * D58: the host's access check for the lens (`useCan` at the host). The kit never imports the store; it asks this for\n * field-level `access` and for developer surfaces (field keys, IDs, API names: `schema.view` or `api.view`).\n * Hosts that omit it (staff tools, demos) get allow-all.\n */\n can: (cap: Cap) => boolean;\n /** pathKey → teammates in that field */\n presence: Record<string, KitPeer[]>;\n /** pathKey → open comment threads */\n comments: Record<string, number>;\n /** Host comment panel. When absent, field comments live in the in-place popover only. */\n onComment?: (path: FieldPath, field: FieldSchema) => void;\n /** The whole form is a global block (\"Navigation\") — every field is synced. */\n syncedFrom?: string;\n /** \"Open {title}\" on a reference card: the host edits the referenced entry in place (stacked panel). */\n onOpenReference?: (ref: { collectionId: string; entryId: string; title: string }) => void;\n /** CPO D39: \"inline\" (default) shows help under the label; \"tooltip\" moves it behind the ⓘ — for dense hosts (grid cells, popovers). */\n helpDisplay?: \"inline\" | \"tooltip\";\n}\nexport const DEFAULT_ENV: KitEnv = {\n variant: \"panel\",\n docId: \"kit\",\n palette: [],\n readOnly: false,\n can: () => true,\n presence: {},\n comments: {},\n};\nconst EnvCtx = React.createContext<KitEnv>(DEFAULT_ENV);\n\n/** D58 field access: fields in the `seo` group default to `{ edit: \"seo.edit\" }`. */\nexport const fieldAccessOf = (field: FieldSchema): FieldAccess | undefined => field.access ?? (field.group === \"seo\" ? { edit: \"seo.edit\" } : undefined);\n\n/**\n * One field for the lens: hidden (no `view`), read-only (plain text: no `edit`, the field is `readOnly`, or the whole form\n * is read-only and the field has no edit cap of its own), or editable. An explicit `edit` cap wins over the form's\n * read-only rule, so an SEO specialist edits SEO fields inside a form they can't otherwise change.\n */\nexport function resolveFieldAccess(field: FieldSchema, env: Pick<KitEnv, \"can\" | \"readOnly\">): { hidden: boolean; readOnly: boolean } {\n const a = fieldAccessOf(field);\n if (a?.view && !env.can(a.view)) return { hidden: true, readOnly: true };\n if (field.readOnly === true) return { hidden: false, readOnly: true };\n if (a?.edit) return { hidden: false, readOnly: !env.can(a.edit) };\n return { hidden: false, readOnly: env.readOnly };\n}\n/** Drop the fields the lens can't `view` (recursively), so they are neither rendered nor validated. Same object back when\n * nothing is hidden. Values of dropped fields stay in the document untouched. */\nexport function visibleFields(fields: FieldSchema[], can: KitEnv[\"can\"]): FieldSchema[] {\n let changed = false;\n const out: FieldSchema[] = [];\n for (const f of fields) {\n const a = fieldAccessOf(f);\n if (a?.view && !can(a.view)) {\n changed = true;\n continue;\n }\n let g = f;\n if (f.fields) {\n const n = visibleFields(f.fields, can);\n if (n !== f.fields) g = { ...g, fields: n };\n }\n if (Array.isArray(f.of)) {\n const n = visibleFields(f.of, can);\n if (n !== f.of) g = { ...g, of: n };\n }\n if (f.slotSettings) {\n const n = visibleFields(f.slotSettings, can);\n if (n !== f.slotSettings) g = { ...g, slotSettings: n };\n }\n if (g !== f) changed = true;\n out.push(g);\n }\n return changed ? out : fields;\n}\nexport function visibleSchema(schema: TypeSchema, can: KitEnv[\"can\"]): TypeSchema {\n const fields = visibleFields(schema.fields, can);\n return fields === schema.fields ? schema : { ...schema, fields };\n}\n\n/** Developer surfaces (field keys, API names, IDs): `schema.view` or `api.view`. */\nexport const seesDevSurfaces = (env: Pick<KitEnv, \"can\">) => env.can(\"schema.view\") || env.can(\"api.view\");\nexport const KitEnvProvider = EnvCtx.Provider;\nexport const useKitEnv = () => React.useContext(EnvCtx);\n\n/* ── Form runtime (inside <SchemaForm>) ──────────────────────────────── */\nexport interface HistoryEntry {\n value: unknown;\n at: number;\n by: string;\n label?: string;\n}\nexport interface FormApi {\n schema: TypeSchema;\n value: Record<string, unknown>;\n /** write a value; `record: false` skips the field undo/history stack (e.g. programmatic sync) */\n setAt: (path: FieldPath, v: unknown, opts?: { record?: boolean; label?: string }) => void;\n getAt: (path: FieldPath) => unknown;\n /** value when the form mounted (field undo baseline) */\n baselineAt: (path: FieldPath) => unknown;\n /** published value (changed dot, Reset to published); undefined when never published */\n publishedAt: (path: FieldPath) => unknown;\n hasPublished: boolean;\n /** component instances (CPO D28): top-level fields inherit from a component unless overridden */\n inherited?: { from: string; isOverridden: (key: string) => boolean; reset: (key: string) => void };\n /** the current navigation path (drill-in stack) */\n path: FieldPath;\n navigate: (path: FieldPath) => void;\n /** the form draws frames for a non-root path. False while SchemaForm renders only the root frame: History and\n * drill-in rows hide or go inert instead of navigating to a path nothing shows (no silent no-op). */\n canNavigate: boolean;\n resolveSchema?: (blockType: string) => TypeSchema | undefined;\n /** blocks offered by \"+ Add block\" in slots (filtered by each slot's allow list) */\n blockLibrary?: TypeSchema[];\n /** all issues by pathKey */\n issues: Map<string, KitIssue>;\n /** the issue shown for a key (rules on blur, required after blur or a publish attempt) */\n visibleIssue: (key: string) => KitIssue | undefined;\n /** visible issues under a path prefix (rollup dots on rows, crumbs and tabs) */\n rollup: (prefix: FieldPath) => { errors: number; warnings: number };\n touch: (key: string) => void;\n showAllErrors: boolean;\n /** per-field undo (Undo last change to {label}) */\n canUndo: (key: string) => boolean;\n undo: (key: string) => void;\n /** versions of a field this session (newest first) */\n history: (key: string) => HistoryEntry[];\n /** the last change to this field came from AI (⋯ shows \"Undo AI change\") */\n aiKeys: Set<string>;\n markAi: (key: string, on: boolean) => void;\n /** remembered UI state per frame (selected group tab, open fieldsets) */\n memory: Map<string, unknown>;\n}\nconst FormCtx = React.createContext<FormApi | null>(null);\nexport const FormProvider = FormCtx.Provider;\nexport const useForm = () => React.useContext(FormCtx);\n"],"mappings":"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"}
|
package/controls/button.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"button.js","names":[],"sources":["../../src/kit/controls/button.tsx"],"sourcesContent":["/**\n * BUTTON — label + link + look as ONE unit (V2 HEAD kit/controls/link.tsx \"Button\", DESIGN §8.8, CPO D43 · D45 · D46).\n *\n * - <ButtonControl> at rest: one FieldUnit, two rows. The label row drills into the button screen (form.navigate → the\n * \"button\" frame); the link row edits the link in place (LinkQuickEdit).\n * - <ButtonScreen> the one button screen (the frame body): preview · label · link (LinkForm) · appearance (style grid,\n * size, leading icon, arrow).\n * - <ButtonStyleGrid>, <ButtonPreview>, <StyleGlyph> — the pieces both draw.\n *\n * Stored shape (prod `button`, adapters/values.ts buttonToProd / buttonFromProd; backend buttonValueProblem). The kit\n * value is the flattened V2 button the adapter hands in. What this control writes keeps that value's keys:\n * - the look goes in the key the value already uses — `style` when it has one, else `variant` (what prod renderers\n * read) — and never both (buttonToProd names an equal pair as lost, so the dock would refuse the write);\n * - `rel: \"follow\"` is never written (prod's rel list is nofollow · sponsored · ugc) and `newTab: false`/`target` only\n * where the stored value had that key (storedLink);\n * - `icon` is a dock icon name (DOCK_ICON_NAMES): the picker offers only icons that are dock names.\n *\n * \"Full width\" writes `fullWidth: true`, and off writes `false` only where the stored value had the key (as Show arrow);\n * every renderer draws it (hosted `bcms-btn-full`, the SDKs' and in-place publishing's `data-full-width`).\n *\n * Deviations from V2, each because prod has nothing behind it: an unset look reads \"Default\" (V2 drew Primary, and guessed Outline for a field named \"secondary\"); the button\n * screen's preview reads the site palette from --kit-preview-paper / -ink / -primary / -primary-on / -line / -filter\n * when the host sets them (the Kit library sets V2's demo-site palette) and otherwise draws in neutral kit ink (the\n * dock has no project palette yet; the canvas shows the site's own button). The style grid stays in kit ink except Primary, which shows the brand colour as V2's chrome swatch does.\n */\nimport * as React from \"react\";\nimport { IconArrowRight, IconChevronDown, IconChevronRight, IconSearch } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { isObj } from \"../lib/path\";\nimport { KIT_ICONS, KitIcon, iconLabel } from \"../lib/icons\";\nimport { BUTTON_VARIANTS, DOCK_ICON_NAME_SET } from \"../adapters/prod-types\";\nimport { useForm, useKitEnv } from \"../context\";\nimport { FieldUnit } from \"../engine/grouping\";\nimport { Input } from \"../ui/input\";\nimport { Segmented, Switch } from \"../ui/controls\";\nimport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from \"../ui/overlay\";\nimport type { ControlProps } from \"../types\";\nimport { LinkForm, LinkLine, LinkQuickEdit, TARGET_KEYS, describeLink, finalizeLink, findTarget, hasLink, normLink, storedLink, useLinkTargets, type ButtonStyle, type LinkValue } from \"./link\";\n\nexport const STYLE_ITEMS: { value: ButtonStyle; label: string }[] = [\n { value: \"primary\", label: \"Primary\" },\n { value: \"secondary\", label: \"Secondary\" },\n { value: \"outline\", label: \"Outline\" },\n { value: \"link\", label: \"Text link\" },\n];\nconst SIZE_LABEL = { sm: \"Small\", md: \"Medium\", lg: \"Large\" } as const;\nconst isVariant = (x: unknown): x is string => typeof x === \"string\" && (BUTTON_VARIANTS as readonly string[]).includes(x);\n\n/** The look prod renders: the first valid of variant, style (buttonToProd's rule). */\nexport function lookOf(v: Pick<LinkValue, \"variant\" | \"style\">): string | undefined {\n return [v.variant, v.style].find(isVariant);\n}\n/** \"Brand\" for a stored look outside the four styles; undefined when unset. */\nexport function lookLabel(look: string | undefined): string {\n if (!look) return \"Default\";\n return STYLE_ITEMS.find((s) => s.value === look)?.label ?? look.charAt(0).toUpperCase() + look.slice(1);\n}\n\n/**\n * The next stored button: `raw` (the value as the field holds it) with `patch` applied, keyed like `raw`. A look in the\n * patch (`style`) lands in the key `raw` uses for it.\n */\nexport function nextButton(raw: unknown, patch: Partial<LinkValue>): LinkValue {\n const base: LinkValue = isObj(raw) ? ({ ...(raw as object) } as LinkValue) : { href: \"\" };\n const { style, ...rest } = patch;\n const out: LinkValue = { ...base, ...rest };\n // prod requires both strings (buttonToProd names a missing one as lost, and the dock refuses the write)\n if (typeof out.href !== \"string\") out.href = \"\";\n if (typeof out.label !== \"string\") out.label = \"\";\n if (style !== undefined) {\n const key = isObj(raw) && raw.style !== undefined ? \"style\" : \"variant\";\n delete out.style;\n delete out.variant;\n out[key] = style;\n }\n return storedLink(out, raw);\n}\n\n/** The icons a button can carry: the kit's drawn icons that are also dock names (the backend checks the name). */\nexport const BUTTON_ICONS: string[] = Object.keys(KIT_ICONS).filter((n) => DOCK_ICON_NAME_SET.has(n));\n\n/** D46: four styles never sit in a row of tabs. The option IS the visual, so it is a 2×2 grid of live previews (one\n * radiogroup: Tab enters on the checked style, arrows move and pick). A stored look outside the four is listed too. */\nexport function ButtonStyleGrid({\n v,\n onPick,\n \"aria-label\": ariaLabel,\n size = \"md\",\n}: {\n v: LinkValue;\n onPick: (s: ButtonStyle) => void;\n \"aria-label\": string;\n size?: \"sm\" | \"md\";\n}) {\n const cur = lookOf(v);\n const items: { value: string; label: string }[] = cur && !STYLE_ITEMS.some((s) => s.value === cur) ? [...STYLE_ITEMS, { value: cur, label: lookLabel(cur) }] : STYLE_ITEMS;\n const onKey = (e: React.KeyboardEvent, i: number) => {\n const d = e.key === \"ArrowRight\" || e.key === \"ArrowDown\" ? 1 : e.key === \"ArrowLeft\" || e.key === \"ArrowUp\" ? -1 : 0;\n if (!d) return;\n e.preventDefault();\n const next = items[(i + d + items.length) % items.length];\n onPick(next.value as ButtonStyle);\n const group = (e.currentTarget as HTMLElement).parentElement;\n requestAnimationFrame(() => group?.querySelector<HTMLElement>(`[data-style=\"${next.value}\"]`)?.focus());\n };\n return (\n <div className=\"grid grid-cols-2 gap-1.5\" role=\"radiogroup\" aria-label={ariaLabel}>\n {items.map((s, i) => {\n const on = cur === s.value;\n return (\n <button\n key={s.value}\n type=\"button\"\n role=\"radio\"\n data-style={s.value}\n aria-checked={on}\n tabIndex={on || (!items.some((x) => x.value === cur) && i === 0) ? 0 : -1}\n onKeyDown={(e) => onKey(e, i)}\n onClick={() => onPick(s.value as ButtonStyle)}\n className={cn(\n \"flex min-w-0 items-center gap-2 rounded-kit-md border px-2 transition-colors\",\n size === \"sm\" ? \"h-8 text-kit-xs\" : \"h-9 text-kit-sm\",\n on ? \"border-[var(--kit-emphasis-line)] bg-kit-selected text-kit-fg\" : \"border-kit-line text-kit-fg-2 hover:border-kit-line-strong hover:text-kit-fg\",\n )}\n >\n <ButtonPreview v={{ ...v, style: s.value as ButtonStyle, variant: undefined, label: \"Aa\", icon: undefined, arrow: false }} small />\n <span className=\"truncate\">{s.label}</span>\n </button>\n );\n })}\n </div>\n );\n}\n\n/**\n * The button as a shape: filled · soft · outlined · underlined. In kit ink by default; `site` draws it in the host's\n * site palette (--kit-preview-*), falling back to kit ink for each token the host leaves unset.\n */\nexport function ButtonPreview({ v, className, small, site }: { v: LinkValue; className?: string; small?: boolean; site?: boolean }) {\n const style = lookOf(v) ?? \"primary\";\n const size = small ? \"sm\" : v.size ?? \"md\";\n return (\n <span\n className={cn(\n \"inline-flex max-w-full items-center justify-center gap-1.5 truncate font-medium transition-colors\",\n size === \"sm\" ? \"h-6 rounded-kit-md px-2 text-kit-xs\" : size === \"lg\" ? \"h-10 rounded-kit-lg px-4 text-kit-base\" : \"h-8 rounded-kit-lg px-3 text-kit-sm\",\n site ? siteLook(style) : style === \"link\"\n ? \"h-auto px-0 text-kit-fg underline underline-offset-4\"\n : style === \"outline\"\n ? \"border border-kit-line-strong text-kit-fg\"\n : style === \"primary\" || style === \"brand\"\n ? \"bg-[color:var(--kit-preview-primary,var(--kit-inverse))] text-[color:var(--kit-preview-primary-on,var(--kit-fg-inverse))]\"\n : style === \"dark\"\n ? \"bg-kit-inverse text-kit-fg-inverse\"\n : \"bg-kit-muted text-kit-fg\",\n className,\n )}\n >\n {v.icon ? <KitIcon name={v.icon} className=\"size-3.5 shrink-0\" /> : null}\n <span className=\"truncate\">{v.label || \"Button\"}</span>\n {v.arrow ? <IconArrowRight className=\"size-3.5 shrink-0\" stroke={1.75} /> : null}\n </span>\n );\n}\n\n/** V2's site preview: primary in the brand colour, secondary / dark as ink on paper, outline as an ink hairline. */\nfunction siteLook(style: string): string {\n if (style === \"link\") return \"h-auto px-0 text-[color:var(--kit-preview-primary,var(--kit-fg))] underline underline-offset-4\";\n if (style === \"outline\") return \"border border-[color:var(--kit-preview-line,var(--kit-line-strong))] text-[color:var(--kit-preview-ink,var(--kit-fg))]\";\n if (style === \"primary\" || style === \"brand\") return \"bg-[color:var(--kit-preview-primary,var(--kit-inverse))] text-[color:var(--kit-preview-primary-on,var(--kit-fg-inverse))]\";\n if (style === \"dark\") return \"bg-[color:var(--kit-preview-ink,var(--kit-inverse))] text-[color:var(--kit-preview-paper,var(--kit-fg-inverse))]\";\n return \"bg-[color:var(--kit-preview-ink,var(--kit-muted))] text-[color:var(--kit-preview-paper,var(--kit-fg))]\";\n}\n\n/** A 16px neutral glyph of the style (filled · outlined · underlined) — brand-free, so the field stays calm. */\nexport function StyleGlyph({ style, className }: { style?: string; className?: string }) {\n return (\n <span aria-hidden className={cn(\"flex size-4 shrink-0 items-center justify-center\", className)}>\n {style === \"link\" ? (\n <span className=\"h-[2px] w-3.5 rounded-full bg-kit-fg-2\" />\n ) : (\n <span className={cn(\"h-2.5 w-4 rounded-[3px]\", style === \"outline\" ? \"border-[1.5px] border-kit-fg-2\" : style === \"secondary\" || style === \"light\" || style === \"tertiary\" ? \"bg-kit-fg-3\" : \"bg-kit-fg\")} />\n )}\n </span>\n );\n}\n\n/** The leading-icon picker: search + grid over BUTTON_ICONS, \"No icon\" first. */\nexport function ButtonIconPicker({ value, onPick }: { value?: string; onPick: (icon: string | undefined) => void }) {\n const [q, setQ] = React.useState(\"\");\n const query = q.trim().toLowerCase();\n const shown = query ? BUTTON_ICONS.filter((n) => n.includes(query.replace(/\\s+/g, \"-\"))) : BUTTON_ICONS;\n return (\n <div className=\"flex flex-col gap-2\">\n <Input size=\"sm\" aria-label=\"Search icons\" leading={<IconSearch stroke={1.5} />} value={q} onChange={(e) => setQ(e.target.value)} placeholder=\"Search icons\" autoFocus />\n <div role=\"radiogroup\" aria-label=\"Leading icon\" className=\"grid max-h-56 grid-cols-8 gap-1 overflow-y-auto overscroll-contain\">\n {query ? null : (\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={!value}\n aria-label=\"No icon\"\n onClick={() => onPick(undefined)}\n className={cn(\"flex size-8 items-center justify-center rounded-kit-md text-kit-fg-3 hover:bg-kit-hover\", !value && \"bg-kit-selected\")}\n >\n <span className=\"size-4 rounded-kit-md border border-dashed border-[var(--kit-emphasis-line)]\" />\n </button>\n )}\n {shown.map((n) => (\n <button\n key={n}\n type=\"button\"\n role=\"radio\"\n aria-checked={value === n}\n aria-label={iconLabel(n)}\n onClick={() => onPick(n)}\n className={cn(\"flex size-8 items-center justify-center rounded-kit-md text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg\", value === n && \"bg-kit-selected text-kit-fg\")}\n >\n <KitIcon name={n} className=\"size-4\" />\n </button>\n ))}\n </div>\n {shown.length === 0 ? <p className=\"px-1 text-kit-xs text-kit-fg-3\">No icon matches “{q.trim()}”.</p> : null}\n </div>\n );\n}\n\n/** The ONE button screen: preview · label · link (+ new tab, rel) · appearance (style, size, icon, arrow). */\nexport function ButtonScreen({ value, onChange, readOnly, title = \"Button\" }: { value: unknown; onChange: (v: LinkValue) => void; readOnly?: boolean; title?: string }) {\n const v = normLink(value);\n const set = (p: Partial<LinkValue>) => onChange(nextButton(value, p));\n const [iconOpen, setIconOpen] = React.useState(false);\n const labelId = React.useId();\n const arrowId = React.useId();\n const fullId = React.useId();\n return (\n <fieldset disabled={readOnly} className=\"flex min-w-0 flex-col gap-5\">\n <div data-button-preview=\"\" className=\"flex min-h-20 items-center justify-center rounded-kit-lg bg-[color:var(--kit-preview-paper,var(--kit-subtle))] px-4 py-5 [filter:var(--kit-preview-filter,none)]\">\n <ButtonPreview v={v} site />\n </div>\n <Row label=\"Label\" htmlFor={labelId}>\n <Input id={labelId} value={v.label ?? \"\"} onChange={(e) => set({ label: e.target.value })} placeholder=\"Shop now\" />\n </Row>\n <div className=\"flex flex-col gap-1.5\" role=\"group\" aria-label={`${title} link`}>\n <span className=\"text-kit-sm font-medium text-kit-fg-2\">Link</span>\n <LinkForm\n readOnly={readOnly}\n value={v}\n onChange={(n) => {\n // a script link is never written; LinkForm says why under the target\n const out = finalizeLink(n);\n if (out) set(linkPart(out));\n }}\n />\n </div>\n <div className=\"flex flex-col gap-4 border-t border-kit-line pt-4\">\n <span className=\"text-kit-xs font-medium text-kit-fg-3\">Appearance</span>\n <Row label=\"Style\">\n <ButtonStyleGrid v={v} aria-label={`${title} style`} onPick={(style) => set({ style })} />\n </Row>\n <Row label=\"Size\">\n <Segmented<\"sm\" | \"md\" | \"lg\">\n aria-label={`${title} size`}\n value={v.size ?? \"md\"}\n onChange={(s) => set({ size: s })}\n items={[\n { value: \"sm\", label: \"Small\" },\n { value: \"md\", label: \"Medium\" },\n { value: \"lg\", label: \"Large\" },\n ]}\n className=\"w-full [&>button]:flex-1\"\n />\n </Row>\n <Row label=\"Leading icon\">\n <Popover open={iconOpen} onOpenChange={setIconOpen}>\n <PopoverTrigger\n render={\n <button\n type=\"button\"\n className=\"flex h-8 w-full items-center gap-2 rounded-kit-md border border-kit-field-border bg-kit-field-bg px-2.5 text-left text-kit-sm text-kit-fg shadow-kit-field hover:border-kit-field-border-hover data-[popup-open]:border-kit-field-border-focus\"\n />\n }\n >\n {v.icon ? <KitIcon name={v.icon} className=\"size-4 text-kit-fg-2\" /> : <span className=\"size-4 rounded-kit-md border border-dashed border-[var(--kit-emphasis-line)]\" />}\n <span className={cn(\"flex-1 truncate\", !v.icon && \"text-kit-fg-3\")}>{v.icon ? iconLabel(v.icon) : \"No icon\"}</span>\n <IconChevronDown className=\"size-3.5 text-kit-fg-3\" stroke={1.5} />\n </PopoverTrigger>\n <PopoverContent className=\"w-[300px] p-2\">\n <ButtonIconPicker\n value={v.icon}\n onPick={(k) => {\n set({ icon: k });\n setIconOpen(false);\n }}\n />\n </PopoverContent>\n </Popover>\n </Row>\n <div className=\"flex flex-col gap-2\">\n <label htmlFor={arrowId} className=\"flex min-h-7 cursor-pointer items-center justify-between gap-3\">\n <span className=\"text-kit-sm text-kit-fg-2\">Show arrow</span>\n <Switch disabled={readOnly} id={arrowId} size=\"sm\" checked={!!v.arrow} onCheckedChange={(c) => set({ arrow: c ? true : isObj(value) && \"arrow\" in value ? false : undefined })} />\n </label>\n <label htmlFor={fullId} className=\"flex min-h-7 cursor-pointer items-center justify-between gap-3\">\n <span className=\"text-kit-sm text-kit-fg-2\">Full width</span>\n <Switch\n disabled={readOnly}\n id={fullId}\n size=\"sm\"\n checked={v.fullWidth === true}\n onCheckedChange={(c) => set({ fullWidth: c ? true : isObj(value) && \"fullWidth\" in value ? false : undefined })}\n />\n </label>\n </div>\n </div>\n </fieldset>\n );\n}\n\n/** The link half of a link value (what LinkForm / the quick edit own); the label and the look stay the button's. */\nfunction linkPart(n: LinkValue): Partial<LinkValue> {\n const { label: _l, style: _s, variant: _v, size: _z, arrow: _a, icon: _i, fullWidth: _f, ...link } = n;\n // a key the new link no longer has (a picked page drops the typed email) is cleared, not kept from before\n return { ...TARGET_KEYS, email: undefined, phone: undefined, subject: undefined, ...link };\n}\n\nfunction Row({ label, children, htmlFor }: { label: string; children: React.ReactNode; htmlFor?: string }) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n <label htmlFor={htmlFor} className=\"text-kit-sm font-medium text-kit-fg-2\">\n {label}\n </label>\n {children}\n </div>\n );\n}\n\n/**\n * Button field at rest: ONE unit between two hairlines (fieldset-like).\n * [style glyph] Label ……………… Primary · Medium › → drills into the button screen (\"… › Button\")\n * [page icon] Title /path → edits the link in place\n */\nexport function ButtonControl({ value, onChange, readOnly, id, path, field }: ControlProps) {\n const v = normLink(value);\n const form = useForm();\n const { variant } = useKitEnv();\n const [open, setOpen] = React.useState(false);\n const [editingLink, setEditingLink] = React.useState(false);\n const { targets } = useLinkTargets();\n const target = findTarget(targets, v);\n const linkBtn = React.useRef<HTMLButtonElement>(null);\n const look = lookOf(v);\n const openSettings = () => (form ? form.navigate(path) : setOpen(true));\n const h = variant === \"document\" ? \"h-10\" : \"h-9\";\n const head = (\n <button\n id={id}\n type=\"button\"\n onClick={readOnly && !form ? undefined : openSettings}\n aria-label={`${field.title}: ${v.label || \"no label\"}. Open button settings`}\n className={cn(\"group/bhead flex w-full min-w-0 items-center gap-2.5 px-2.5 text-left outline-none transition-colors hover:bg-kit-hover focus-visible:bg-kit-hover\", h)}\n >\n <StyleGlyph style={look} />\n <span className={cn(\"min-w-0 flex-1 truncate text-kit-sm font-medium\", v.label ? \"text-kit-fg\" : \"text-kit-fg-3\")}>{v.label || \"Add a label\"}</span>\n <span className=\"shrink-0 text-kit-xs text-kit-fg-3\">\n {lookLabel(look)}\n {v.size && v.size !== \"md\" ? ` · ${SIZE_LABEL[v.size]}` : \"\"}\n </span>\n <IconChevronRight className=\"size-4 shrink-0 text-kit-fg-3 transition-transform group-hover/bhead:translate-x-0.5\" stroke={1.5} aria-hidden />\n </button>\n );\n const linkRow =\n editingLink && !readOnly ? (\n <div>\n <LinkQuickEdit\n value={v}\n ariaLabel={`${field.title} link`}\n size=\"sm\"\n bare\n onCommit={(n) => onChange(nextButton(value, n ? linkPart(n) : { ...linkPart({ href: \"\" }), type: \"page\", href: \"\" }))}\n onDone={() => {\n setEditingLink(false);\n requestAnimationFrame(() => linkBtn.current?.focus({ preventScroll: true }));\n }}\n />\n </div>\n ) : (\n <button\n ref={linkBtn}\n type=\"button\"\n disabled={readOnly}\n onClick={() => setEditingLink(true)}\n aria-label={hasLink(v) ? `${field.title} link: ${describeLink(v, target).primary}. Edit link` : `Add a link to ${field.title.toLowerCase()}`}\n className={cn(\"flex w-full min-w-0 items-center px-2.5 text-left outline-none transition-colors hover:bg-kit-hover focus-visible:bg-kit-hover disabled:cursor-default disabled:hover:bg-transparent\", h)}\n >\n <LinkLine v={v} target={target} />\n </button>\n );\n // CPO D43 + D45: label + link are ONE unit — one border, a hairline between the label row and the link row\n const unit = (\n <FieldUnit data-button-unit=\"\" aria-label={field.title} className=\"overflow-hidden\">\n {head}\n {linkRow}\n </FieldUnit>\n );\n if (form) return unit;\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverAnchor render={unit} />\n <PopoverContent className=\"w-[360px] p-4\" align=\"start\">\n <ButtonScreen value={value} onChange={onChange} readOnly={readOnly} title={field.title} />\n </PopoverContent>\n </Popover>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,IAAa,cAAuD;CAClE;EAAE,OAAO;EAAW,OAAO;EAAW;CACtC;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAW,OAAO;EAAW;CACtC;EAAE,OAAO;EAAQ,OAAO;EAAa;CACtC;AACD,IAAM,aAAa;CAAE,IAAI;CAAS,IAAI;CAAU,IAAI;CAAS;AAC7D,IAAM,aAAa,MAA4B,OAAO,MAAM,YAAa,gBAAsC,SAAS,EAAE;;AAG1H,SAAgB,OAAO,GAA6D;AAClF,QAAO,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,KAAK,UAAU;;;AAG7C,SAAgB,UAAU,MAAkC;AAC1D,KAAI,CAAC,KAAM,QAAO;AAClB,QAAO,YAAY,MAAM,MAAM,EAAE,UAAU,KAAK,EAAE,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE;;;;;;AAOzG,SAAgB,WAAW,KAAc,OAAsC;CAC7E,MAAM,OAAkB,MAAM,IAAI,GAAI,EAAE,GAAI,KAAgB,GAAiB,EAAE,MAAM,IAAI;CACzF,MAAM,EAAE,OAAO,GAAG,SAAS;CAC3B,MAAM,MAAiB;EAAE,GAAG;EAAM,GAAG;EAAM;AAE3C,KAAI,OAAO,IAAI,SAAS,SAAU,KAAI,OAAO;AAC7C,KAAI,OAAO,IAAI,UAAU,SAAU,KAAI,QAAQ;AAC/C,KAAI,UAAU,KAAA,GAAW;EACvB,MAAM,MAAM,MAAM,IAAI,IAAI,IAAI,UAAU,KAAA,IAAY,UAAU;AAC9D,SAAO,IAAI;AACX,SAAO,IAAI;AACX,MAAI,OAAO;;AAEb,QAAO,WAAW,KAAK,IAAI;;;AAI7B,IAAa,eAAyB,OAAO,KAAK,UAAU,CAAC,QAAQ,MAAM,mBAAmB,IAAI,EAAE,CAAC;;;AAIrG,SAAgB,gBAAgB,EAC9B,GACA,QACA,cAAc,WACd,OAAO,QAMN;CACD,MAAM,MAAM,OAAO,EAAE;CACrB,MAAM,QAA4C,OAAO,CAAC,YAAY,MAAM,MAAM,EAAE,UAAU,IAAI,GAAG,CAAC,GAAG,aAAa;EAAE,OAAO;EAAK,OAAO,UAAU,IAAI;EAAE,CAAC,GAAG;CAC/J,MAAM,SAAS,GAAwB,MAAc;EACnD,MAAM,IAAI,EAAE,QAAQ,gBAAgB,EAAE,QAAQ,cAAc,IAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,YAAY,KAAK;AACpH,MAAI,CAAC,EAAG;AACR,IAAE,gBAAgB;EAClB,MAAM,OAAO,OAAO,IAAI,IAAI,MAAM,UAAU,MAAM;AAClD,SAAO,KAAK,MAAqB;EACjC,MAAM,QAAS,EAAE,cAA8B;AAC/C,8BAA4B,OAAO,cAA2B,gBAAgB,KAAK,MAAM,IAAI,EAAE,OAAO,CAAC;;AAEzG,QACE,oBAAC,OAAD;EAAK,WAAU;EAA2B,MAAK;EAAa,cAAY;YACrE,MAAM,KAAK,GAAG,MAAM;GACnB,MAAM,KAAK,QAAQ,EAAE;AACrB,UACE,qBAAC,UAAD;IAEE,MAAK;IACL,MAAK;IACL,cAAY,EAAE;IACd,gBAAc;IACd,UAAU,MAAO,CAAC,MAAM,MAAM,MAAM,EAAE,UAAU,IAAI,IAAI,MAAM,IAAK,IAAI;IACvE,YAAY,MAAM,MAAM,GAAG,EAAE;IAC7B,eAAe,OAAO,EAAE,MAAqB;IAC7C,WAAW,GACT,gFACA,SAAS,OAAO,oBAAoB,mBACpC,KAAK,kEAAkE,+EACxE;cAbH,CAeE,oBAAC,eAAD;KAAe,GAAG;MAAE,GAAG;MAAG,OAAO,EAAE;MAAsB,SAAS,KAAA;MAAW,OAAO;MAAM,MAAM,KAAA;MAAW,OAAO;MAAO;KAAE,OAAA;KAAQ,CAAA,EACnI,oBAAC,QAAD;KAAM,WAAU;eAAY,EAAE;KAAa,CAAA,CACpC;MAhBF,EAAE,MAgBA;IAEX;EACE,CAAA;;;;;;AAQV,SAAgB,cAAc,EAAE,GAAG,WAAW,OAAO,QAA+E;CAClI,MAAM,QAAQ,OAAO,EAAE,IAAI;CAC3B,MAAM,OAAO,QAAQ,OAAO,EAAE,QAAQ;AACtC,QACE,qBAAC,QAAD;EACE,WAAW,GACT,qGACA,SAAS,OAAO,wCAAwC,SAAS,OAAO,2CAA2C,uCACnH,OAAO,SAAS,MAAM,GAAG,UAAU,SAC/B,yDACA,UAAU,YACR,8CACA,UAAU,aAAa,UAAU,UAC/B,8HACA,UAAU,SACR,uCACA,4BACV,UACD;YAdH;GAgBG,EAAE,OAAO,oBAAC,SAAD;IAAS,MAAM,EAAE;IAAM,WAAU;IAAsB,CAAA,GAAG;GACpE,oBAAC,QAAD;IAAM,WAAU;cAAY,EAAE,SAAS;IAAgB,CAAA;GACtD,EAAE,QAAQ,oBAAC,gBAAD;IAAgB,WAAU;IAAoB,QAAQ;IAAQ,CAAA,GAAG;GACvE;;;;AAKX,SAAS,SAAS,OAAuB;AACvC,KAAI,UAAU,OAAQ,QAAO;AAC7B,KAAI,UAAU,UAAW,QAAO;AAChC,KAAI,UAAU,aAAa,UAAU,QAAS,QAAO;AACrD,KAAI,UAAU,OAAQ,QAAO;AAC7B,QAAO;;;AAIT,SAAgB,WAAW,EAAE,OAAO,aAAqD;AACvF,QACE,oBAAC,QAAD;EAAM,eAAA;EAAY,WAAW,GAAG,oDAAoD,UAAU;YAC3F,UAAU,SACT,oBAAC,QAAD,EAAM,WAAU,0CAA2C,CAAA,GAE3D,oBAAC,QAAD,EAAM,WAAW,GAAG,2BAA2B,UAAU,YAAY,mCAAmC,UAAU,eAAe,UAAU,WAAW,UAAU,aAAa,gBAAgB,YAAY,EAAI,CAAA;EAE1M,CAAA;;;AAKX,SAAgB,iBAAiB,EAAE,OAAO,UAA0E;CAClH,MAAM,CAAC,GAAG,QAAQ,MAAM,SAAS,GAAG;CACpC,MAAM,QAAQ,EAAE,MAAM,CAAC,aAAa;CACpC,MAAM,QAAQ,QAAQ,aAAa,QAAQ,MAAM,EAAE,SAAS,MAAM,QAAQ,QAAQ,IAAI,CAAC,CAAC,GAAG;AAC3F,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,OAAD;IAAO,MAAK;IAAK,cAAW;IAAe,SAAS,oBAAC,YAAD,EAAY,QAAQ,KAAO,CAAA;IAAE,OAAO;IAAG,WAAW,MAAM,KAAK,EAAE,OAAO,MAAM;IAAE,aAAY;IAAe,WAAA;IAAY,CAAA;GACzK,qBAAC,OAAD;IAAK,MAAK;IAAa,cAAW;IAAe,WAAU;cAA3D,CACG,QAAQ,OACP,oBAAC,UAAD;KACE,MAAK;KACL,MAAK;KACL,gBAAc,CAAC;KACf,cAAW;KACX,eAAe,OAAO,KAAA,EAAU;KAChC,WAAW,GAAG,2FAA2F,CAAC,SAAS,kBAAkB;eAErI,oBAAC,QAAD,EAAM,WAAU,gFAAiF,CAAA;KAC1F,CAAA,EAEV,MAAM,KAAK,MACV,oBAAC,UAAD;KAEE,MAAK;KACL,MAAK;KACL,gBAAc,UAAU;KACxB,cAAY,UAAU,EAAE;KACxB,eAAe,OAAO,EAAE;KACxB,WAAW,GAAG,6GAA6G,UAAU,KAAK,8BAA8B;eAExK,oBAAC,SAAD;MAAS,MAAM;MAAG,WAAU;MAAW,CAAA;KAChC,EATF,EASE,CACT,CACE;;GACL,MAAM,WAAW,IAAI,qBAAC,KAAD;IAAG,WAAU;cAAb;KAA8C;KAAkB,EAAE,MAAM;KAAC;KAAM;QAAG;GACpG;;;;AAKV,SAAgB,aAAa,EAAE,OAAO,UAAU,UAAU,QAAQ,YAAsG;CACtK,MAAM,IAAI,SAAS,MAAM;CACzB,MAAM,OAAO,MAA0B,SAAS,WAAW,OAAO,EAAE,CAAC;CACrE,MAAM,CAAC,UAAU,eAAe,MAAM,SAAS,MAAM;CACrD,MAAM,UAAU,MAAM,OAAO;CAC7B,MAAM,UAAU,MAAM,OAAO;CAC7B,MAAM,SAAS,MAAM,OAAO;AAC5B,QACE,qBAAC,YAAD;EAAU,UAAU;EAAU,WAAU;YAAxC;GACE,oBAAC,OAAD;IAAK,uBAAoB;IAAG,WAAU;cACpC,oBAAC,eAAD;KAAkB;KAAG,MAAA;KAAO,CAAA;IACxB,CAAA;GACN,oBAAC,KAAD;IAAK,OAAM;IAAQ,SAAS;cAC1B,oBAAC,OAAD;KAAO,IAAI;KAAS,OAAO,EAAE,SAAS;KAAI,WAAW,MAAM,IAAI,EAAE,OAAO,EAAE,OAAO,OAAO,CAAC;KAAE,aAAY;KAAa,CAAA;IAChH,CAAA;GACN,qBAAC,OAAD;IAAK,WAAU;IAAwB,MAAK;IAAQ,cAAY,GAAG,MAAM;cAAzE,CACE,oBAAC,QAAD;KAAM,WAAU;eAAwC;KAAW,CAAA,EACnE,oBAAC,UAAD;KACY;KACV,OAAO;KACP,WAAW,MAAM;MAEf,MAAM,MAAM,aAAa,EAAE;AAC3B,UAAI,IAAK,KAAI,SAAS,IAAI,CAAC;;KAE7B,CAAA,CACE;;GACN,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,QAAD;MAAM,WAAU;gBAAwC;MAAiB,CAAA;KACzE,oBAAC,KAAD;MAAK,OAAM;gBACT,oBAAC,iBAAD;OAAoB;OAAG,cAAY,GAAG,MAAM;OAAS,SAAS,UAAU,IAAI,EAAE,OAAO,CAAC;OAAI,CAAA;MACtF,CAAA;KACN,oBAAC,KAAD;MAAK,OAAM;gBACT,oBAAC,WAAD;OACE,cAAY,GAAG,MAAM;OACrB,OAAO,EAAE,QAAQ;OACjB,WAAW,MAAM,IAAI,EAAE,MAAM,GAAG,CAAC;OACjC,OAAO;QACL;SAAE,OAAO;SAAM,OAAO;SAAS;QAC/B;SAAE,OAAO;SAAM,OAAO;SAAU;QAChC;SAAE,OAAO;SAAM,OAAO;SAAS;QAChC;OACD,WAAU;OACV,CAAA;MACE,CAAA;KACN,oBAAC,KAAD;MAAK,OAAM;gBACT,qBAAC,SAAD;OAAS,MAAM;OAAU,cAAc;iBAAvC,CACE,qBAAC,gBAAD;QACE,QACE,oBAAC,UAAD;SACE,MAAK;SACL,WAAU;SACV,CAAA;kBALN;SAQG,EAAE,OAAO,oBAAC,SAAD;UAAS,MAAM,EAAE;UAAM,WAAU;UAAyB,CAAA,GAAG,oBAAC,QAAD,EAAM,WAAU,gFAAiF,CAAA;SACxK,oBAAC,QAAD;UAAM,WAAW,GAAG,mBAAmB,CAAC,EAAE,QAAQ,gBAAgB;oBAAG,EAAE,OAAO,UAAU,EAAE,KAAK,GAAG;UAAiB,CAAA;SACnH,oBAAC,iBAAD;UAAiB,WAAU;UAAyB,QAAQ;UAAO,CAAA;SACpD;WACjB,oBAAC,gBAAD;QAAgB,WAAU;kBACxB,oBAAC,kBAAD;SACE,OAAO,EAAE;SACT,SAAS,MAAM;AACb,cAAI,EAAE,MAAM,GAAG,CAAC;AAChB,sBAAY,MAAM;;SAEpB,CAAA;QACa,CAAA,CACT;;MACN,CAAA;KACN,qBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,qBAAC,SAAD;OAAO,SAAS;OAAS,WAAU;iBAAnC,CACE,oBAAC,QAAD;QAAM,WAAU;kBAA4B;QAAiB,CAAA,EAC7D,oBAAC,QAAD;QAAQ,UAAU;QAAU,IAAI;QAAS,MAAK;QAAK,SAAS,CAAC,CAAC,EAAE;QAAO,kBAAkB,MAAM,IAAI,EAAE,OAAO,IAAI,OAAO,MAAM,MAAM,IAAI,WAAW,QAAQ,QAAQ,KAAA,GAAW,CAAC;QAAI,CAAA,CAC5K;UACR,qBAAC,SAAD;OAAO,SAAS;OAAQ,WAAU;iBAAlC,CACE,oBAAC,QAAD;QAAM,WAAU;kBAA4B;QAAiB,CAAA,EAC7D,oBAAC,QAAD;QACE,UAAU;QACV,IAAI;QACJ,MAAK;QACL,SAAS,EAAE,cAAc;QACzB,kBAAkB,MAAM,IAAI,EAAE,WAAW,IAAI,OAAO,MAAM,MAAM,IAAI,eAAe,QAAQ,QAAQ,KAAA,GAAW,CAAC;QAC/G,CAAA,CACI;SACJ;;KACF;;GACG;;;;AAKf,SAAS,SAAS,GAAkC;CAClD,MAAM,EAAE,OAAO,IAAI,OAAO,IAAI,SAAS,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,IAAI,WAAW,IAAI,GAAG,SAAS;AAErG,QAAO;EAAE,GAAG;EAAa,OAAO,KAAA;EAAW,OAAO,KAAA;EAAW,SAAS,KAAA;EAAW,GAAG;EAAM;;AAG5F,SAAS,IAAI,EAAE,OAAO,UAAU,WAA2E;AACzG,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,SAAD;GAAgB;GAAS,WAAU;aAChC;GACK,CAAA,EACP,SACG;;;;;;;;AASV,SAAgB,cAAc,EAAE,OAAO,UAAU,UAAU,IAAI,MAAM,SAAuB;CAC1F,MAAM,IAAI,SAAS,MAAM;CACzB,MAAM,OAAO,SAAS;CACtB,MAAM,EAAE,YAAY,WAAW;CAC/B,MAAM,CAAC,MAAM,WAAW,MAAM,SAAS,MAAM;CAC7C,MAAM,CAAC,aAAa,kBAAkB,MAAM,SAAS,MAAM;CAC3D,MAAM,EAAE,YAAY,gBAAgB;CACpC,MAAM,SAAS,WAAW,SAAS,EAAE;CACrC,MAAM,UAAU,MAAM,OAA0B,KAAK;CACrD,MAAM,OAAO,OAAO,EAAE;CACtB,MAAM,qBAAsB,OAAO,KAAK,SAAS,KAAK,GAAG,QAAQ,KAAK;CACtE,MAAM,IAAI,YAAY,aAAa,SAAS;CAC5C,MAAM,OACJ,qBAAC,UAAD;EACM;EACJ,MAAK;EACL,SAAS,YAAY,CAAC,OAAO,KAAA,IAAY;EACzC,cAAY,GAAG,MAAM,MAAM,IAAI,EAAE,SAAS,WAAW;EACrD,WAAW,GAAG,sJAAsJ,EAAE;YALxK;GAOE,oBAAC,YAAD,EAAY,OAAO,MAAQ,CAAA;GAC3B,oBAAC,QAAD;IAAM,WAAW,GAAG,mDAAmD,EAAE,QAAQ,gBAAgB,gBAAgB;cAAG,EAAE,SAAS;IAAqB,CAAA;GACpJ,qBAAC,QAAD;IAAM,WAAU;cAAhB,CACG,UAAU,KAAK,EACf,EAAE,QAAQ,EAAE,SAAS,OAAO,MAAM,WAAW,EAAE,UAAU,GACrD;;GACP,oBAAC,kBAAD;IAAkB,WAAU;IAAuF,QAAQ;IAAK,eAAA;IAAc,CAAA;GACvI;;CAEX,MAAM,UACJ,eAAe,CAAC,WACd,oBAAC,OAAD,EAAA,UACE,oBAAC,eAAD;EACE,OAAO;EACP,WAAW,GAAG,MAAM,MAAM;EAC1B,MAAK;EACL,MAAA;EACA,WAAW,MAAM,SAAS,WAAW,OAAO,IAAI,SAAS,EAAE,GAAG;GAAE,GAAG,SAAS,EAAE,MAAM,IAAI,CAAC;GAAE,MAAM;GAAQ,MAAM;GAAI,CAAC,CAAC;EACrH,cAAc;AACZ,kBAAe,MAAM;AACrB,+BAA4B,QAAQ,SAAS,MAAM,EAAE,eAAe,MAAM,CAAC,CAAC;;EAE9E,CAAA,EACE,CAAA,GAEN,oBAAC,UAAD;EACE,KAAK;EACL,MAAK;EACL,UAAU;EACV,eAAe,eAAe,KAAK;EACnC,cAAY,QAAQ,EAAE,GAAG,GAAG,MAAM,MAAM,SAAS,aAAa,GAAG,OAAO,CAAC,QAAQ,eAAe,iBAAiB,MAAM,MAAM,aAAa;EAC1I,WAAW,GAAG,wLAAwL,EAAE;YAExM,oBAAC,UAAD;GAAa;GAAW;GAAU,CAAA;EAC3B,CAAA;CAGb,MAAM,OACJ,qBAAC,WAAD;EAAW,oBAAiB;EAAG,cAAY,MAAM;EAAO,WAAU;YAAlE,CACG,MACA,QACS;;AAEd,KAAI,KAAM,QAAO;AACjB,QACE,qBAAC,SAAD;EAAe;EAAM,cAAc;YAAnC,CACE,oBAAC,eAAD,EAAe,QAAQ,MAAQ,CAAA,EAC/B,oBAAC,gBAAD;GAAgB,WAAU;GAAgB,OAAM;aAC9C,oBAAC,cAAD;IAAqB;IAAiB;IAAoB;IAAU,OAAO,MAAM;IAAS,CAAA;GAC3E,CAAA,CACT"}
|
package/controls/c1.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"c1.js","names":[],"sources":["../../src/kit/controls/c1.ts"],"sourcesContent":["/**\n * Lane C1 (text, slug, email, url, number, rating, color): the controls and label-row actions this lane ports, keyed by\n * kit type, for the engine's CONTROLS / ACTIONS tables. `registerC1Controls()` puts them in; a registered type stops\n * drawing the host's legacy control.\n */\nimport type { ComponentType } from \"react\";\nimport type { SchemaType } from \"../schema/types\";\nimport type { ControlProps } from \"../types\";\nimport { ACTIONS, CONTROLS } from \"../engine/kit-field\";\nimport { ColorControl } from \"./color\";\nimport { NumberControl, RatingControl } from \"./number\";\nimport { EmailControl, SlugControl, SlugGenerate, StringControl, TextControl, UrlControl } from \"./text\";\n\nexport const C1_CONTROLS: Partial<Record<SchemaType, ComponentType<ControlProps>>> = {\n string: StringControl,\n text: TextControl,\n email: EmailControl,\n url: UrlControl,\n slug: SlugControl,\n number: NumberControl,\n rating: RatingControl,\n color: ColorControl,\n};\nexport const C1_ACTIONS: Partial<Record<SchemaType, ComponentType<ControlProps>>> = { slug: SlugGenerate };\n\nexport function registerC1Controls() {\n Object.assign(CONTROLS, C1_CONTROLS);\n Object.assign(ACTIONS, C1_ACTIONS);\n}\n"],"mappings":";;;;;AAaA,IAAa,cAAwE;CACnF,QAAQ;CACR,MAAM;CACN,OAAO;CACP,KAAK;CACL,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,OAAO;CACR;AACD,IAAa,aAAuE,EAAE,MAAM,cAAc;AAE1G,SAAgB,qBAAqB;AACnC,QAAO,OAAO,UAAU,YAAY;AACpC,QAAO,OAAO,SAAS,WAAW"}
|
package/controls/c2.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"c2.js","names":[],"sources":["../../src/kit/controls/c2.ts"],"sourcesContent":["/**\n * Lane C2 (boolean, select, multiselect, tags, and the scale capsule for a number with a scale): the controls this lane\n * ports, keyed by kit type, for the engine's CONTROLS table. `registerC2Controls()` puts them in and hands the scale\n * control to the number control (lane C1's NUMBER_SCALE hook); a registered type stops drawing the host's legacy control.\n */\nimport type { ComponentType } from \"react\";\nimport type { SchemaType } from \"../schema/types\";\nimport type { ControlProps } from \"../types\";\nimport { CONTROLS } from \"../engine/kit-field\";\nimport { BooleanControl, MultiSelectControl, SelectControl, TagsControl } from \"./choice\";\nimport { NUMBER_SCALE } from \"./number\";\nimport { ScaleControl } from \"./scale\";\n\nexport const C2_CONTROLS: Partial<Record<SchemaType, ComponentType<ControlProps>>> = {\n boolean: BooleanControl,\n select: SelectControl,\n multiselect: MultiSelectControl,\n tags: TagsControl,\n};\n\nexport function registerC2Controls() {\n Object.assign(CONTROLS, C2_CONTROLS);\n NUMBER_SCALE.control = ScaleControl;\n}\n"],"mappings":";;;;;AAaA,IAAa,cAAwE;CACnF,SAAS;CACT,QAAQ;CACR,aAAa;CACb,MAAM;CACP;AAED,SAAgB,qBAAqB;AACnC,QAAO,OAAO,UAAU,YAAY;AACpC,cAAa,UAAU"}
|
package/controls/choice.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"choice.js","names":[],"sources":["../../src/kit/controls/choice.tsx"],"sourcesContent":["/**\n * CHOICE — boolean · select · multiselect · tags (V2 HEAD 9829bf1 kit/controls/choice.tsx, DESIGN 8.10–8.12).\n * Rule (production): few options → segmented, many → dropdown, many values → checkboxes, on/off → switch card.\n * D46: `layout: \"segmented\"` is a request, not a promise. With 4+ options, or labels that would wrap or truncate\n * in a 340px inspector (`fitsSegmented`), it renders the dropdown instead, so every schema follows the rule.\n *\n * Values are the ones production stores, untouched by any adapter (schema.ts plans them AS_IS): boolean, the option's\n * string, a string[] of option values, a string[] of tags. Tags are written the way the backend judges them\n * (tagsValueProblem: trimmed, case-insensitively unique, at most TAG_VALUE_MAX_LENGTH characters), and a tag the\n * control will not add says why under the box instead of vanishing.\n *\n * Option icons are all or none per list (the schema adapter's rule): a list draws icons only when every option names an\n * icon that can be drawn, so labels stay aligned and no option gets a stand-in glyph. The host's glyphs come first\n * (KitServices.IconGlyph, the BetterCMS set the site renders: every stored option icon is one of its names); with no\n * host renderer, the kit's own drawn icons.\n */\nimport * as React from \"react\";\nimport { IconCheck, IconPlus, IconX } from \"@tabler/icons-react\";\nimport { Checkbox, Segmented, Switch } from \"../ui/controls\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../ui/overlay\";\nimport { Select } from \"../ui/select\";\nimport { fitsSegmented } from \"../ui/choice-switch\";\nimport { shortcutHintsOn } from \"../ui/shortcut-hint\";\nimport { cn } from \"../lib/cn\";\nimport { KitIcon, iconKey } from \"../lib/icons\";\nimport type { Option } from \"../schema/types\";\nimport { useKitEnv, useKitServices, type KitServices } from \"../context\";\nimport { dockIconOf } from \"../adapters/icons\";\nimport type { ControlProps } from \"../types\";\nimport { TAG_VALUE_MAX_LENGTH } from \"../adapters/prod-types\";\n\nconst str = (v: unknown) => (typeof v === \"string\" ? v : v == null ? \"\" : String(v));\nconst opts = (o?: Option[]) => o ?? [];\n\n/**\n * Icons for a list: every option's icon when all of them resolve, otherwise none (never a fallback glyph). `Glyph` is\n * the host's renderer (KitServices.IconGlyph): it draws every BetterCMS icon name (the option's kit name read back\n * through dockIconOf); without it, or when a name is not in that set, the kit's own drawn icons.\n */\nexport function optionIcons(options: Option[], className?: string, Glyph?: KitServices[\"IconGlyph\"]): (React.ReactNode | undefined)[] {\n if (options.length === 0) return [];\n const dock = options.map((o) => dockIconOf(o.icon));\n // a block box, as the kit's own <svg> is under preflight: an inline glyph would sit on a line box and grow the row\n if (Glyph && dock.every((n) => n !== undefined)) return dock.map((n) => <Glyph name={n!} className={cn(\"flex\", className)} />);\n const all = options.every((o) => iconKey(o.icon) !== undefined);\n return options.map((o) => (all ? <KitIcon name={o.icon} className={className} /> : undefined));\n}\n\n/** The limit sentence (DESIGN 8.12), shared by multiselect and tags. */\nfunction LimitLine({ max }: { max: number }) {\n return <span className=\"px-0.5 text-kit-xs text-kit-fg-3\">That's the limit of {max}. Remove one to add another.</span>;\n}\n\n/**\n * Roving focus for a radiogroup of buttons (WAI-ARIA radio group, as Segmented does): Tab lands on the selected option\n * (or the first), arrows move and select, Home / End jump.\n */\nfunction useRadioKeys(values: string[], current: string, onPick: (v: string) => void, readOnly?: boolean) {\n const focusable = values.includes(current) ? current : values[0];\n const onKeyDown = (e: React.KeyboardEvent, i: number) => {\n if (readOnly || !values.length) return;\n const n = values.length;\n const next =\n e.key === \"ArrowRight\" || e.key === \"ArrowDown\"\n ? (i + 1) % n\n : e.key === \"ArrowLeft\" || e.key === \"ArrowUp\"\n ? (i - 1 + n) % n\n : e.key === \"Home\"\n ? 0\n : e.key === \"End\"\n ? n - 1\n : -1;\n if (next < 0) return;\n e.preventDefault();\n onPick(values[next]);\n const group = (e.currentTarget as HTMLElement).closest(\"[role=radiogroup]\");\n group?.querySelector<HTMLElement>(`[data-choice-value=\"${CSS.escape(values[next])}\"]`)?.focus();\n };\n return { tabIndexOf: (v: string) => (v === focusable ? 0 : -1), onKeyDown };\n}\n\n/**\n * Adds or removes one id of the control's own in aria-describedby, leaving the ids FieldShell wires (help, issue)\n * in place (as ScaleSlider does).\n */\nexport function useOwnDescription(ref: React.RefObject<HTMLElement | null>, ownId: string | null) {\n const last = React.useRef<string | null>(null);\n React.useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const ids = (el.getAttribute(\"aria-describedby\") ?? \"\").split(\" \").filter((t) => t && t !== last.current && t !== ownId);\n if (ownId) ids.push(ownId);\n if (ids.length) el.setAttribute(\"aria-describedby\", ids.join(\" \"));\n else el.removeAttribute(\"aria-describedby\");\n last.current = ownId;\n });\n}\n\n/** Boolean switch (used inside the switch card the shell draws). Commits immediately. */\nexport function BooleanControl({ field, value, onChange, readOnly, id }: ControlProps) {\n if (field.layout === \"checkbox\")\n return <Checkbox id={id} checked={Boolean(value)} disabled={readOnly} onCheckedChange={(c) => onChange(c === true)} aria-label={field.title} />;\n /* V2's switch is a native <button role=\"switch\"> (Radix); Base UI draws a <span> unless asked for the button */\n return <Switch id={id} checked={Boolean(value)} disabled={readOnly} onCheckedChange={(c) => onChange(c)} aria-label={field.title} nativeButton render={<button type=\"button\" />} />;\n}\n\nexport function SelectControl({ field, value, onChange, readOnly, id }: ControlProps) {\n const { variant } = useKitEnv();\n const { IconGlyph } = useKitServices();\n const options = opts(field.options);\n const v = str(value);\n const fits = fitsSegmented(options.map((o) => o.label));\n const layout = field.layout ?? (fits ? \"segmented\" : \"dropdown\");\n const pick = (n: string) => {\n if (!readOnly && n !== v) onChange(n);\n };\n const keys = useRadioKeys(\n options.map((o) => o.value),\n v,\n pick,\n readOnly,\n );\n\n if (layout === \"segmented\" && fits) {\n const icons = optionIcons(options, \"size-3.5\", IconGlyph);\n return (\n <Segmented\n aria-label={field.title}\n value={v}\n onChange={pick}\n items={options.map((o, i) => ({ value: o.value, label: o.label, icon: icons[i], disabled: readOnly }))}\n className=\"w-full [&>button]:min-w-0 [&>button]:flex-1\"\n />\n );\n }\n if (layout === \"radio\")\n return (\n <div role=\"radiogroup\" id={id} aria-label={field.title} className=\"flex flex-col gap-0.5\">\n {options.map((o, i) => (\n <button\n key={o.value}\n type=\"button\"\n role=\"radio\"\n data-choice-value={o.value}\n aria-checked={o.value === v}\n tabIndex={keys.tabIndexOf(o.value)}\n disabled={readOnly}\n onClick={() => pick(o.value)}\n onKeyDown={(e) => keys.onKeyDown(e, i)}\n className=\"flex items-start gap-2.5 rounded-kit-md px-1.5 py-1.5 text-left hover:bg-kit-hover\"\n >\n <span className={cn(\"mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-full border transition-colors\", o.value === v ? \"border-kit-accent\" : \"border-kit-line-strong\")}>\n {o.value === v ? <span className=\"size-2 rounded-full bg-kit-accent\" /> : null}\n </span>\n <span className=\"min-w-0\">\n <span className=\"block text-kit-sm text-kit-fg\">{o.label}</span>\n {o.description ? <span className=\"block text-kit-xs text-kit-fg-3\">{o.description}</span> : null}\n </span>\n </button>\n ))}\n </div>\n );\n if (layout === \"cards\" || layout === \"grid\") {\n const icons = optionIcons(options, \"size-4\", IconGlyph);\n return (\n <div role=\"radiogroup\" id={id} aria-label={field.title} className={cn(\"grid gap-1.5\", variant === \"document\" ? \"grid-cols-3\" : \"grid-cols-2\")}>\n {options.map((o, i) => {\n const on = o.value === v;\n return (\n <button\n key={o.value}\n type=\"button\"\n role=\"radio\"\n data-choice-value={o.value}\n aria-checked={on}\n tabIndex={keys.tabIndexOf(o.value)}\n disabled={readOnly}\n onClick={() => pick(o.value)}\n onKeyDown={(e) => keys.onKeyDown(e, i)}\n className={cn(\n \"relative flex flex-col items-start gap-1.5 rounded-kit-lg border p-2.5 text-left transition-[border-color,box-shadow] duration-150 focus-visible:outline-offset-[-2px]\",\n on ? \"border-[var(--kit-emphasis-line)] bg-kit-control-bg shadow-kit-xs\" : \"border-kit-line hover:border-kit-line-strong\",\n )}\n >\n {icons[i] ? <span className={cn(\"[&_svg]:size-4\", on ? \"text-kit-fg\" : \"text-kit-fg-3\")}>{icons[i]}</span> : null}\n <span className=\"text-kit-sm font-medium text-kit-fg\">{o.label}</span>\n {o.description ? <span className=\"text-kit-xs leading-4 text-kit-fg-3\">{o.description}</span> : null}\n {on ? <IconCheck aria-hidden className=\"absolute right-2 top-2 size-3.5 text-kit-fg\" stroke={2} /> : null}\n </button>\n );\n })}\n </div>\n );\n }\n const icons = optionIcons(options, undefined, IconGlyph);\n return (\n <Select\n id={id}\n aria-label={field.title}\n size={variant === \"document\" ? \"lg\" : \"md\"}\n value={v || undefined}\n disabled={readOnly}\n onValueChange={pick}\n placeholder={field.placeholder ?? \"Select…\"}\n options={options.map((o, i) => ({ value: o.value, label: o.label, description: o.description, icon: icons[i] }))}\n />\n );\n}\n\nexport function MultiSelectControl({ field, value, onChange, readOnly, id }: ControlProps) {\n const list = Array.isArray(value) ? (value as unknown[]).filter((x): x is string => typeof x === \"string\") : [];\n const options = opts(field.options);\n const max = field.validation?.max;\n const full = max != null && list.length >= max;\n const toggle = (o: string) => {\n if (readOnly) return;\n if (list.includes(o)) onChange(list.filter((x) => x !== o));\n else if (!full) onChange([...list, o]);\n };\n const label = (val: string) => options.find((o) => o.value === val)?.label ?? val;\n /* V2 draws the control bare; the limit line (ours: say why the next pick is refused) wraps it only while it shows */\n const withLimit = (body: React.ReactElement) =>\n full && !readOnly ? (\n <div className=\"flex flex-col gap-1\">\n {body}\n <LimitLine max={max!} />\n </div>\n ) : (\n body\n );\n if (field.layout === \"checkbox\" || field.layout === \"list\")\n return withLimit(\n <>\n <div id={id} role=\"group\" aria-label={field.title} className=\"flex flex-col gap-0.5\">\n {options.map((o) => {\n const on = list.includes(o.value);\n return (\n <label key={o.value} className={cn(\"flex items-center gap-2.5 rounded-kit-md px-1.5 py-1.5\", !on && full ? \"cursor-not-allowed\" : \"cursor-pointer hover:bg-kit-hover\")}>\n <Checkbox checked={on} disabled={readOnly || (!on && full)} onCheckedChange={() => toggle(o.value)} />\n <span className=\"text-kit-sm text-kit-fg\">{o.label}</span>\n </label>\n );\n })}\n </div>\n </>,\n );\n return withLimit(\n <>\n <Popover>\n {/* read-only there is no trigger to carry the field id, so the chip row is the named group */}\n <div\n id={readOnly ? id : undefined}\n role={readOnly ? \"group\" : undefined}\n aria-label={readOnly ? field.title : undefined}\n className=\"flex min-h-8 flex-wrap items-center gap-1 rounded-kit-md border border-kit-line-strong bg-kit-field-bg p-1 transition-colors hover:border-kit-line-strong\">\n {list.map((o) => (\n <span key={o} className=\"inline-flex h-6 items-center gap-1 rounded-kit-md border border-kit-line bg-kit-control-bg pl-2 pr-1 text-kit-sm text-kit-fg shadow-kit-xs\">\n {label(o)}\n {readOnly ? null : (\n <button type=\"button\" aria-label={`Remove ${label(o)}`} onClick={() => toggle(o)} className=\"flex rounded-kit-md p-0.5 text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\">\n <IconX className=\"size-3\" stroke={1.5} />\n </button>\n )}\n </span>\n ))}\n {readOnly ? null : (\n <PopoverTrigger id={id} className=\"inline-flex h-6 items-center gap-1 rounded-kit-md px-1.5 text-kit-sm text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\">\n <IconPlus aria-hidden className=\"size-3.5\" stroke={1.5} />\n {list.length ? \"Add\" : field.placeholder ?? \"Choose…\"}\n </PopoverTrigger>\n )}\n </div>\n <PopoverContent className=\"w-60 p-1\">\n <div role=\"group\" aria-label={field.title}>\n {options.map((o) => {\n const on = list.includes(o.value);\n const blocked = !on && full;\n return (\n <button\n key={o.value}\n type=\"button\"\n role=\"checkbox\"\n aria-checked={on}\n disabled={blocked}\n onClick={() => toggle(o.value)}\n className=\"flex h-8 w-full items-center gap-2 rounded-kit-md px-2 text-left text-kit-sm hover:bg-kit-hover disabled:opacity-40 disabled:hover:bg-transparent\"\n >\n <span className={cn(\"flex size-4 items-center justify-center rounded-kit-md border\", on ? \"border-kit-accent bg-kit-accent text-kit-accent-on\" : \"border-kit-line-strong\")}>\n {on ? <IconCheck aria-hidden className=\"size-3\" stroke={3} /> : null}\n </span>\n {o.label}\n </button>\n );\n })}\n </div>\n {full ? <div className=\"px-2 pb-1 pt-1.5\"><LimitLine max={max!} /></div> : null}\n </PopoverContent>\n </Popover>\n </>,\n );\n}\n\n/** Why a typed tag is not added, or null when it is (the backend's own checks, said in words). */\nexport function tagRefusal(tag: string, list: string[]): string | null {\n if (Array.from(tag).length > TAG_VALUE_MAX_LENGTH) return `A tag can be up to ${TAG_VALUE_MAX_LENGTH} characters.`;\n const folded = tag.toLowerCase();\n const twin = list.find((t) => t.trim().toLowerCase() === folded);\n if (twin !== undefined) return `\"${twin}\" is already a tag.`;\n return null;\n}\n\n/** Chip input. Says so at its limit, and says why a tag was not added, instead of silently dropping it. */\nexport function TagsControl({ field, value, onChange, readOnly, id, onBlur }: ControlProps) {\n const list = Array.isArray(value) ? (value as unknown[]).map((x) => str(x)) : [];\n const [draft, setDraft] = React.useState(\"\");\n const [refusal, setRefusal] = React.useState<string | null>(null);\n const reasonId = React.useId();\n const inputRef = React.useRef<HTMLInputElement>(null);\n useOwnDescription(inputRef, refusal ? reasonId : null);\n const max = field.validation?.max;\n const full = max != null && list.length >= max;\n const add = () => {\n const t = draft.trim().replace(/,$/, \"\").trim();\n if (!t || full) {\n setDraft(\"\");\n setRefusal(null);\n return;\n }\n const why = tagRefusal(t, list);\n if (why) {\n // keep the text so it can be fixed; the reason reads under the box\n setRefusal(why);\n return;\n }\n onChange([...list, t]);\n setDraft(\"\");\n setRefusal(null);\n };\n return (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex min-h-8 flex-wrap items-center gap-1 rounded-kit-md border border-kit-line-strong bg-kit-field-bg p-1 transition-colors focus-within:border-kit-line-strong focus-within:bg-kit-field-bg hover:border-kit-line-strong\">\n {list.map((t, i) => (\n <span key={`${t}-${i}`} className=\"inline-flex h-6 items-center gap-1 rounded-kit-md bg-kit-selected pl-2 pr-1 text-kit-sm text-kit-fg\">\n {t}\n {readOnly ? null : (\n <button type=\"button\" aria-label={`Remove ${t}`} onClick={() => onChange(list.filter((_, j) => j !== i))} className=\"flex rounded-kit-md p-0.5 text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\">\n <IconX className=\"size-3\" stroke={1.5} />\n </button>\n )}\n </span>\n ))}\n {readOnly ? null : (\n <input\n ref={inputRef}\n id={id}\n value={draft}\n disabled={full}\n onChange={(e) => {\n setDraft(e.target.value);\n if (refusal) setRefusal(null);\n }}\n onBlur={() => {\n add();\n onBlur?.();\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \",\") {\n e.preventDefault();\n add();\n } else if (e.key === \"Backspace\" && !draft && list.length) onChange(list.slice(0, -1));\n }}\n placeholder={full ? \"\" : list.length ? \"Add…\" : field.placeholder ?? (shortcutHintsOn() ? \"Type and press Enter\" : \"Add…\")}\n className=\"h-6 min-w-20 flex-1 bg-transparent px-1.5 text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3\"\n />\n )}\n </div>\n {refusal && !readOnly ? (\n <span id={reasonId} role=\"status\" aria-live=\"polite\" className=\"px-0.5 text-kit-xs text-kit-fg-3\">\n {refusal}\n </span>\n ) : null}\n {full && !readOnly ? <LimitLine max={max!} /> : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,IAAM,OAAO,MAAgB,OAAO,MAAM,WAAW,IAAI,KAAK,OAAO,KAAK,OAAO,EAAE;AACnF,IAAM,QAAQ,MAAiB,KAAK,EAAE;;;;;;AAOtC,SAAgB,YAAY,SAAmB,WAAoB,OAAmE;AACpI,KAAI,QAAQ,WAAW,EAAG,QAAO,EAAE;CACnC,MAAM,OAAO,QAAQ,KAAK,MAAM,WAAW,EAAE,KAAK,CAAC;AAEnD,KAAI,SAAS,KAAK,OAAO,MAAM,MAAM,KAAA,EAAU,CAAE,QAAO,KAAK,KAAK,MAAM,oBAAC,OAAD;EAAO,MAAM;EAAI,WAAW,GAAG,QAAQ,UAAU;EAAI,CAAA,CAAC;CAC9H,MAAM,MAAM,QAAQ,OAAO,MAAM,QAAQ,EAAE,KAAK,KAAK,KAAA,EAAU;AAC/D,QAAO,QAAQ,KAAK,MAAO,MAAM,oBAAC,SAAD;EAAS,MAAM,EAAE;EAAiB;EAAa,CAAA,GAAG,KAAA,EAAW;;;AAIhG,SAAS,UAAU,EAAE,OAAwB;AAC3C,QAAO,qBAAC,QAAD;EAAM,WAAU;YAAhB;GAAmD;GAAqB;GAAI;GAAmC;;;;;;;AAOxH,SAAS,aAAa,QAAkB,SAAiB,QAA6B,UAAoB;CACxG,MAAM,YAAY,OAAO,SAAS,QAAQ,GAAG,UAAU,OAAO;CAC9D,MAAM,aAAa,GAAwB,MAAc;AACvD,MAAI,YAAY,CAAC,OAAO,OAAQ;EAChC,MAAM,IAAI,OAAO;EACjB,MAAM,OACJ,EAAE,QAAQ,gBAAgB,EAAE,QAAQ,eAC/B,IAAI,KAAK,IACV,EAAE,QAAQ,eAAe,EAAE,QAAQ,aAChC,IAAI,IAAI,KAAK,IACd,EAAE,QAAQ,SACR,IACA,EAAE,QAAQ,QACR,IAAI,IACJ;AACZ,MAAI,OAAO,EAAG;AACd,IAAE,gBAAgB;AAClB,SAAO,OAAO,MAAM;AACL,IAAE,cAA8B,QAAQ,oBAAoB,EACpE,cAA2B,uBAAuB,IAAI,OAAO,OAAO,MAAM,CAAC,IAAI,EAAE,OAAO;;AAEjG,QAAO;EAAE,aAAa,MAAe,MAAM,YAAY,IAAI;EAAK;EAAW;;;;;;AAO7E,SAAgB,kBAAkB,KAA0C,OAAsB;CAChG,MAAM,OAAO,MAAM,OAAsB,KAAK;AAC9C,OAAM,gBAAgB;EACpB,MAAM,KAAK,IAAI;AACf,MAAI,CAAC,GAAI;EACT,MAAM,OAAO,GAAG,aAAa,mBAAmB,IAAI,IAAI,MAAM,IAAI,CAAC,QAAQ,MAAM,KAAK,MAAM,KAAK,WAAW,MAAM,MAAM;AACxH,MAAI,MAAO,KAAI,KAAK,MAAM;AAC1B,MAAI,IAAI,OAAQ,IAAG,aAAa,oBAAoB,IAAI,KAAK,IAAI,CAAC;MAC7D,IAAG,gBAAgB,mBAAmB;AAC3C,OAAK,UAAU;GACf;;;AAIJ,SAAgB,eAAe,EAAE,OAAO,OAAO,UAAU,UAAU,MAAoB;AACrF,KAAI,MAAM,WAAW,WACnB,QAAO,oBAAC,UAAD;EAAc;EAAI,SAAS,QAAQ,MAAM;EAAE,UAAU;EAAU,kBAAkB,MAAM,SAAS,MAAM,KAAK;EAAE,cAAY,MAAM;EAAS,CAAA;AAEjJ,QAAO,oBAAC,QAAD;EAAY;EAAI,SAAS,QAAQ,MAAM;EAAE,UAAU;EAAU,kBAAkB,MAAM,SAAS,EAAE;EAAE,cAAY,MAAM;EAAO,cAAA;EAAa,QAAQ,oBAAC,UAAD,EAAQ,MAAK,UAAW,CAAA;EAAI,CAAA;;AAGrL,SAAgB,cAAc,EAAE,OAAO,OAAO,UAAU,UAAU,MAAoB;CACpF,MAAM,EAAE,YAAY,WAAW;CAC/B,MAAM,EAAE,cAAc,gBAAgB;CACtC,MAAM,UAAU,KAAK,MAAM,QAAQ;CACnC,MAAM,IAAI,IAAI,MAAM;CACpB,MAAM,OAAO,cAAc,QAAQ,KAAK,MAAM,EAAE,MAAM,CAAC;CACvD,MAAM,SAAS,MAAM,WAAW,OAAO,cAAc;CACrD,MAAM,QAAQ,MAAc;AAC1B,MAAI,CAAC,YAAY,MAAM,EAAG,UAAS,EAAE;;CAEvC,MAAM,OAAO,aACX,QAAQ,KAAK,MAAM,EAAE,MAAM,EAC3B,GACA,MACA,SACD;AAED,KAAI,WAAW,eAAe,MAAM;EAClC,MAAM,QAAQ,YAAY,SAAS,YAAY,UAAU;AACzD,SACE,oBAAC,WAAD;GACE,cAAY,MAAM;GAClB,OAAO;GACP,UAAU;GACV,OAAO,QAAQ,KAAK,GAAG,OAAO;IAAE,OAAO,EAAE;IAAO,OAAO,EAAE;IAAO,MAAM,MAAM;IAAI,UAAU;IAAU,EAAE;GACtG,WAAU;GACV,CAAA;;AAGN,KAAI,WAAW,QACb,QACE,oBAAC,OAAD;EAAK,MAAK;EAAiB;EAAI,cAAY,MAAM;EAAO,WAAU;YAC/D,QAAQ,KAAK,GAAG,MACf,qBAAC,UAAD;GAEE,MAAK;GACL,MAAK;GACL,qBAAmB,EAAE;GACrB,gBAAc,EAAE,UAAU;GAC1B,UAAU,KAAK,WAAW,EAAE,MAAM;GAClC,UAAU;GACV,eAAe,KAAK,EAAE,MAAM;GAC5B,YAAY,MAAM,KAAK,UAAU,GAAG,EAAE;GACtC,WAAU;aAVZ,CAYE,oBAAC,QAAD;IAAM,WAAW,GAAG,iGAAiG,EAAE,UAAU,IAAI,sBAAsB,yBAAyB;cACjL,EAAE,UAAU,IAAI,oBAAC,QAAD,EAAM,WAAU,qCAAsC,CAAA,GAAG;IACrE,CAAA,EACP,qBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,oBAAC,QAAD;KAAM,WAAU;eAAiC,EAAE;KAAa,CAAA,EAC/D,EAAE,cAAc,oBAAC,QAAD;KAAM,WAAU;eAAmC,EAAE;KAAmB,CAAA,GAAG,KACvF;MACA;KAlBF,EAAE,MAkBA,CACT;EACE,CAAA;AAEV,KAAI,WAAW,WAAW,WAAW,QAAQ;EAC3C,MAAM,QAAQ,YAAY,SAAS,UAAU,UAAU;AACvD,SACE,oBAAC,OAAD;GAAK,MAAK;GAAiB;GAAI,cAAY,MAAM;GAAO,WAAW,GAAG,gBAAgB,YAAY,aAAa,gBAAgB,cAAc;aAC1I,QAAQ,KAAK,GAAG,MAAM;IACrB,MAAM,KAAK,EAAE,UAAU;AACvB,WACE,qBAAC,UAAD;KAEE,MAAK;KACL,MAAK;KACL,qBAAmB,EAAE;KACrB,gBAAc;KACd,UAAU,KAAK,WAAW,EAAE,MAAM;KAClC,UAAU;KACV,eAAe,KAAK,EAAE,MAAM;KAC5B,YAAY,MAAM,KAAK,UAAU,GAAG,EAAE;KACtC,WAAW,GACT,0KACA,KAAK,sEAAsE,+CAC5E;eAbH;MAeG,MAAM,KAAK,oBAAC,QAAD;OAAM,WAAW,GAAG,kBAAkB,KAAK,gBAAgB,gBAAgB;iBAAG,MAAM;OAAU,CAAA,GAAG;MAC7G,oBAAC,QAAD;OAAM,WAAU;iBAAuC,EAAE;OAAa,CAAA;MACrE,EAAE,cAAc,oBAAC,QAAD;OAAM,WAAU;iBAAuC,EAAE;OAAmB,CAAA,GAAG;MAC/F,KAAK,oBAAC,WAAD;OAAW,eAAA;OAAY,WAAU;OAA8C,QAAQ;OAAK,CAAA,GAAG;MAC9F;OAlBF,EAAE,MAkBA;KAEX;GACE,CAAA;;CAGV,MAAM,QAAQ,YAAY,SAAS,KAAA,GAAW,UAAU;AACxD,QACE,oBAAC,QAAD;EACM;EACJ,cAAY,MAAM;EAClB,MAAM,YAAY,aAAa,OAAO;EACtC,OAAO,KAAK,KAAA;EACZ,UAAU;EACV,eAAe;EACf,aAAa,MAAM,eAAe;EAClC,SAAS,QAAQ,KAAK,GAAG,OAAO;GAAE,OAAO,EAAE;GAAO,OAAO,EAAE;GAAO,aAAa,EAAE;GAAa,MAAM,MAAM;GAAI,EAAE;EAChH,CAAA;;AAIN,SAAgB,mBAAmB,EAAE,OAAO,OAAO,UAAU,UAAU,MAAoB;CACzF,MAAM,OAAO,MAAM,QAAQ,MAAM,GAAI,MAAoB,QAAQ,MAAmB,OAAO,MAAM,SAAS,GAAG,EAAE;CAC/G,MAAM,UAAU,KAAK,MAAM,QAAQ;CACnC,MAAM,MAAM,MAAM,YAAY;CAC9B,MAAM,OAAO,OAAO,QAAQ,KAAK,UAAU;CAC3C,MAAM,UAAU,MAAc;AAC5B,MAAI,SAAU;AACd,MAAI,KAAK,SAAS,EAAE,CAAE,UAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,CAAC;WAClD,CAAC,KAAM,UAAS,CAAC,GAAG,MAAM,EAAE,CAAC;;CAExC,MAAM,SAAS,QAAgB,QAAQ,MAAM,MAAM,EAAE,UAAU,IAAI,EAAE,SAAS;CAE9E,MAAM,aAAa,SACjB,QAAQ,CAAC,WACP,qBAAC,OAAD;EAAK,WAAU;YAAf,CACG,MACD,oBAAC,WAAD,EAAgB,KAAQ,CAAA,CACpB;MAEN;AAEJ,KAAI,MAAM,WAAW,cAAc,MAAM,WAAW,OAClD,QAAO,UACL,oBAAA,UAAA,EAAA,UACE,oBAAC,OAAD;EAAS;EAAI,MAAK;EAAQ,cAAY,MAAM;EAAO,WAAU;YAC1D,QAAQ,KAAK,MAAM;GAClB,MAAM,KAAK,KAAK,SAAS,EAAE,MAAM;AACjC,UACE,qBAAC,SAAD;IAAqB,WAAW,GAAG,0DAA0D,CAAC,MAAM,OAAO,uBAAuB,oCAAoC;cAAtK,CACE,oBAAC,UAAD;KAAU,SAAS;KAAI,UAAU,YAAa,CAAC,MAAM;KAAO,uBAAuB,OAAO,EAAE,MAAM;KAAI,CAAA,EACtG,oBAAC,QAAD;KAAM,WAAU;eAA2B,EAAE;KAAa,CAAA,CACpD;MAHI,EAAE,MAGN;IAEV;EACE,CAAA,EACL,CAAA,CACJ;AACH,QAAO,UACL,oBAAA,UAAA,EAAA,UACE,qBAAC,SAAD,EAAA,UAAA,CAEE,qBAAC,OAAD;EACE,IAAI,WAAW,KAAK,KAAA;EACpB,MAAM,WAAW,UAAU,KAAA;EAC3B,cAAY,WAAW,MAAM,QAAQ,KAAA;EACrC,WAAU;YAJZ,CAKG,KAAK,KAAK,MACT,qBAAC,QAAD;GAAc,WAAU;aAAxB,CACG,MAAM,EAAE,EACR,WAAW,OACV,oBAAC,UAAD;IAAQ,MAAK;IAAS,cAAY,UAAU,MAAM,EAAE;IAAI,eAAe,OAAO,EAAE;IAAE,WAAU;cAC1F,oBAAC,OAAD;KAAO,WAAU;KAAS,QAAQ;KAAO,CAAA;IAClC,CAAA,CAEN;KAPI,EAOJ,CACP,EACD,WAAW,OACV,qBAAC,gBAAD;GAAoB;GAAI,WAAU;aAAlC,CACE,oBAAC,UAAD;IAAU,eAAA;IAAY,WAAU;IAAW,QAAQ;IAAO,CAAA,EACzD,KAAK,SAAS,QAAQ,MAAM,eAAe,UAC7B;KAEf;KACN,qBAAC,gBAAD;EAAgB,WAAU;YAA1B,CACE,oBAAC,OAAD;GAAK,MAAK;GAAQ,cAAY,MAAM;aACjC,QAAQ,KAAK,MAAM;IAClB,MAAM,KAAK,KAAK,SAAS,EAAE,MAAM;AAEjC,WACE,qBAAC,UAAD;KAEE,MAAK;KACL,MAAK;KACL,gBAAc;KACd,UAPY,CAAC,MAAM;KAQnB,eAAe,OAAO,EAAE,MAAM;KAC9B,WAAU;eAPZ,CASE,oBAAC,QAAD;MAAM,WAAW,GAAG,iEAAiE,KAAK,uDAAuD,yBAAyB;gBACvK,KAAK,oBAAC,WAAD;OAAW,eAAA;OAAY,WAAU;OAAS,QAAQ;OAAK,CAAA,GAAG;MAC3D,CAAA,EACN,EAAE,MACI;OAZF,EAAE,MAYA;KAEX;GACE,CAAA,EACL,OAAO,oBAAC,OAAD;GAAK,WAAU;aAAmB,oBAAC,WAAD,EAAgB,KAAQ,CAAA;GAAM,CAAA,GAAG,KAC5D;IACT,EAAA,CAAA,EACT,CAAA,CACJ;;;AAIH,SAAgB,WAAW,KAAa,MAA+B;AACrE,KAAI,MAAM,KAAK,IAAI,CAAC,SAAA,GAA+B,QAAO;CAC1D,MAAM,SAAS,IAAI,aAAa;CAChC,MAAM,OAAO,KAAK,MAAM,MAAM,EAAE,MAAM,CAAC,aAAa,KAAK,OAAO;AAChE,KAAI,SAAS,KAAA,EAAW,QAAO,IAAI,KAAK;AACxC,QAAO;;;AAIT,SAAgB,YAAY,EAAE,OAAO,OAAO,UAAU,UAAU,IAAI,UAAwB;CAC1F,MAAM,OAAO,MAAM,QAAQ,MAAM,GAAI,MAAoB,KAAK,MAAM,IAAI,EAAE,CAAC,GAAG,EAAE;CAChF,MAAM,CAAC,OAAO,YAAY,MAAM,SAAS,GAAG;CAC5C,MAAM,CAAC,SAAS,cAAc,MAAM,SAAwB,KAAK;CACjE,MAAM,WAAW,MAAM,OAAO;CAC9B,MAAM,WAAW,MAAM,OAAyB,KAAK;AACrD,mBAAkB,UAAU,UAAU,WAAW,KAAK;CACtD,MAAM,MAAM,MAAM,YAAY;CAC9B,MAAM,OAAO,OAAO,QAAQ,KAAK,UAAU;CAC3C,MAAM,YAAY;EAChB,MAAM,IAAI,MAAM,MAAM,CAAC,QAAQ,MAAM,GAAG,CAAC,MAAM;AAC/C,MAAI,CAAC,KAAK,MAAM;AACd,YAAS,GAAG;AACZ,cAAW,KAAK;AAChB;;EAEF,MAAM,MAAM,WAAW,GAAG,KAAK;AAC/B,MAAI,KAAK;AAEP,cAAW,IAAI;AACf;;AAEF,WAAS,CAAC,GAAG,MAAM,EAAE,CAAC;AACtB,WAAS,GAAG;AACZ,aAAW,KAAK;;AAElB,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,KAAK,KAAK,GAAG,MACZ,qBAAC,QAAD;KAAwB,WAAU;eAAlC,CACG,GACA,WAAW,OACV,oBAAC,UAAD;MAAQ,MAAK;MAAS,cAAY,UAAU;MAAK,eAAe,SAAS,KAAK,QAAQ,GAAG,MAAM,MAAM,EAAE,CAAC;MAAE,WAAU;gBAClH,oBAAC,OAAD;OAAO,WAAU;OAAS,QAAQ;OAAO,CAAA;MAClC,CAAA,CAEN;OAPI,GAAG,EAAE,GAAG,IAOZ,CACP,EACD,WAAW,OACV,oBAAC,SAAD;KACE,KAAK;KACD;KACJ,OAAO;KACP,UAAU;KACV,WAAW,MAAM;AACf,eAAS,EAAE,OAAO,MAAM;AACxB,UAAI,QAAS,YAAW,KAAK;;KAE/B,cAAc;AACZ,WAAK;AACL,gBAAU;;KAEZ,YAAY,MAAM;AAChB,UAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,SAAE,gBAAgB;AAClB,YAAK;iBACI,EAAE,QAAQ,eAAe,CAAC,SAAS,KAAK,OAAQ,UAAS,KAAK,MAAM,GAAG,GAAG,CAAC;;KAExF,aAAa,OAAO,KAAK,KAAK,SAAS,SAAS,MAAM,gBAAgB,iBAAiB,GAAG,yBAAyB;KACnH,WAAU;KACV,CAAA,CAEA;;GACL,WAAW,CAAC,WACX,oBAAC,QAAD;IAAM,IAAI;IAAU,MAAK;IAAS,aAAU;IAAS,WAAU;cAC5D;IACI,CAAA,GACL;GACH,QAAQ,CAAC,WAAW,oBAAC,WAAD,EAAgB,KAAQ,CAAA,GAAG;GAC5C"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"code-register.js","names":[],"sources":["../../src/kit/controls/code-register.ts"],"sourcesContent":["/** Lane C3: the code field in the engine's dispatch table (one line per type; merge with other lanes by line). */\nimport { CONTROLS } from \"../engine/kit-field\";\nimport { CodeControl } from \"./code\";\n\nCONTROLS.code = CodeControl;\n"],"mappings":";;;;AAIA,SAAS,OAAO"}
|
package/controls/code.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"code.js","names":[],"sources":["../../src/kit/controls/code.tsx"],"sourcesContent":["/**\n * CODE — the code field (DESIGN 8.21), V2 controls/misc.tsx (CodeSurface, CodeControl) fitted to what prod stores.\n *\n * Values (backend reference-validation `code`, adapters/values.ts codeToProd):\n * \"<p>hi</p>\" a bare string, kept a string\n * { language?: \"html\", code: \"…\" } the object form; only `code` and `language` are written back\n * The language list sits in the surface header. Picking one writes the object form; a value that never changes its\n * language keeps the shape it was stored in. A value over CODE_MAX_LENGTH characters is refused with the reason.\n *\n * Panel: a one-line summary button that opens a `lg` dialog editing a draft (Cancel / Done). Document: the surface\n * inline. The surface: mono 12/20 textarea with line numbers, Tab inserts two spaces (Shift+Tab leaves the field),\n * Copy, and for JSON a Format action and a live \"Invalid JSON · {reason}\" footer (json.tsx).\n */\nimport * as React from \"react\";\nimport { IconAlertTriangle, IconBraces, IconCode, IconMaximize } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { isObj } from \"../lib/path\";\nimport { useKitEnv, useKitServices } from \"../context\";\nimport { CODE_MAX_LENGTH } from \"../adapters/prod-types\";\nimport type { ControlProps } from \"../types\";\nimport { Button } from \"../ui/button\";\nimport { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader } from \"../ui/overlay\";\nimport { Select } from \"../ui/select\";\n\nconst CODE_LANGUAGES: { value: string; label: string }[] = [\n { value: \"html\", label: \"HTML\" },\n { value: \"css\", label: \"CSS\" },\n { value: \"js\", label: \"JS\" },\n { value: \"ts\", label: \"TS\" },\n { value: \"json\", label: \"JSON\" },\n { value: \"liquid\", label: \"Liquid\" },\n { value: \"markdown\", label: \"Markdown\" },\n { value: \"shell\", label: \"Shell\" },\n];\nconst PLAIN = \"plain\";\n\n/** The picker: Plain text, then the field's allowed languages (or the built-in list), then the stored one if it is outside them. */\nfunction languageOptions(language: string | undefined, allowed: string[] | undefined) {\n const list = allowed ? allowed.map((v) => CODE_LANGUAGES.find((l) => l.value === v) ?? { value: v, label: v }) : CODE_LANGUAGES;\n return [{ value: PLAIN, label: \"Plain text\" }, ...list, ...(language && !list.some((l) => l.value === language) ? [{ value: language, label: language }] : [])];\n}\n\n/** Why a JSON text does not parse (\"\" when it does, or is empty). */\nexport function jsonProblem(text: string): string {\n if (!text.trim()) return \"\";\n try {\n JSON.parse(text);\n return \"\";\n } catch (e) {\n return (e as Error).message.replace(/^JSON\\.parse: /, \"\");\n }\n}\n\n/* ── The surface ──────────────────────────────────────────────────────── */\nexport interface CodeSurfaceProps {\n /** \"json\": the JSON header, Format and the parse footer. \"code\": the language list. */\n kind: \"json\" | \"code\";\n value: string;\n onChange: (v: string) => void;\n /** code: the language shown in the header (\"\" = none) and what picking one does; absent = no list */\n language?: string;\n onLanguage?: (language: string) => void;\n /** code: the only languages the field allows (its config.languages); absent = the built-in list */\n languages?: string[];\n readOnly?: boolean;\n id?: string;\n invalid?: boolean;\n minRows?: number;\n label?: string;\n describedBy?: string;\n}\n\nexport function CodeSurface({ kind, value, onChange, language, onLanguage, languages, readOnly, id, invalid, minRows = 8, label, describedBy }: CodeSurfaceProps) {\n const { toast } = useKitServices();\n const lines = Math.max(minRows, value.split(\"\\n\").length);\n const problem = kind === \"json\" ? jsonProblem(value) : value.length > CODE_MAX_LENGTH ? `Code can hold up to ${CODE_MAX_LENGTH.toLocaleString(\"en-US\")} characters; this has ${value.length.toLocaleString(\"en-US\")}.` : \"\";\n const footerId = id ? `${id}-problem` : undefined;\n const format = () => {\n try {\n onChange(JSON.stringify(JSON.parse(value), null, 2));\n toast?.success(\"JSON formatted\");\n } catch {\n toast?.(\"Fix the JSON before formatting\");\n }\n };\n const copy = () => {\n void navigator.clipboard?.writeText(value);\n toast?.success(\"Copied\");\n };\n return (\n <div className={cn(\"overflow-hidden rounded-kit-lg border bg-kit-subtle transition-colors\", invalid || problem ? \"border-[var(--kit-field-invalid)]\" : \"border-kit-line focus-within:border-kit-field-border-focus\")}>\n <div className=\"flex h-8 items-center justify-between border-b border-kit-line px-2\">\n {kind === \"json\" ? (\n <span className=\"px-1 font-kit-mono text-kit-xs text-kit-fg-3\">JSON</span>\n ) : onLanguage ? (\n <Select\n aria-label=\"Code language\"\n size=\"sm\"\n variant=\"ghost\"\n disabled={readOnly}\n value={language || PLAIN}\n onValueChange={(l) => onLanguage(l === PLAIN ? \"\" : l)}\n options={languageOptions(language, languages)}\n />\n ) : (\n <span className=\"px-1 font-kit-mono text-kit-xs text-kit-fg-3\">Code</span>\n )}\n <div className=\"flex items-center gap-1\">\n {kind === \"json\" ? (\n <button type=\"button\" disabled={readOnly} className=\"rounded-kit-md px-1.5 py-0.5 text-kit-xs text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg disabled:opacity-50\" onClick={format}>\n Format\n </button>\n ) : null}\n <button type=\"button\" className=\"rounded-kit-md px-1.5 py-0.5 text-kit-xs text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg\" onClick={copy}>\n Copy\n </button>\n </div>\n </div>\n <div className=\"flex max-h-[60vh] overflow-auto font-kit-mono text-kit-xs leading-5\">\n <div aria-hidden className=\"select-none border-r border-kit-line bg-kit-subtle px-2 py-2 text-right text-kit-fg-4\">\n {Array.from({ length: lines }).map((_, i) => (\n <div key={i}>{i + 1}</div>\n ))}\n </div>\n <textarea\n id={id}\n spellCheck={false}\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n value={value}\n readOnly={readOnly}\n aria-invalid={invalid || !!problem || undefined}\n aria-label={label}\n aria-describedby={[describedBy, problem ? footerId : undefined].filter(Boolean).join(\" \") || undefined}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Tab\" && !e.shiftKey && !readOnly) {\n e.preventDefault();\n const el = e.currentTarget;\n const s = el.selectionStart;\n onChange(value.slice(0, s) + \" \" + value.slice(el.selectionEnd));\n requestAnimationFrame(() => el.setSelectionRange(s + 2, s + 2));\n }\n }}\n style={{ height: lines * 20 + 16 }}\n className=\"min-w-0 flex-1 resize-none bg-kit-field-bg px-3 py-2 text-kit-fg outline-none\"\n />\n </div>\n {problem ? (\n <div id={footerId} className=\"border-t border-kit-danger-line bg-kit-danger-soft px-3 py-1.5 text-kit-xs text-kit-danger-fg\">\n {kind === \"json\" ? `Invalid JSON · ${problem}` : problem}\n </div>\n ) : null}\n </div>\n );\n}\n\n/* ── Panel: summary button + dialog over a draft ─────────────────────── */\nexport function CodeDialogField({\n kind, title, description, text, readOnly, id, invalid, language, languages, onDone,\n}: {\n kind: \"json\" | \"code\";\n title: string;\n description?: string;\n text: string;\n readOnly?: boolean;\n id: string;\n invalid?: boolean;\n language?: string;\n languages?: string[];\n /** commit the draft; returns the reason it can't be saved, or null when saved */\n onDone: (draft: string, language: string | undefined) => string | null;\n}) {\n const { toast } = useKitServices();\n const [open, setOpen] = React.useState(false);\n const [draft, setDraft] = React.useState(text);\n const [lang, setLang] = React.useState(language);\n const [refusal, setRefusal] = React.useState<string | null>(null);\n const first = text.split(\"\\n\").find((l) => l.trim()) ?? \"\";\n const Icon = kind === \"json\" ? IconBraces : IconCode;\n return (\n <>\n <button\n id={id}\n type=\"button\"\n aria-haspopup=\"dialog\"\n aria-invalid={invalid || undefined}\n onClick={() => {\n setDraft(text);\n setLang(language);\n setRefusal(null);\n setOpen(true);\n }}\n className={cn(\n \"group/code flex w-full min-w-0 items-center gap-2 rounded-kit-md border bg-kit-subtle px-2.5 py-2 text-left outline-none transition-colors hover:border-kit-line-strong focus-visible:outline-2 focus-visible:outline-kit-focus-ring\",\n invalid ? \"border-[var(--kit-field-invalid)]\" : \"border-kit-line\",\n )}\n >\n <Icon className=\"size-4 shrink-0 text-kit-fg-3\" stroke={1.5} aria-hidden />\n <span className={cn(\"min-w-0 flex-1 truncate font-kit-mono text-kit-xs\", first ? \"text-kit-fg-2\" : \"text-kit-fg-3\")}>{first || \"Empty\"}</span>\n <span className=\"shrink-0 text-kit-2xs tabular-nums text-kit-fg-3\">{text ? `${text.split(\"\\n\").length} lines` : \"\"}</span>\n <IconMaximize className=\"size-3.5 shrink-0 text-kit-fg-3 group-hover/code:text-kit-fg\" stroke={1.5} aria-hidden />\n </button>\n <Modal open={open} onOpenChange={setOpen}>\n <ModalContent size=\"lg\">\n <ModalHeader title={title} description={description ?? (kind === \"json\" ? \"Structured data for developers\" : \"Custom code\")} />\n <ModalBody>\n <CodeSurface kind={kind} value={draft} onChange={setDraft} language={lang ?? \"\"} onLanguage={kind === \"code\" ? setLang : undefined} languages={languages} readOnly={readOnly} minRows={14} label={title} />\n {refusal ? (\n <p role=\"alert\" className=\"mt-2 flex items-start gap-1.5 text-kit-xs text-kit-danger-fg\">\n <IconAlertTriangle className=\"mt-0.5 size-3.5 shrink-0\" stroke={1.5} aria-hidden />\n {refusal}\n </p>\n ) : null}\n </ModalBody>\n <ModalFooter>\n <span className=\"text-kit-xs text-kit-fg-3\">Esc to close</span>\n <span className=\"mr-auto\" aria-hidden />\n <Button variant=\"ghost\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button\n variant=\"primary\"\n disabled={readOnly}\n onClick={() => {\n const why = onDone(draft, lang);\n if (why) {\n setRefusal(why);\n toast?.(kind === \"json\" ? \"Invalid JSON\" : \"Can't save this code\", { description: \"Fix it before saving.\" });\n return;\n }\n setOpen(false);\n }}\n >\n Done\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n </>\n );\n}\n\n/* ── The control ──────────────────────────────────────────────────────── */\ntype CodeRead = { ok: true; code: string; language?: string; object: boolean } | { ok: false };\nfunction readCode(v: unknown): CodeRead {\n if (v == null) return { ok: true, code: \"\", object: false };\n if (typeof v === \"string\") return { ok: true, code: v, object: false };\n if (isObj(v) && typeof v.code === \"string\" && (v.language === undefined || typeof v.language === \"string\")) return { ok: true, code: v.code, language: v.language as string | undefined, object: true };\n return { ok: false };\n}\n\n/** The stored shape for edited code: a string stays a string until a language is picked; the object keeps its form. */\nfunction codeValue(prev: CodeRead & { ok: true }, code: string, language: string | undefined): string | { language?: string; code: string } {\n const lang = language ?? prev.language ?? \"\";\n if (!prev.object && !lang) return code;\n return lang ? { language: lang, code } : { code };\n}\nconst tooLong = (code: string) => (code.length > CODE_MAX_LENGTH ? `Code can hold up to ${CODE_MAX_LENGTH.toLocaleString(\"en-US\")} characters; this has ${code.length.toLocaleString(\"en-US\")}.` : null);\n\nexport function CodeControl({ field, value, onChange, readOnly, id, invalid }: ControlProps) {\n const { variant } = useKitEnv();\n const [refused, setRefused] = React.useState<string | null>(null);\n const read = readCode(value);\n if (!read.ok) return <UnreadableValue id={id} title={field.title} kind=\"code\" value={value} />;\n if (variant === \"document\")\n return (\n <div className=\"flex flex-col gap-1.5\">\n <CodeSurface\n kind=\"code\"\n id={id}\n invalid={invalid || !!refused}\n readOnly={readOnly}\n value={read.code}\n language={read.language ?? \"\"}\n languages={field.languages}\n onChange={(code) => {\n const why = tooLong(code);\n setRefused(why);\n if (!why) onChange(codeValue(read, code, undefined));\n }}\n onLanguage={(l) => onChange(codeValue(read, read.code, l))}\n />\n {refused ? (\n <p role=\"alert\" className=\"text-kit-xs text-kit-danger-fg\">\n {refused}\n </p>\n ) : null}\n </div>\n );\n return (\n <CodeDialogField\n kind=\"code\"\n id={id}\n title={field.title}\n description={field.description || undefined}\n text={read.code}\n language={read.language}\n languages={field.languages}\n readOnly={readOnly}\n invalid={invalid}\n onDone={(draft, lang) => {\n const why = tooLong(draft);\n if (why) return why;\n const next = codeValue(read, draft, lang);\n if (draft !== read.code || (lang ?? \"\") !== (read.language ?? \"\")) onChange(next);\n return null;\n }}\n />\n );\n}\n\n/** A stored value the control cannot read: named, shown, kept as it is (never replaced by a stray edit). */\nexport function UnreadableValue({ id, title, kind, value }: { id: string; title: string; kind: string; value: unknown }) {\n let raw: string;\n try {\n raw = typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n } catch {\n raw = String(value);\n }\n return (\n <output\n id={id}\n tabIndex={0}\n data-slot={`${kind}-unreadable`}\n className=\"flex min-w-0 items-start gap-2 rounded-kit-md border border-dashed border-kit-line-strong bg-kit-subtle px-2.5 py-2 text-kit-xs text-kit-fg-2 outline-none focus-visible:outline-2 focus-visible:outline-kit-focus-ring\"\n >\n <IconAlertTriangle className=\"mt-0.5 size-3.5 shrink-0 text-kit-warning-fg\" stroke={1.5} aria-hidden />\n <span className=\"min-w-0\">\n {title} holds a value this {kind} editor can't read, so it is kept as it is:{\" \"}\n <span className=\"block max-h-24 overflow-auto whitespace-pre-wrap break-all font-kit-mono text-kit-fg\">{raw}</span>\n </span>\n </output>\n );\n}\n"],"mappings":"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"}
|
package/controls/color.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"color.js","names":[],"sources":["../../src/kit/controls/color.tsx"],"sourcesContent":["/**\n * COLOR — site-palette swatches first, then a custom colour (V2 HEAD 9829bf1 kit/controls/misc.tsx, DESIGN §8.13).\n *\n * Stored shape (prod `color`): a hex string the backend accepts — #RGB, #RRGGBB or #RRGGBBAA — or null when cleared.\n * The hex box keeps what you type as a draft and writes it only once it is a hex colour; while it is not, the box is\n * marked invalid and says why, so a half-typed \"#12\" never reaches the save (the API would refuse it).\n * The palette is the host's (`env.palette`, the project's brand colours); with none, the popover offers the custom\n * picker alone.\n */\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useKitEnv } from \"../context\";\nimport { Input } from \"../ui/input\";\nimport { Popover, PopoverContent, PopoverTrigger, Tooltip } from \"../ui/overlay\";\nimport type { ControlProps } from \"../types\";\nimport { str, TEXT_FOCUS } from \"./text\";\n\nexport const HEX_COLOR = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;\n/** #RGB / #RRGGBBAA → #RRGGBB for the native picker, which takes only six digits. */\nexport function pickerHex(v: string): string {\n if (!HEX_COLOR.test(v)) return \"#000000\";\n const h = v.slice(1);\n const six = h.length === 3 ? h.split(\"\").map((c) => c + c).join(\"\") : h.slice(0, 6);\n return `#${six.toLowerCase()}`;\n}\n\nexport function ColorControl({ field, value, onChange, readOnly, id, invalid, onBlur }: ControlProps) {\n const { palette } = useKitEnv();\n const v = str(value);\n const [draft, setDraft] = React.useState<string | null>(null);\n const shown = draft ?? v;\n const bad = draft !== null && draft.trim() !== \"\" && !HEX_COLOR.test(draft.trim());\n const sw = palette.find((p) => p.value.toLowerCase() === v.toLowerCase());\n const errId = React.useId();\n const write = (next: string | null) => {\n setDraft(null);\n onChange(next);\n };\n return (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-2\">\n <Popover>\n <PopoverTrigger\n disabled={readOnly}\n aria-label={`Choose a colour for ${field.title}`}\n render={\n <button\n type=\"button\"\n className=\"flex h-8 min-w-0 flex-1 items-center gap-2 rounded-kit-md border border-kit-field-border bg-kit-field-bg pl-1 pr-2.5 text-left text-kit-sm shadow-kit-field transition-colors hover:border-kit-field-border-hover disabled:cursor-not-allowed disabled:opacity-60 data-[popup-open]:border-kit-field-border-focus\"\n />\n }\n >\n <span className=\"size-6 shrink-0 rounded-kit-md border border-kit-swatch-ring shadow-kit-xs\" style={{ background: v || \"transparent\" }} />\n <span className={cn(\"min-w-0 flex-1 truncate\", v ? \"text-kit-fg\" : \"text-kit-fg-3\")}>{sw ? sw.name : v ? \"Custom\" : \"No color\"}</span>\n {sw?.token ? <span className=\"truncate font-kit-mono text-kit-2xs text-kit-fg-3\">{sw.token}</span> : null}\n </PopoverTrigger>\n <PopoverContent className=\"w-64\">\n {palette.length ? (\n <>\n <div className=\"mb-2 text-kit-xs text-kit-fg-3\">Site palette</div>\n <div className=\"grid grid-cols-5 gap-2\">\n {palette.map((s) => (\n <Tooltip key={s.value} content={`${s.name}${s.token ? ` · ${s.token}` : \"\"}`}>\n <button\n type=\"button\"\n aria-label={s.name}\n aria-pressed={s.value.toLowerCase() === v.toLowerCase()}\n onClick={() => write(s.value)}\n className={cn(\n \"relative size-9 rounded-kit-md border border-kit-swatch-ring transition-transform hover:scale-105\",\n s.value.toLowerCase() === v.toLowerCase() && \"ring-2 ring-kit-fg ring-offset-2 ring-offset-kit-surface\",\n )}\n style={{ background: s.value }}\n />\n </Tooltip>\n ))}\n </div>\n </>\n ) : null}\n <label className={cn(\"flex items-center gap-2 text-kit-xs text-kit-fg-3\", palette.length && \"mt-3 border-t border-kit-line pt-3\")}>\n Custom\n <input\n type=\"color\"\n value={pickerHex(v)}\n onChange={(e) => write(e.target.value.toUpperCase())}\n className=\"h-7 w-full cursor-pointer rounded-kit-md border border-kit-line bg-transparent\"\n />\n </label>\n {v ? (\n <button type=\"button\" onClick={() => write(null)} className=\"mt-2 w-full rounded-kit-md px-1.5 py-1 text-left text-kit-xs text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg\">\n No color\n </button>\n ) : null}\n </PopoverContent>\n </Popover>\n <Input\n id={id}\n value={shown}\n readOnly={readOnly}\n aria-invalid={invalid || bad}\n aria-describedby={bad ? errId : undefined}\n placeholder=\"#RRGGBB\"\n spellCheck={false}\n onChange={(e) => {\n const t = e.target.value.trim();\n if (t === \"\") write(null);\n else if (HEX_COLOR.test(t)) write(t);\n else setDraft(e.target.value);\n }}\n onBlur={onBlur}\n className={cn(TEXT_FOCUS, \"w-28 shrink-0 font-kit-mono\")}\n />\n </div>\n {bad ? (\n <p id={errId} role=\"alert\" className=\"text-kit-xs text-kit-danger-fg\">\n “{draft!.trim()}” isn't a hex color, so it isn't saved. Use #RGB or #RRGGBB.\n </p>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"date-register.js","names":[],"sources":["../../src/kit/controls/date-register.ts"],"sourcesContent":["/** Lane C3: date and datetime in the engine's dispatch table (one line per type; merge with other lanes by line). */\nimport { CONTROLS } from \"../engine/kit-field\";\nimport { DateControl } from \"./date\";\n\nCONTROLS.date = DateControl;\nCONTROLS.datetime = DateControl;\n"],"mappings":";;;;AAIA,SAAS,OAAO;AAChB,SAAS,WAAW"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"date-zone.js","names":[],"sources":["../../src/kit/controls/date-zone.ts"],"sourcesContent":["/**\n * DATE / DATETIME values and time zones (DESIGN 6.4, D43), ported from V2 controls/date.tsx and fitted to what the\n * backend and the value adapters keep (adapters/values.ts datetimeToProd / datetimeFromProd, backend\n * parseDateField / parseDatetimeField).\n *\n * What the control writes, per field (`zonePolicy`):\n *\n * date (any timezone) \"2026-10-14\" a prod `date` without includeTime refuses a \"T\"\n * datetime, timezone false \"2026-10-14T09:00:00\" floating wall time\n * datetime, true / unset \"2026-10-14T09:00:00+05:30\" the zone the editor picked lives in the offset:\n * datetime, \"site\" \"2026-10-14T09:00:00-07:00\" prod keeps no [Zone] (the adapter names a kept\n * one as lost and the dock refuses the write)\n * datetime, \"fixed:<IANA>\" \"2026-10-14T09:00:00-04:00[America/New_York]\" the adapter checks the zone against\n * config.timezone, stores the instant, and\n * reads it back with the same [Zone]\n *\n * Seconds are always written (prod refuses a seconds-less datetime; the adapter names it \"format\"). The offset is the\n * zone's offset AT the wall time the author typed (two passes, so it is right on both sides of a clock change), and a\n * wall time that a clock change skips is refused with a named reason, never shifted silently.\n */\nimport * as React from \"react\";\nimport { useKitServices } from \"../context\";\nimport type { FieldSchema } from \"../schema/types\";\n\n/* ── The site zone (a host service) ───────────────────────────────────── */\ndeclare module \"../context\" {\n interface KitServices {\n /**\n * The site's IANA zone (Project.localeConfig.timeZone, Settings › General): where a new date/time value starts and\n * what timezone \"site\" locks to. The dock passes `useSiteTimeZone().zone` when its source is \"site\". Absent or not\n * a zone → the viewer's browser zone, which the picker names \"Your time zone\".\n */\n siteTimeZone?: string;\n }\n}\n\nexport type ZoneSource = \"site\" | \"browser\";\n\nexport function validZone(z: unknown): z is string {\n if (typeof z !== \"string\" || !z) return false;\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: z });\n return true;\n } catch {\n return false;\n }\n}\n\n/** ICU still lists some zones under their old names; people read the current ones (Kolkata, not Calcutta). */\nconst MODERN: Readonly<Record<string, string>> = {\n \"Asia/Calcutta\": \"Asia/Kolkata\",\n \"Asia/Katmandu\": \"Asia/Kathmandu\",\n \"Asia/Saigon\": \"Asia/Ho_Chi_Minh\",\n \"Asia/Rangoon\": \"Asia/Yangon\",\n \"Europe/Kiev\": \"Europe/Kyiv\",\n \"America/Godthab\": \"America/Nuuk\",\n \"Atlantic/Faeroe\": \"Atlantic/Faroe\",\n \"America/Buenos_Aires\": \"America/Argentina/Buenos_Aires\",\n};\nexport const modernZone = (z: string) => (MODERN[z] && validZone(MODERN[z]) ? MODERN[z] : z);\n\nexport function browserZone(): string {\n try {\n return modernZone(Intl.DateTimeFormat().resolvedOptions().timeZone || \"UTC\");\n } catch {\n return \"UTC\";\n }\n}\n\n/** The zone a new value starts in: the site's, else the browser's. `source` names which one. */\nexport function useDefaultZone(): { zone: string; source: ZoneSource } {\n const site = useKitServices().siteTimeZone;\n return React.useMemo(() => (validZone(site) ? { zone: site, source: \"site\" as const } : { zone: browserZone(), source: \"browser\" as const }), [site]);\n}\n\n/* ── Policy ───────────────────────────────────────────────────────────── */\nexport type ZoneMode = \"pick\" | \"site\" | \"fixed\" | \"none\";\n/**\n * What the schema allows. A `date` never carries a zone here: prod stores a date as \"YYYY-MM-DD\" and refuses a time on\n * a date field without includeTime, so a zoned date (V2 allowed one) would be refused at save.\n */\nexport function zonePolicy(field: Pick<FieldSchema, \"type\" | \"timezone\">): { mode: ZoneMode; zone?: string } {\n if (field.type !== \"datetime\") return { mode: \"none\" };\n const t = field.timezone ?? true;\n if (t === false) return { mode: \"none\" };\n if (t === \"site\") return { mode: \"site\" };\n if (typeof t === \"string\" && t.startsWith(\"fixed:\")) {\n const z = t.slice(6);\n return validZone(z) ? { mode: \"fixed\", zone: z } : { mode: \"site\" };\n }\n return { mode: \"pick\" };\n}\n\n/* ── Offsets ──────────────────────────────────────────────────────────── */\nconst pad = (n: number) => String(Math.abs(Math.trunc(n))).padStart(2, \"0\");\n\n/** The zone's UTC offset in minutes at an instant (+330 for Kolkata). */\nexport function offsetMinutes(zone: string, at: Date): number {\n try {\n const name = new Intl.DateTimeFormat(\"en-US\", { timeZone: zone, timeZoneName: \"longOffset\" }).formatToParts(at).find((p) => p.type === \"timeZoneName\")?.value ?? \"GMT\";\n const m = /GMT([+\\-−])(\\d{1,2})(?::?(\\d{2}))?/.exec(name);\n if (!m) return 0;\n const sign = m[1] === \"+\" ? 1 : -1;\n return sign * (Number(m[2]) * 60 + Number(m[3] ?? 0));\n } catch {\n return 0;\n }\n}\n\n/** +330 → \"+05:30\"; 0 → \"+00:00\". */\nexport const offsetIso = (min: number) => `${min < 0 ? \"-\" : \"+\"}${pad(Math.floor(Math.abs(min) / 60))}:${pad(Math.abs(min) % 60)}`;\n\n/** \"GMT+5:30\", \"GMT−7\", \"GMT\" — the short form people read (with a true minus sign). */\nexport function zoneShortOffset(zone: string, at = new Date()): string {\n const min = offsetMinutes(zone, at);\n if (min === 0) return \"GMT\";\n const h = Math.floor(Math.abs(min) / 60);\n const m = Math.abs(min) % 60;\n return `GMT${min < 0 ? \"−\" : \"+\"}${h}${m ? `:${pad(m)}` : \"\"}`;\n}\n\nexport const zoneCity = (z: string) => (z === \"UTC\" || z === \"Etc/UTC\" ? \"UTC\" : (z.split(\"/\").pop() ?? z).replace(/_/g, \" \"));\n/** \"GMT+5:30 · Kolkata\" */\nexport const zoneLabel = (zone: string, at?: Date) => `${zoneShortOffset(zone, at)} · ${zoneCity(zone)}`;\n\n/* ── Wall time ↔ instant ──────────────────────────────────────────────── */\nexport interface Wall {\n /** \"YYYY-MM-DD\" */\n ymd: string;\n /** \"HH:mm\" */\n time: string;\n}\nconst ymdParts = (ymd: string) => ymd.split(\"-\").map(Number) as [number, number, number];\nconst hmParts = (time: string) => time.split(\":\").map(Number) as [number, number];\nconst wallUtc = ({ ymd, time }: Wall) => {\n const [y, mo, d] = ymdParts(ymd);\n const [h, mi] = hmParts(time);\n return Date.UTC(y, mo - 1, d, h, mi);\n};\n\n/** The wall clock an instant shows in a zone. */\nexport function instantToWall(instant: Date, zone: string): Wall {\n const parts = new Intl.DateTimeFormat(\"en-CA\", { timeZone: zone, year: \"numeric\", month: \"2-digit\", day: \"2-digit\", hour: \"2-digit\", minute: \"2-digit\", hourCycle: \"h23\" }).formatToParts(instant);\n const get = (t: string) => parts.find((p) => p.type === t)?.value ?? \"00\";\n return { ymd: `${get(\"year\")}-${get(\"month\")}-${get(\"day\")}`, time: `${get(\"hour\")}:${get(\"minute\")}` };\n}\n\n/**\n * The offset of a wall time in a zone, or null when a clock change skips that wall time (it names no instant there).\n * Two passes: the offset at the naive instant, then at the instant that offset gives.\n */\nexport function wallOffset(zone: string, wall: Wall): number | null {\n const naive = wallUtc(wall);\n const first = offsetMinutes(zone, new Date(naive));\n const second = offsetMinutes(zone, new Date(naive - first * 60_000));\n for (const off of second === first ? [first] : [second, first]) {\n const back = instantToWall(new Date(naive - off * 60_000), zone);\n if (back.ymd === wall.ymd && back.time === wall.time) return off;\n }\n return null;\n}\n\n/** The instant a wall time names in a zone (the earlier one when a clock change skips it). */\nexport const wallInstant = (zone: string, wall: Wall) => new Date(wallUtc(wall) - (wallOffset(zone, wall) ?? offsetMinutes(zone, new Date(wallUtc(wall)))) * 60_000);\n\n/* ── Stored value → parts ─────────────────────────────────────────────── */\nexport interface ParsedValue {\n /** the day as stored (wall clock), or null when empty */\n wall: Wall | null;\n hasTime: boolean;\n /** the stated offset in minutes (\"Z\" → 0); undefined for a floating time */\n offset?: number;\n /** an RFC 9557 [Zone] suffix, when valid */\n zone?: string;\n /** false: a value this control cannot read (an object, a word); it is shown and never overwritten by accident */\n readable: boolean;\n}\n\nconst STORED = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2})(?::\\d{2}(?:\\.\\d+)?)?(Z|[+-]\\d{2}:?\\d{2})?)?(?:\\[([^\\]]+)\\])?$/;\nconst EMPTY: ParsedValue = { wall: null, hasTime: false, readable: true };\n\nexport function parseStored(v: unknown): ParsedValue {\n if (v == null || v === \"\") return EMPTY;\n if (typeof v !== \"string\") return { ...EMPTY, readable: false };\n const m = STORED.exec(v.trim());\n if (!m) return { ...EMPTY, readable: false };\n const [, y, mo, d, h, mi, off, zone] = m;\n const date = new Date(Date.UTC(Number(y), Number(mo) - 1, Number(d)));\n if (date.getUTCMonth() !== Number(mo) - 1 || date.getUTCDate() !== Number(d)) return { ...EMPTY, readable: false };\n let offset: number | undefined;\n if (off === \"Z\") offset = 0;\n else if (off) {\n const om = /([+-])(\\d{2}):?(\\d{2})/.exec(off)!;\n offset = (om[1] === \"-\" ? -1 : 1) * (Number(om[2]) * 60 + Number(om[3]));\n }\n return { wall: { ymd: `${y}-${mo}-${d}`, time: h ? `${h}:${mi}` : \"09:00\" }, hasTime: !!h, offset, zone: validZone(zone) ? zone : undefined, readable: true };\n}\n\n/** A stored value as a JS Date (drops the [Zone] annotation, which `new Date()` can't read). */\nexport function storedToDate(v: unknown): Date | null {\n if (typeof v !== \"string\" || !v) return null;\n const d = new Date(v.replace(/\\[[^\\]]*\\]$/, \"\"));\n return Number.isNaN(d.getTime()) ? null : d;\n}\n\n/* ── Zones ────────────────────────────────────────────────────────────── */\n/** Every IANA zone this runtime knows, UTC included. */\nexport const ALL_ZONES: readonly string[] = (() => {\n const list = typeof Intl.supportedValuesOf === \"function\" ? Intl.supportedValuesOf(\"timeZone\").map(modernZone) : [];\n return Array.from(new Set(list.includes(\"UTC\") ? list : [...list, \"UTC\"]));\n})();\n\n/** The first zone (in order) whose offset at the instant is `offset`; undefined when none is. */\nexport function zoneWithOffset(offset: number, instant: Date, candidates: readonly (string | undefined)[]): string | undefined {\n for (const z of candidates) if (z && validZone(z) && offsetMinutes(z, instant) === offset) return z;\n return undefined;\n}\n\n/**\n * What the control shows for a stored value: the wall time and the zone it lives in.\n *\n * - none: the stored wall time, as typed.\n * - site / fixed: that zone. A stored instant with another offset is shown as THAT instant's wall time in the zone,\n * so the shown and the saved time never disagree.\n * - pick: the stored [Zone]; else the zone the editor picked this session, the default, the browser's, then any\n * zone whose offset matches the stored one (a \"+05:30\" reads back as Kolkata). A floating time reads in the default.\n */\nexport function resolveShown(parsed: ParsedValue, mode: ZoneMode, zones: { fixed?: string; def: string; picked?: string }): { wall: Wall | null; zone: string } {\n const lockedZone = mode === \"fixed\" ? zones.fixed! : zones.def;\n if (!parsed.wall) return { wall: null, zone: mode === \"pick\" ? (zones.picked ?? zones.def) : lockedZone };\n if (mode === \"none\" || parsed.offset === undefined) {\n const zone = mode === \"pick\" ? (parsed.zone ?? zones.picked ?? zones.def) : lockedZone;\n return { wall: parsed.wall, zone };\n }\n const instant = new Date(wallUtc(parsed.wall) - parsed.offset * 60_000);\n if (mode === \"pick\") {\n const zone = (parsed.zone && offsetMinutes(parsed.zone, instant) === parsed.offset ? parsed.zone : undefined) ?? zoneWithOffset(parsed.offset, instant, [zones.picked, zones.def, browserZone(), ...ALL_ZONES]);\n if (zone) return { wall: parsed.wall, zone };\n return { wall: instantToWall(instant, zones.def), zone: zones.def };\n }\n return { wall: offsetMinutes(lockedZone, instant) === parsed.offset ? parsed.wall : instantToWall(instant, lockedZone), zone: lockedZone };\n}\n\n/* ── Parts → stored value ─────────────────────────────────────────────── */\nexport type WriteResult = { ok: true; value: string } | { ok: false; reason: string };\n\n/** The stored string for a wall time under the field's policy (file header). */\nexport function writeValue(o: { withTime: boolean; mode: ZoneMode; wall: Wall; zone: string }): WriteResult {\n const { withTime, mode, wall, zone } = o;\n if (!withTime) return { ok: true, value: wall.ymd };\n const local = `${wall.ymd}T${wall.time}:00`;\n if (mode === \"none\") return { ok: true, value: local };\n const off = wallOffset(zone, wall);\n if (off === null) return { ok: false, reason: `That local time doesn't exist in ${zoneCity(zone)} (clocks change). Pick another time.` };\n return { ok: true, value: `${local}${offsetIso(off)}${mode === \"fixed\" ? `[${zone}]` : \"\"}` };\n}\n\n/** Today in a zone (the browser's local day for a floating field). */\nexport function todayIn(zone: string | undefined, now = new Date()): string {\n if (zone) return instantToWall(now, zone).ymd;\n return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;\n}\n"],"mappings":"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"}
|
package/controls/date.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"date.js","names":[],"sources":["../../src/kit/controls/date.tsx"],"sourcesContent":["/**\n * DATE / DATETIME — one picker for date, time and time zone (DESIGN 8.9, CPO D43). V2 controls/date.tsx, with the\n * stored shapes prod keeps (date-zone.ts header) and a calendar you can drive from the keyboard:\n *\n * arrows move a day / a week · Home / End go to the week's start / end · Page Up / Down move a month (Shift: a year)\n * Enter or Space picks · the calendar is one tab stop (the picked day, else today, else the 1st)\n *\n * A value this picker cannot read (an object, a word) is shown with its reason and never overwritten by a stray\n * click. A wall time a clock change skips is refused with the reason, not shifted.\n */\nimport * as React from \"react\";\nimport { IconAlertTriangle, IconCalendar, IconChevronDown, IconChevronLeft, IconChevronRight, IconClock, IconLock, IconWorld } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { useKitEnv } from \"../context\";\nimport type { ControlProps } from \"../types\";\nimport { Button } from \"../ui/button\";\nimport { Popover, PopoverContent, PopoverTrigger, Tooltip } from \"../ui/overlay\";\nimport { Select, type SelectOption } from \"../ui/select\";\nimport {\n ALL_ZONES, browserZone, parseStored, resolveShown, todayIn, useDefaultZone, validZone, wallInstant, writeValue, zoneCity, zoneLabel,\n zonePolicy, zoneShortOffset, type Wall,\n} from \"./date-zone\";\n\n/* ── Day arithmetic on \"YYYY-MM-DD\" (UTC, so no local zone leaks in) ──── */\nconst pad = (n: number) => String(n).padStart(2, \"0\");\nconst toUtc = (ymd: string) => {\n const [y, m, d] = ymd.split(\"-\").map(Number);\n return new Date(Date.UTC(y, m - 1, d));\n};\nconst fromUtc = (d: Date) => `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}`;\nconst addDays = (ymd: string, n: number) => {\n const d = toUtc(ymd);\n d.setUTCDate(d.getUTCDate() + n);\n return fromUtc(d);\n};\nconst addMonths = (ymd: string, n: number) => {\n const d = toUtc(ymd);\n const day = d.getUTCDate();\n const t = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + n, 1));\n const last = new Date(Date.UTC(t.getUTCFullYear(), t.getUTCMonth() + 1, 0)).getUTCDate();\n t.setUTCDate(Math.min(day, last));\n return fromUtc(t);\n};\nconst monthOf = (ymd: string) => ymd.slice(0, 7);\nconst fmt = (ymd: string, o: Intl.DateTimeFormatOptions) => toUtc(ymd).toLocaleDateString(\"en-US\", { ...o, timeZone: \"UTC\" });\nconst fmtTime = (hm: string) => {\n const [h, m] = hm.split(\":\").map(Number);\n return new Date(Date.UTC(2000, 0, 1, h, m)).toLocaleTimeString(\"en-US\", { hour: \"numeric\", minute: \"2-digit\", timeZone: \"UTC\" });\n};\n\n/* ── Calendar ─────────────────────────────────────────────────────────── */\nconst WD = [\"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\", \"Su\"];\nexport function MiniCalendar({ value, today, onSelect }: { value: string | null; today: string; onSelect: (ymd: string) => void }) {\n const [view, setView] = React.useState(() => `${monthOf(value ?? today)}-01`);\n const [cursor, setCursor] = React.useState<string>(value ?? today);\n const grid = React.useRef<HTMLDivElement>(null);\n const refocus = React.useRef(false);\n const viewMonth = monthOf(view);\n /* the one tab stop: the cursor when it is in view, else the picked day, today, or the 1st */\n const stop = [cursor, value, today].find((d) => d && monthOf(d) === viewMonth) ?? view;\n const lead = (toUtc(view).getUTCDay() + 6) % 7;\n const cells = Array.from({ length: 42 }, (_, i) => addDays(view, i - lead));\n\n React.useEffect(() => {\n if (!refocus.current) return;\n refocus.current = false;\n grid.current?.querySelector<HTMLButtonElement>(`[data-day=\"${cursor}\"]`)?.focus();\n }, [cursor, view]);\n\n const go = (ymd: string) => {\n refocus.current = true;\n setCursor(ymd);\n if (monthOf(ymd) !== viewMonth) setView(`${monthOf(ymd)}-01`);\n };\n const onKeyDown = (e: React.KeyboardEvent) => {\n const from = (e.target as HTMLElement).dataset.day;\n if (!from) return;\n const dow = (toUtc(from).getUTCDay() + 6) % 7;\n const to = ({\n ArrowLeft: () => addDays(from, -1),\n ArrowRight: () => addDays(from, 1),\n ArrowUp: () => addDays(from, -7),\n ArrowDown: () => addDays(from, 7),\n Home: () => addDays(from, -dow),\n End: () => addDays(from, 6 - dow),\n PageUp: () => addMonths(from, e.shiftKey ? -12 : -1),\n PageDown: () => addMonths(from, e.shiftKey ? 12 : 1),\n } as Record<string, () => string>)[e.key];\n if (!to) return;\n e.preventDefault();\n go(to());\n };\n const page = (n: number) => {\n const next = addMonths(view, n);\n setView(next);\n setCursor(next);\n };\n\n return (\n <div className=\"w-[248px]\">\n <div className=\"mb-2 flex items-center justify-between\">\n <button type=\"button\" aria-label=\"Previous month\" onClick={() => page(-1)} className=\"flex size-7 items-center justify-center rounded-kit-md text-kit-fg-2 hover:bg-kit-hover\">\n <IconChevronLeft className=\"size-4\" stroke={1.5} />\n </button>\n <span className=\"text-kit-sm font-medium text-kit-fg\" aria-live=\"polite\">{fmt(view, { month: \"long\", year: \"numeric\" })}</span>\n <button type=\"button\" aria-label=\"Next month\" onClick={() => page(1)} className=\"flex size-7 items-center justify-center rounded-kit-md text-kit-fg-2 hover:bg-kit-hover\">\n <IconChevronRight className=\"size-4\" stroke={1.5} />\n </button>\n </div>\n <div ref={grid} role=\"group\" aria-label={fmt(view, { month: \"long\", year: \"numeric\" })} className=\"grid grid-cols-7 gap-0.5 text-center\" onKeyDown={onKeyDown}>\n {WD.map((d) => (\n <span key={d} aria-hidden className=\"pb-1 text-kit-2xs text-kit-fg-3\">{d}</span>\n ))}\n {cells.map((d) => {\n const out = monthOf(d) !== viewMonth;\n const sel = d === value;\n return (\n <button\n key={d}\n type=\"button\"\n data-day={d}\n tabIndex={d === stop ? 0 : -1}\n onClick={() => {\n setCursor(d);\n onSelect(d);\n }}\n aria-pressed={sel}\n aria-current={d === today ? \"date\" : undefined}\n aria-label={fmt(d, { weekday: \"long\", month: \"long\", day: \"numeric\", year: \"numeric\" })}\n className={cn(\n \"flex size-8 items-center justify-center rounded-kit-md text-kit-sm tabular-nums transition-colors\",\n sel ? \"bg-kit-inverse font-medium text-kit-fg-inverse\" : out ? \"text-kit-fg-4 hover:bg-kit-hover\" : \"text-kit-fg hover:bg-kit-hover\",\n !sel && d === today && \"ring-1 ring-inset ring-kit-line-strong\",\n )}\n >\n {Number(d.slice(8))}\n </button>\n );\n })}\n </div>\n </div>\n );\n}\n\n/* ── Zone list ────────────────────────────────────────────────────────── */\n/** One searchable list: Suggested (the default zone, your zone, the value's zone) first, then every IANA zone by region. */\nfunction zoneOptions(current: string, def: { zone: string; source: string }, at: Date): SelectOption[] {\n const suggested: SelectOption[] = [];\n const seen = new Set<string>();\n const option = (z: string, group: string, description?: string): SelectOption => ({\n value: z,\n label: zoneLabel(z, at),\n description,\n group,\n keywords: [z, zoneCity(z), zoneShortOffset(z, at), ...(description ? [description] : [])],\n });\n const push = (z: string, note: string) => {\n if (seen.has(z) || !validZone(z)) return;\n seen.add(z);\n suggested.push(option(z, \"Suggested\", note));\n };\n push(def.zone, def.source === \"site\" ? \"Site time zone\" : \"Your time zone\");\n push(browserZone(), \"Your time zone\");\n push(current, \"Current\");\n return [...suggested, ...ALL_ZONES.filter((z) => !seen.has(z)).map((z) => option(z, z.includes(\"/\") ? z.split(\"/\")[0] : \"Other\"))];\n}\n\nfunction ZoneSelect({ zone, def, at, disabled, onPick }: { zone: string; def: { zone: string; source: string }; at: Date; disabled: boolean; onPick: (z: string) => void }) {\n const options = React.useMemo(() => zoneOptions(zone, def, at), [zone, def, at]);\n return (\n <Select\n aria-label=\"Time zone\"\n size=\"md\"\n className=\"min-w-0 flex-1\"\n searchable\n searchPlaceholder=\"Search city, region or offset\"\n menuClassName=\"w-[300px]\"\n value={zone}\n onValueChange={onPick}\n options={options}\n disabled={disabled}\n />\n );\n}\n\n/* ── The control ──────────────────────────────────────────────────────── */\nexport function DateControl({ field, value, onChange, readOnly, id, invalid }: ControlProps) {\n const { variant } = useKitEnv();\n const withTime = field.type === \"datetime\";\n const policy = zonePolicy(field);\n const def = useDefaultZone();\n const [picked, setPicked] = React.useState<string>();\n const [open, setOpen] = React.useState(false);\n const [problem, setProblem] = React.useState<string | null>(null);\n const parsed = React.useMemo(() => parseStored(value), [value]);\n const { wall, zone } = React.useMemo(() => resolveShown(parsed, policy.mode, { fixed: policy.zone, def: def.zone, picked }), [parsed, policy.mode, policy.zone, def.zone, picked]);\n const zoned = policy.mode !== \"none\";\n const time = wall?.time ?? \"09:00\";\n const today = todayIn(zoned ? zone : undefined);\n const at = React.useMemo(() => (wall ? wallInstant(zone, wall) : new Date()), [wall, zone]);\n\n if (!parsed.readable) return <Unreadable id={id} title={field.title} value={value} />;\n\n const commit = (next: Wall, z = zone) => {\n const r = writeValue({ withTime, mode: policy.mode, wall: next, zone: z });\n if (!r.ok) {\n setProblem(r.reason);\n return false;\n }\n setProblem(null);\n onChange(r.value);\n return true;\n };\n const pickDay = (ymd: string) => {\n if (commit({ ymd, time }) && !withTime) setOpen(false);\n };\n\n const timeText = withTime && wall ? fmtTime(wall.time) : \"\";\n const showZone = zoned && withTime;\n const full = wall ? `${fmt(wall.ymd, { weekday: \"long\", month: \"long\", day: \"numeric\", year: \"numeric\" })}${timeText ? ` at ${timeText}` : \"\"}${showZone ? ` (${zoneLabel(zone, at)})` : \"\"}` : \"\";\n\n return (\n <Popover\n open={open}\n onOpenChange={(o) => {\n setOpen(o);\n if (!o) setProblem(null);\n }}\n >\n <PopoverTrigger\n render={\n <button\n id={id}\n type=\"button\"\n disabled={readOnly}\n aria-invalid={invalid || undefined}\n aria-label={wall ? `${field.title}: ${full}. Change` : `${field.title}: pick a date`}\n className={cn(\n \"@container/date flex w-full min-w-0 items-center gap-2 rounded-kit-md border bg-kit-field-bg px-2.5 text-left text-kit-sm text-kit-fg shadow-kit-field outline-none transition-colors disabled:opacity-60\",\n invalid ? \"border-[var(--kit-field-invalid)]\" : \"border-kit-field-border hover:border-kit-field-border-hover data-[popup-open]:border-kit-field-border-focus focus-visible:border-kit-field-border-focus\",\n variant === \"document\" ? \"h-9\" : \"h-8\",\n )}\n />\n }\n >\n <IconCalendar className=\"size-4 shrink-0 text-kit-fg-3\" stroke={1.5} aria-hidden />\n {wall ? (\n /* never truncate the date itself: drop the weekday first, then the zone (it stays in the label and popover) */\n <span className=\"flex min-w-0 flex-1 items-baseline gap-1.5 whitespace-nowrap\" data-slot=\"date-text\">\n <span className=\"shrink-0\">\n <span className=\"hidden @[260px]/date:inline\">{fmt(wall.ymd, { weekday: \"short\" })}, </span>\n {fmt(wall.ymd, { month: \"short\", day: \"numeric\", year: \"numeric\" })}\n {timeText ? <span className=\"text-kit-fg-2\"> · {timeText}</span> : null}\n </span>\n {showZone ? <span className=\"hidden min-w-0 truncate text-kit-xs text-kit-fg-3 @[200px]/date:inline\">{zoneShortOffset(zone, at)}</span> : null}\n </span>\n ) : (\n <span className=\"min-w-0 flex-1 truncate text-kit-fg-3\">{withTime ? \"Pick a date and time\" : \"Pick a date\"}</span>\n )}\n <IconChevronDown className=\"size-3.5 shrink-0 text-kit-fg-3\" stroke={1.5} aria-hidden />\n </PopoverTrigger>\n <PopoverContent className=\"w-auto\" aria-label={withTime ? `${field.title}: date and time` : `${field.title}: date`}>\n <MiniCalendar value={wall?.ymd ?? null} today={today} onSelect={pickDay} />\n {withTime ? (\n <div className=\"mt-3 flex w-[248px] flex-col gap-2 border-t border-kit-line pt-3\">\n <label className=\"flex items-center gap-2\">\n <IconClock className=\"size-4 shrink-0 text-kit-fg-3\" stroke={1.5} aria-hidden />\n <input\n type=\"time\"\n value={time}\n onChange={(e) => e.target.value && commit({ ymd: wall?.ymd ?? today, time: e.target.value })}\n className=\"h-8 min-w-0 flex-1 rounded-kit-md border border-kit-field-border bg-kit-field-bg px-2 text-kit-sm text-kit-fg outline-none hover:border-kit-field-border-hover focus:border-kit-field-border-focus\"\n aria-label=\"Time\"\n />\n </label>\n {zoned ? (\n <div className=\"flex items-center gap-2\">\n <IconWorld className=\"size-4 shrink-0 text-kit-fg-3\" stroke={1.5} aria-hidden />\n {policy.mode === \"pick\" ? (\n <ZoneSelect\n zone={zone}\n def={def}\n at={at}\n disabled={!wall}\n onPick={(z) => {\n if (!wall) return;\n // keep the wall time the author typed; the instant moves with the zone (6.4)\n if (commit(wall, z)) setPicked(z);\n }}\n />\n ) : (\n <Tooltip content={policy.mode === \"site\" ? \"Uses the site's time zone (Site settings › General).\" : \"Set by the developer for this field.\"}>\n <span tabIndex={0} className=\"flex h-8 min-w-0 flex-1 items-center gap-1.5 rounded-kit-md bg-kit-subtle px-2 text-kit-sm text-kit-fg-2 outline-none focus-visible:outline-2 focus-visible:outline-kit-focus-ring\">\n <span className=\"min-w-0 flex-1 truncate\">{zoneLabel(zone, at)}</span>\n <IconLock className=\"size-3.5 shrink-0 text-kit-fg-3\" stroke={1.5} role=\"img\" aria-label={policy.mode === \"site\" ? \"Site time zone\" : \"Fixed time zone\"} />\n </span>\n </Tooltip>\n )}\n </div>\n ) : null}\n </div>\n ) : null}\n {problem ? (\n <p role=\"alert\" className=\"mt-2 flex w-[248px] items-start gap-1.5 text-kit-xs text-kit-danger-fg\">\n <IconAlertTriangle className=\"mt-0.5 size-3.5 shrink-0\" stroke={1.5} aria-hidden />\n {problem}\n </p>\n ) : null}\n <div className=\"mt-2 flex justify-between\">\n <Button size=\"xs\" variant=\"ghost\" onClick={() => pickDay(today)}>\n Today\n </Button>\n {wall ? (\n <Button\n size=\"xs\"\n variant=\"ghost\"\n onClick={() => {\n // null, not \"\": the backend skips an empty value but refuses \"\" as \"not a valid date\"\n onChange(null);\n setProblem(null);\n setOpen(false);\n }}\n >\n Clear\n </Button>\n ) : null}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\n/** A stored value this picker cannot read: shown with the reason, kept as it is, never replaced by a stray pick. */\nfunction Unreadable({ id, title, value }: { id: string; title: string; value: unknown }) {\n const raw = typeof value === \"string\" ? value : JSON.stringify(value);\n return (\n <output\n id={id}\n tabIndex={0}\n data-slot=\"date-unreadable\"\n className=\"flex min-w-0 items-start gap-2 rounded-kit-md border border-dashed border-kit-line-strong bg-kit-subtle px-2.5 py-2 text-kit-xs text-kit-fg-2 outline-none focus-visible:outline-2 focus-visible:outline-kit-focus-ring\"\n >\n <IconAlertTriangle className=\"mt-0.5 size-3.5 shrink-0 text-kit-warning-fg\" stroke={1.5} aria-hidden />\n <span className=\"min-w-0\">\n {title} holds a value this picker can't read, so it is kept as it is:{\" \"}\n <span className=\"break-all font-kit-mono text-kit-fg\">{raw}</span>\n </span>\n </output>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"form-picker-register.js","names":[],"sources":["../../src/kit/controls/form-picker-register.ts"],"sourcesContent":["/**\n * Lane L3: a reference to forms only (`reference: { to: [\"form\"] }`, a component's `form` prop) draws the form picker\n * when the host provides the project's forms; any other reference keeps the reference control. Imported after\n * reference-register (kit barrel), so it wraps the registered reference control.\n */\nimport { createElement } from \"react\";\nimport type { ControlProps } from \"../types\";\nimport { useKitServices } from \"../context\";\nimport { CONTROLS } from \"../engine/kit-field\";\nimport { ReferenceControl } from \"./reference\";\nimport { FormPickerControl, isFormOnly } from \"./form-picker\";\n\nconst Reference = CONTROLS.reference ?? ReferenceControl;\nCONTROLS.reference = function ReferenceOrFormControl(props: ControlProps) {\n const { forms, useFormOptions } = useKitServices();\n return createElement(isFormOnly(props.field) && (forms || useFormOptions) ? FormPickerControl : Reference, props);\n};\n"],"mappings":";;;;;;;;;;;AAYA,IAAM,YAAY,SAAS,aAAa;AACxC,SAAS,YAAY,SAAS,uBAAuB,OAAqB;CACxE,MAAM,EAAE,OAAO,mBAAmB,gBAAgB;AAClD,QAAO,cAAc,WAAW,MAAM,MAAM,KAAK,SAAS,kBAAkB,oBAAoB,WAAW,MAAM"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"form-picker.js","names":[],"sources":["../../src/kit/controls/form-picker.tsx"],"sourcesContent":["/**\n * FORM PICKER — a reference to the project's forms (`reference: { to: [\"form\"] }`; a component's `form` prop), drawn as\n * V2 draws it: the reference control's card and 300px search popover, its rows the host's forms (V2 read them from\n * `services.forms`, with \"{n} fields · {n} submissions\" under each name).\n *\n * The rows come from the host, never a seed: `forms` (V2's synchronous list) or `useFormOptions`, a React HOOK for a host\n * that loads them (the dock: GET /forms). While they load, the saved form shows its id; a failed load is said in words\n * on the card and in the picker. D58: submission counts are form data, so a viewer without `forms.submissions` sees\n * them dropped from the subtitle (V2 rule).\n *\n * Remove clears the value (`undefined`): a form prop stores `{ formId }` or nothing, never a null envelope.\n * `FormDetails`, when the host has one, draws under a chosen form (where the form renders on the site, editing its fields).\n */\nimport * as React from \"react\";\nimport { KitServicesProvider, useKitEnv, useKitServices, type KitServices } from \"../context\";\nimport type { FieldSchema } from \"../schema/types\";\nimport type { ControlProps } from \"../types\";\nimport { ReferenceControl } from \"./reference\";\nimport type { KitReferenceOption, KitReferenceQuery } from \"./reference-services\";\n\nexport interface KitFormOption {\n id: string;\n title: string;\n /** \"5 fields · 128 submissions\" */\n subtitle?: string;\n /** \"draft\" shows the Draft chip (a draft form refuses submissions) */\n status?: string | null;\n}\n\ndeclare module \"../context\" {\n interface KitServices {\n /** A React HOOK: the project's forms, for a host that loads them. One identity for the life of the form. */\n useFormOptions?: () => { forms: KitFormOption[]; loading?: boolean; error?: string };\n /** Drawn under a chosen form: the host's own detail for it (where it renders, its fields). */\n FormDetails?: React.ComponentType<{ formId: string; readOnly?: boolean; onPick?: (formId: string) => void }>;\n }\n}\n\n/** A reference whose only target is forms (no filter: a filtered one stays on the reference search). */\nexport const isFormOnly = (field: FieldSchema) => {\n const to = field.reference?.to ?? [];\n return to.length === 1 && to[0] === \"form\" && !field.reference?.filter;\n};\n\nconst SUBMISSIONS = / · [\\d,]+ submissions?$/;\n\nfunction useFormRows(services: KitServices): { forms: KitFormOption[] | null; error?: string } {\n const loaded = services.useFormOptions ? services.useFormOptions() : null;\n if (loaded) return { forms: loaded.loading ? null : loaded.forms, error: loaded.error };\n return { forms: services.forms?.() ?? [] };\n}\n\nexport function FormPickerControl(props: ControlProps) {\n const services = useKitServices();\n const subs = useKitEnv().can(\"forms.submissions\");\n const { forms, error } = useFormRows(services);\n // by content: `forms()` may hand back a new list on every render, and the search must keep one identity (the picker\n // searches again whenever it changes)\n const rowsKey = JSON.stringify(forms);\n const options = React.useMemo<KitReferenceOption[] | null>(\n () =>\n forms?.map((f) => ({ id: f.id, kind: \"form\" as const, title: f.title, subtitle: (subs ? f.subtitle : f.subtitle?.replace(SUBMISSIONS, \"\")) || null, status: f.status ?? null })) ?? null,\n [rowsKey, subs], // eslint-disable-line react-hooks/exhaustive-deps\n );\n // the reference control over these rows: search by name, read the saved id back. While the forms load there is no\n // lookup, so the card shows the saved id (never a \"Missing\" that is only \"not loaded yet\").\n const reads = React.useMemo(() => {\n const fail = () => Promise.reject(new Error(error));\n return {\n searchReferences: error\n ? fail\n : async (q: KitReferenceQuery) => {\n const t = q.q.trim().toLowerCase();\n const rows = (options ?? []).filter((o) => o.id !== q.excludeId && (!t || o.title.toLowerCase().includes(t)));\n return { options: rows.slice(0, q.limit), truncated: false };\n },\n lookupReferences: error ? fail : options ? async (ids: string[]) => options.filter((o) => ids.includes(o.id)) : undefined,\n };\n }, [options, error]);\n const value: KitServices = { ...services, ...reads, createReference: undefined };\n const formId = typeof props.value === \"string\" && props.value ? props.value : null;\n const Details = services.FormDetails;\n return (\n <div className=\"flex min-w-0 flex-col gap-2\">\n <KitServicesProvider value={value}>\n <ReferenceControl {...props} onChange={(v) => props.onChange(v == null || v === \"\" ? undefined : v)} />\n </KitServicesProvider>\n {formId && Details ? <Details formId={formId} readOnly={props.readOnly} onPick={(id) => props.onChange(id)} /> : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuCA,IAAa,cAAc,UAAuB;CAChD,MAAM,KAAK,MAAM,WAAW,MAAM,EAAE;AACpC,QAAO,GAAG,WAAW,KAAK,GAAG,OAAO,UAAU,CAAC,MAAM,WAAW;;AAGlE,IAAM,cAAc;AAEpB,SAAS,YAAY,UAA0E;CAC7F,MAAM,SAAS,SAAS,iBAAiB,SAAS,gBAAgB,GAAG;AACrE,KAAI,OAAQ,QAAO;EAAE,OAAO,OAAO,UAAU,OAAO,OAAO;EAAO,OAAO,OAAO;EAAO;AACvF,QAAO,EAAE,OAAO,SAAS,SAAS,IAAI,EAAE,EAAE;;AAG5C,SAAgB,kBAAkB,OAAqB;CACrD,MAAM,WAAW,gBAAgB;CACjC,MAAM,OAAO,WAAW,CAAC,IAAI,oBAAoB;CACjD,MAAM,EAAE,OAAO,UAAU,YAAY,SAAS;CAG9C,MAAM,UAAU,KAAK,UAAU,MAAM;CACrC,MAAM,UAAU,MAAM,cAElB,OAAO,KAAK,OAAO;EAAE,IAAI,EAAE;EAAI,MAAM;EAAiB,OAAO,EAAE;EAAO,WAAW,OAAO,EAAE,WAAW,EAAE,UAAU,QAAQ,aAAa,GAAG,KAAK;EAAM,QAAQ,EAAE,UAAU;EAAM,EAAE,IAAI,MACtL,CAAC,SAAS,KAAK,CAChB;CAGD,MAAM,QAAQ,MAAM,cAAc;EAChC,MAAM,aAAa,QAAQ,OAAO,IAAI,MAAM,MAAM,CAAC;AACnD,SAAO;GACL,kBAAkB,QACd,OACA,OAAO,MAAyB;IAC9B,MAAM,IAAI,EAAE,EAAE,MAAM,CAAC,aAAa;AAElC,WAAO;KAAE,UADK,WAAW,EAAE,EAAE,QAAQ,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,aAAa,CAAC,SAAS,EAAE,EAAE,CACtF,MAAM,GAAG,EAAE,MAAM;KAAE,WAAW;KAAO;;GAElE,kBAAkB,QAAQ,OAAO,UAAU,OAAO,QAAkB,QAAQ,QAAQ,MAAM,IAAI,SAAS,EAAE,GAAG,CAAC,GAAG,KAAA;GACjH;IACA,CAAC,SAAS,MAAM,CAAC;CACpB,MAAM,QAAqB;EAAE,GAAG;EAAU,GAAG;EAAO,iBAAiB,KAAA;EAAW;CAChF,MAAM,SAAS,OAAO,MAAM,UAAU,YAAY,MAAM,QAAQ,MAAM,QAAQ;CAC9E,MAAM,UAAU,SAAS;AACzB,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,qBAAD;GAA4B;aAC1B,oBAAC,kBAAD;IAAkB,GAAI;IAAO,WAAW,MAAM,MAAM,SAAS,KAAK,QAAQ,MAAM,KAAK,KAAA,IAAY,EAAE;IAAI,CAAA;GACnF,CAAA,EACrB,UAAU,UAAU,oBAAC,SAAD;GAAiB;GAAQ,UAAU,MAAM;GAAU,SAAS,OAAO,MAAM,SAAS,GAAG;GAAI,CAAA,GAAG,KAC7G"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"icon-register.js","names":[],"sources":["../../src/kit/controls/icon-register.ts"],"sourcesContent":["/** Lane C3: the icon field in the engine's dispatch table (one line per type; merge with other lanes by line). */\nimport { CONTROLS } from \"../engine/kit-field\";\nimport { IconControl } from \"./icon\";\n\nCONTROLS.icon = IconControl;\n"],"mappings":";;;;AAIA,SAAS,OAAO"}
|
package/controls/icon.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"icon.js","names":[],"sources":["../../src/kit/controls/icon.tsx"],"sourcesContent":["/**\n * ICON — the icon field (DESIGN 8.14), V2 controls/icon.tsx fitted to what prod stores.\n *\n * Values (backend reference-validation `icon`, the classic PropsPanel IconValueInput):\n * \"arrow-right\" a name from the BetterCMS icon set (DOCK_ICON_NAMES, 472 names)\n * \"https://…/logo.svg\" an uploaded icon: an image URL (picked from the media library; a component prop\n * stores the URL string, like the classic panel's codec=\"url\")\n * { url, … } an uploaded icon stored as an image value: shown and kept until replaced\n * null no icon (\"No icon\"; the backend skips an empty value)\n *\n * The grid offers the BetterCMS set, the one prod accepts. Search also matches a name's Tabler twin through the\n * Tabler ↔ dock adapter (adapters/icons.ts), so \"map\" finds earth-americas. A stored name outside the set (a stale\n * Tabler or Lucide name) is shown with its reason and kept until the author picks another.\n *\n * Glyphs: the host draws them (KitServices.IconGlyph: the dashboard's DockIcon, the set the site renders). With no\n * host renderer the kit draws the Tabler twin, loaded on first use; a name with no Tabler twin shows its name.\n */\nimport * as React from \"react\";\nimport type { Icon as TablerIcon } from \"@tabler/icons-react\";\nimport { IconAlertTriangle, IconChevronDown, IconPhoto, IconSearch, IconX } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { isObj } from \"../lib/path\";\nimport { iconLabel } from \"../lib/icons\";\nimport { useKitServices } from \"../context\";\nimport { DOCK_ICON_NAMES, DOCK_ICON_NAME_SET } from \"../adapters/prod-types\";\nimport { tablerIconOf } from \"../adapters/icons\";\nimport type { ControlProps } from \"../types\";\nimport { Button } from \"../ui/button\";\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../ui/overlay\";\nimport { TooltipLayer } from \"../ui/tooltip-root\";\n\n/* ── Glyphs ───────────────────────────────────────────────────────────── */\ndeclare module \"../context\" {\n interface KitServices {\n /**\n * Draws one icon of the BetterCMS set by name, aria-hidden (the name beside it is the accessible text): the glyphs\n * the site renders. The dashboard passes `DockIcon` (src/components/dock/DockIcon). Absent → the Tabler twin.\n */\n IconGlyph?: React.ComponentType<{ name: string; className?: string }>;\n }\n}\n\nlet tablerSet: Record<string, unknown> | null = null;\nlet tablerLoad: Promise<void> | null = null;\nconst pascal = (kebab: string) => `Icon${kebab.split(\"-\").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(\"\")}`;\n\n/** The full Tabler set, loaded once and only when no host renderer is provided. */\nfunction useTablerSet(need: boolean): Record<string, unknown> | null {\n const [, landed] = React.useReducer((n: number) => n + 1, 0);\n React.useEffect(() => {\n if (!need || tablerSet) return;\n let live = true;\n tablerLoad ??= import(\"@tabler/icons-react\").then((m) => {\n tablerSet = m as unknown as Record<string, unknown>;\n });\n tablerLoad.then(() => live && landed(), () => {});\n return () => {\n live = false;\n };\n }, [need]);\n return tablerSet;\n}\n\nfunction Glyph({ name, className }: { name: string; className?: string }) {\n const Host = useKitServices().IconGlyph;\n const set = useTablerSet(!Host);\n if (Host) return <Host name={name} className={className} />;\n const T = set?.[pascal(tablerIconOf(name))] as TablerIcon | undefined;\n if (T) return <T className={className} stroke={1.5} aria-hidden />;\n // no Tabler twin (or the set is still loading): the name itself, never a stand-in shape\n return (\n <span aria-hidden className=\"max-w-full truncate px-0.5 text-[9px] leading-3 text-kit-fg-3\">\n {name}\n </span>\n );\n}\n\n/* ── Values ───────────────────────────────────────────────────────────── */\ntype Read =\n | { kind: \"empty\" }\n | { kind: \"name\"; name: string }\n | { kind: \"unknown\"; name: string }\n | { kind: \"upload\"; url: string }\n | { kind: \"unreadable\" };\nconst isUrlish = (s: string) => /[/.]/.test(s);\nfunction readIcon(v: unknown): Read {\n if (v == null || v === \"\") return { kind: \"empty\" };\n if (typeof v === \"string\") return DOCK_ICON_NAME_SET.has(v) ? { kind: \"name\", name: v } : isUrlish(v) ? { kind: \"upload\", url: v } : { kind: \"unknown\", name: v };\n if (isObj(v) && typeof v.url === \"string\" && v.url) return { kind: \"upload\", url: v.url };\n return { kind: \"unreadable\" };\n}\nconst fileName = (url: string) => decodeURIComponent(url.split(/[?#]/)[0].split(\"/\").pop() || url);\n\n/** Names picked this session, newest first (shown as \"Recent\"). */\nconst recents: string[] = [];\nconst pushRecent = (name: string) => {\n const i = recents.indexOf(name);\n if (i !== -1) recents.splice(i, 1);\n recents.unshift(name);\n recents.length = Math.min(recents.length, COLS);\n};\n\n/* ── The grid: one tab stop, arrow keys, Home / End ───────────────────── */\nconst COLS = 8;\nconst norm = (q: string) => q.toLowerCase().trim().replace(/\\s+/g, \"-\");\ninterface GridItem {\n key: string;\n label: string;\n node: React.ReactNode;\n}\n\ntype TipHandle = ReturnType<typeof TooltipPrimitive.createHandle<string>>;\n\n/** Up / down within a grid keep the column; past its edge they land in the same column of the next / previous grid. */\nfunction verticalTarget(grids: HTMLButtonElement[][], g: number, j: number, down: boolean): HTMLButtonElement | \"search\" | undefined {\n const col = j % COLS;\n const cur = grids[g];\n const within = down ? j + COLS : j - COLS;\n if (within >= 0 && within < cur.length) return cur[within];\n if (down && Math.floor(j / COLS) < Math.floor((cur.length - 1) / COLS)) return cur[cur.length - 1]; // a short last row\n const next = grids[down ? g + 1 : g - 1];\n if (!next) return down ? undefined : \"search\";\n if (down) return next[Math.min(col, next.length - 1)];\n const lastRow = Math.floor((next.length - 1) / COLS) * COLS;\n return next[Math.min(lastRow + col, next.length - 1)];\n}\n\nfunction IconGrid({ items, selected, onPick, label, tip }: { items: GridItem[]; selected?: string; onPick: (key: string) => void; label: string; tip: TipHandle }) {\n const ref = React.useRef<HTMLDivElement>(null);\n const stop = items.some((i) => i.key === selected) ? selected : items[0]?.key;\n const move = (e: React.KeyboardEvent) => {\n // one keyboard space across every group in the picker (Recent, the set, search results)\n const scope = ref.current?.closest(\"[data-icon-picker]\") ?? ref.current;\n const grids = Array.from(scope?.querySelectorAll<HTMLElement>(\"[data-icon-grid]\") ?? []).map((g) => Array.from(g.querySelectorAll<HTMLButtonElement>(\"[data-grid-item]\")));\n const btns = grids.flat();\n const i = btns.indexOf(document.activeElement as HTMLButtonElement);\n if (i === -1) return;\n const g = grids.findIndex((list) => list.includes(btns[i]));\n const j = grids[g].indexOf(btns[i]);\n let to: HTMLButtonElement | \"search\" | undefined;\n if (e.key === \"ArrowRight\") to = btns[Math.min(i + 1, btns.length - 1)];\n else if (e.key === \"ArrowLeft\") to = btns[Math.max(i - 1, 0)];\n else if (e.key === \"Home\") to = btns[0];\n else if (e.key === \"End\") to = btns[btns.length - 1];\n else if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") to = verticalTarget(grids, g, j, e.key === \"ArrowDown\") ?? btns[i];\n else return;\n e.preventDefault();\n if (to === \"search\") scope?.querySelector<HTMLInputElement>(\"input[data-icon-search]\")?.focus();\n else to?.focus();\n };\n return (\n <div ref={ref} data-icon-grid className=\"grid gap-0.5\" style={{ gridTemplateColumns: `repeat(${COLS}, minmax(0, 1fr))` }} role=\"listbox\" aria-label={label} onKeyDown={move}>\n {items.map((it) => (\n // one shared tooltip for the whole picker (hundreds of icons): each trigger hands it its label\n <TooltipPrimitive.Trigger\n key={it.key}\n handle={tip}\n payload={it.label}\n delay={500}\n render={\n <button\n type=\"button\"\n role=\"option\"\n data-grid-item\n data-icon={it.key}\n aria-selected={it.key === selected}\n aria-label={it.label}\n tabIndex={it.key === stop ? 0 : -1}\n onClick={() => onPick(it.key)}\n className={cn(\n \"flex aspect-square min-w-0 items-center justify-center overflow-hidden rounded-kit-md text-kit-fg-2 outline-none transition-colors hover:bg-kit-hover hover:text-kit-fg focus-visible:outline-2 focus-visible:outline-kit-focus-ring\",\n it.key === selected && \"bg-kit-selected text-kit-fg ring-1 ring-inset ring-kit-line-strong\",\n )}\n >\n {it.node}\n </button>\n }\n />\n ))}\n </div>\n );\n}\n\nconst NONE = \"__none\";\n\n/** The picker: search, Recent, then the whole set (\"No icon\" first). Search spans the name and its Tabler twin. */\nexport function IconPicker({ value, onPick, onChooseMedia }: { value?: string; onPick: (name: string | null) => void; onChooseMedia?: () => void }) {\n const [q, setQ] = React.useState(\"\");\n const root = React.useRef<HTMLDivElement>(null);\n const tip = React.useMemo(() => TooltipPrimitive.createHandle<string>(), []);\n const needle = norm(q);\n const item = (name: string): GridItem => ({ key: name, label: iconLabel(name), node: <Glyph name={name} className=\"size-[18px]\" /> });\n const pick = (key: string) => onPick(key === NONE ? null : key);\n const hits = needle ? DOCK_ICON_NAMES.filter((n) => n.includes(needle) || tablerIconOf(n).includes(needle)) : [];\n const recent = recents.filter((n) => DOCK_ICON_NAME_SET.has(n));\n return (\n <div ref={root} data-icon-picker className=\"flex flex-col gap-2\">\n <TooltipPrimitive.Root handle={tip}>{({ payload }) => (payload ? <TooltipLayer>{payload}</TooltipLayer> : null)}</TooltipPrimitive.Root>\n <label className=\"flex h-8 items-center gap-2 rounded-kit-md bg-kit-muted px-2.5 text-kit-fg-3 focus-within:bg-kit-field-bg focus-within:ring-1 focus-within:ring-kit-line-strong\">\n <IconSearch className=\"size-4 shrink-0\" stroke={1.5} aria-hidden />\n <input\n autoFocus\n data-icon-search\n value={q}\n onChange={(e) => setQ(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n root.current?.querySelector<HTMLButtonElement>(\"[data-grid-item]\")?.focus();\n }\n }}\n placeholder=\"Search icons\"\n aria-label=\"Search icons\"\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 className=\"max-h-56 overflow-y-auto pr-0.5\">\n {needle ? (\n hits.length ? (\n <IconGrid label=\"Icons\" selected={value} onPick={pick} tip={tip} items={hits.map(item)} />\n ) : (\n <p className=\"py-6 text-center text-kit-sm text-kit-fg-3\">No icons match “{q.trim()}”</p>\n )\n ) : (\n <div className=\"flex flex-col gap-2\">\n {recent.length ? (\n <Group title=\"Recent\">\n <IconGrid label=\"Recent icons\" selected={value} onPick={pick} tip={tip} items={recent.map(item)} />\n </Group>\n ) : null}\n <Group title={recent.length ? \"All icons\" : undefined}>\n <IconGrid\n label=\"Icons\"\n selected={value ?? NONE}\n onPick={pick}\n tip={tip}\n items={[{ key: NONE, label: \"No icon\", node: <IconX className=\"size-4\" stroke={1.5} aria-hidden /> }, ...DOCK_ICON_NAMES.map(item)]}\n />\n </Group>\n </div>\n )}\n </div>\n {onChooseMedia ? (\n <div className=\"flex items-center justify-between gap-2 border-t border-kit-line pt-2\">\n <span className=\"whitespace-nowrap text-kit-xs text-kit-fg-3\">Images keep their colours.</span>\n <Button size=\"xs\" variant=\"ghost\" leftIcon={<IconPhoto stroke={1.5} />} onClick={onChooseMedia}>\n Choose from media\n </Button>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction Group({ title, children }: { title?: string; children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1\">\n {title ? <div className=\"px-0.5 text-kit-2xs font-medium text-kit-fg-3\">{title}</div> : null}\n {children}\n </div>\n );\n}\n\n/* ── The control ──────────────────────────────────────────────────────── */\nexport function IconControl({ field, value, onChange, readOnly, id, invalid }: ControlProps) {\n const { MediaPicker, mediaSrc } = useKitServices();\n const [open, setOpen] = React.useState(false);\n const [mediaOpen, setMediaOpen] = React.useState(false);\n const read = readIcon(value);\n\n const commit = (v: string | null) => {\n onChange(v);\n if (v && DOCK_ICON_NAME_SET.has(v)) pushRecent(v);\n setOpen(false);\n };\n\n const tile =\n read.kind === \"name\" ? (\n <Glyph name={read.name} className=\"size-4\" />\n ) : read.kind === \"upload\" ? (\n <img src={mediaSrc ? mediaSrc(read.url) : read.url} alt=\"\" className=\"size-4 object-contain\" />\n ) : read.kind === \"empty\" ? (\n <span className=\"size-3 rounded-kit-md border border-dashed border-[var(--kit-emphasis-line)]\" />\n ) : (\n <IconAlertTriangle className=\"size-3.5 text-kit-warning-fg\" stroke={1.5} aria-hidden />\n );\n const text =\n read.kind === \"name\"\n ? iconLabel(read.name)\n : read.kind === \"upload\"\n ? fileName(read.url)\n : read.kind === \"unknown\"\n ? `“${read.name}” isn't in the icon set`\n : read.kind === \"unreadable\"\n ? \"This value isn't an icon this picker can read\"\n : \"Choose an icon\";\n const warn = read.kind === \"unknown\" || read.kind === \"unreadable\";\n\n return (\n <>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n render={\n <button\n id={id}\n type=\"button\"\n disabled={readOnly}\n aria-invalid={invalid || undefined}\n className={cn(\n \"flex h-8 w-full min-w-0 items-center gap-2.5 rounded-kit-md border bg-kit-field-bg px-1 pr-2.5 text-left text-kit-sm outline-none transition-colors disabled:opacity-60 focus-visible:border-kit-field-border-focus\",\n invalid ? \"border-[var(--kit-field-invalid)]\" : \"border-kit-line-strong hover:border-kit-field-border-hover data-[popup-open]:border-kit-field-border-focus\",\n )}\n />\n }\n >\n <span className=\"flex size-6 shrink-0 items-center justify-center rounded-kit-md border border-kit-line bg-kit-control-bg text-kit-fg\">{tile}</span>\n <span className={cn(\"min-w-0 flex-1 truncate\", warn ? \"text-kit-warning-fg\" : read.kind === \"empty\" ? \"text-kit-fg-3\" : \"text-kit-fg\")}>{text}</span>\n <IconChevronDown className=\"size-3.5 shrink-0 text-kit-fg-3\" stroke={1.5} aria-hidden />\n </PopoverTrigger>\n <PopoverContent className=\"w-[312px] p-2\" align=\"start\" aria-label={`${field.title}: choose an icon`}>\n <IconPicker\n value={read.kind === \"name\" ? read.name : read.kind === \"empty\" ? undefined : \"\"}\n onPick={commit}\n onChooseMedia={\n MediaPicker\n ? () => {\n setOpen(false);\n setMediaOpen(true);\n }\n : undefined\n }\n />\n </PopoverContent>\n </Popover>\n {MediaPicker && mediaOpen ? (\n <MediaPicker open={mediaOpen} onOpenChange={setMediaOpen} accept={[\"svg\", \"image\"]} onPick={(assets) => assets[0]?.url && commit(assets[0].url)} />\n ) : null}\n </>\n );\n}\n"],"mappings":"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"}
|
package/controls/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/kit/controls/index.ts"],"sourcesContent":["/**\n * The ported kit controls, and the one call that puts them in the engine's CONTROLS / ACTIONS tables (and the scale\n * capsule into the number control). A registered type stops drawing the host's legacy control; a type nobody\n * registers keeps it. The kit barrel calls `registerKitControls()` once, so every host that imports the kit gets them.\n */\nimport { ButtonControl } from \"./button\";\nimport { LinkControl } from \"./link\";\nimport { registerC1Controls } from \"./c1\";\nimport { registerC2Controls } from \"./c2\";\nimport { CONTROLS } from \"../engine/kit-field\";\n\nexport * from \"./c1\";\nexport * from \"./c2\";\nexport { LinkControl, LinkField, LinkForm, LinkLine, SectionAnchorsProvider, type LinkTarget, type KitLinkServices, type SectionAnchor } from \"./link\";\nexport { ButtonControl, ButtonScreen } from \"./button\";\n\nexport function registerKitControls() {\n registerC1Controls();\n registerC2Controls();\n CONTROLS.link = LinkControl;\n CONTROLS.button = ButtonControl;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,SAAgB,sBAAsB;AACpC,qBAAoB;AACpB,qBAAoB;AACpB,UAAS,OAAO;AAChB,UAAS,SAAS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"json-register.js","names":[],"sources":["../../src/kit/controls/json-register.ts"],"sourcesContent":["/** Lane C3: the json field in the engine's dispatch table (one line per type; merge with other lanes by line). */\nimport { CONTROLS } from \"../engine/kit-field\";\nimport { JsonControl } from \"./json\";\n\nCONTROLS.json = JsonControl;\n"],"mappings":";;;;AAIA,SAAS,OAAO"}
|
package/controls/json.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"json.js","names":[],"sources":["../../src/kit/controls/json.tsx"],"sourcesContent":["/**\n * JSON — the json field (DESIGN 8.21), on the code surface (code.tsx).\n *\n * Values: whatever JSON the field holds (an object, a list, a number, or a JSON string a textarea wrote). An edit is\n * written PARSED, the way the classic JsonField writes it, and an emptied box writes null; the backend takes both.\n * Text that does not parse is never written: the panel's Done refuses with \"Invalid JSON · {reason}\", the inline\n * (document) surface keeps the last valid value and shows the reason under the code.\n */\nimport * as React from \"react\";\nimport { useKitEnv } from \"../context\";\nimport type { ControlProps } from \"../types\";\nimport { CodeDialogField, CodeSurface, jsonProblem } from \"./code\";\n\n/** The text a stored JSON value is edited as. */\nconst jsonText = (v: unknown): string => (v == null || v === \"\" ? \"\" : typeof v === \"string\" ? v : JSON.stringify(v, null, 2));\nconst parse = (text: string): unknown => (text.trim() ? JSON.parse(text) : null);\n\nexport function JsonControl({ field, value, onChange, readOnly, id, invalid }: ControlProps) {\n const { variant } = useKitEnv();\n const text = jsonText(value);\n if (variant === \"document\") return <InlineJson id={id} value={value} text={text} onChange={onChange} readOnly={readOnly} invalid={invalid} />;\n return (\n <CodeDialogField\n kind=\"json\"\n id={id}\n title={field.title}\n description={field.description || undefined}\n text={text}\n readOnly={readOnly}\n invalid={invalid}\n onDone={(draft) => {\n if (draft === text) return null; // nothing edited: Done closes even over a stored string that isn't JSON\n const why = jsonProblem(draft);\n if (why) return `Invalid JSON · ${why}`;\n if (draft !== text) onChange(parse(draft));\n return null;\n }}\n />\n );\n}\n\n/** The document variant: the surface inline over a draft that survives invalid intermediates. */\nfunction InlineJson({ id, value, text, onChange, readOnly, invalid }: { id: string; value: unknown; text: string; onChange: (v: unknown) => void; readOnly?: boolean; invalid?: boolean }) {\n const [draft, setDraft] = React.useState(text);\n const [mine, setMine] = React.useState<unknown>(undefined);\n const [seen, setSeen] = React.useState(value);\n // a value set from elsewhere (undo, another editor) replaces the draft; our own writes keep the author's text\n if (value !== seen) {\n setSeen(value);\n if (value !== mine) setDraft(text);\n }\n return (\n <CodeSurface\n kind=\"json\"\n id={id}\n invalid={invalid}\n readOnly={readOnly}\n value={draft}\n onChange={(next) => {\n setDraft(next);\n if (jsonProblem(next)) return;\n const parsed = parse(next);\n setMine(parsed);\n onChange(parsed);\n }}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,IAAM,YAAY,MAAwB,KAAK,QAAQ,MAAM,KAAK,KAAK,OAAO,MAAM,WAAW,IAAI,KAAK,UAAU,GAAG,MAAM,EAAE;AAC7H,IAAM,SAAS,SAA2B,KAAK,MAAM,GAAG,KAAK,MAAM,KAAK,GAAG;AAE3E,SAAgB,YAAY,EAAE,OAAO,OAAO,UAAU,UAAU,IAAI,WAAyB;CAC3F,MAAM,EAAE,YAAY,WAAW;CAC/B,MAAM,OAAO,SAAS,MAAM;AAC5B,KAAI,YAAY,WAAY,QAAO,oBAAC,YAAD;EAAgB;EAAW;EAAa;EAAgB;EAAoB;EAAmB;EAAW,CAAA;AAC7I,QACE,oBAAC,iBAAD;EACE,MAAK;EACD;EACJ,OAAO,MAAM;EACb,aAAa,MAAM,eAAe,KAAA;EAC5B;EACI;EACD;EACT,SAAS,UAAU;AACjB,OAAI,UAAU,KAAM,QAAO;GAC3B,MAAM,MAAM,YAAY,MAAM;AAC9B,OAAI,IAAK,QAAO,kBAAkB;AAClC,OAAI,UAAU,KAAM,UAAS,MAAM,MAAM,CAAC;AAC1C,UAAO;;EAET,CAAA;;;AAKN,SAAS,WAAW,EAAE,IAAI,OAAO,MAAM,UAAU,UAAU,WAAgI;CACzL,MAAM,CAAC,OAAO,YAAY,MAAM,SAAS,KAAK;CAC9C,MAAM,CAAC,MAAM,WAAW,MAAM,SAAkB,KAAA,EAAU;CAC1D,MAAM,CAAC,MAAM,WAAW,MAAM,SAAS,MAAM;AAE7C,KAAI,UAAU,MAAM;AAClB,UAAQ,MAAM;AACd,MAAI,UAAU,KAAM,UAAS,KAAK;;AAEpC,QACE,oBAAC,aAAD;EACE,MAAK;EACD;EACK;EACC;EACV,OAAO;EACP,WAAW,SAAS;AAClB,YAAS,KAAK;AACd,OAAI,YAAY,KAAK,CAAE;GACvB,MAAM,SAAS,MAAM,KAAK;AAC1B,WAAQ,OAAO;AACf,YAAS,OAAO;;EAElB,CAAA"}
|