@bettercms-ai/kit 1.0.0 → 2.0.0-next.1
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 +94 -31
- package/dist/adapters/lossy.js +419 -0
- package/dist/adapters/lossy.js.map +1 -0
- package/{adapters → dist/adapters}/prod-types.d.ts +91 -26
- package/{adapters → dist/adapters}/prod-types.js +82 -13
- package/dist/adapters/prod-types.js.map +1 -0
- package/{adapters → dist/adapters}/schema.d.ts +40 -1
- package/{adapters → dist/adapters}/schema.js +1038 -204
- 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} +131 -2
- package/{context.js → dist/context.js} +44 -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/dist/controls/form-picker-register.d.ts +7 -0
- package/{controls → dist/controls}/form-picker-register.js +2 -6
- 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 +116 -200
- 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 +59 -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 +21 -4
- package/{controls → dist/controls}/media.js +407 -130
- 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/article-shell.d.ts +145 -0
- package/dist/controls/rich-text/article-shell.js +510 -0
- package/dist/controls/rich-text/article-shell.js.map +1 -0
- package/dist/controls/rich-text/author.d.ts +25 -0
- package/dist/controls/rich-text/author.js +104 -0
- package/dist/controls/rich-text/author.js.map +1 -0
- package/dist/controls/rich-text/blocks.d.ts +60 -0
- package/{controls → dist/controls}/rich-text/blocks.js +164 -389
- package/dist/controls/rich-text/blocks.js.map +1 -0
- package/dist/controls/rich-text/button.d.ts +23 -0
- package/dist/controls/rich-text/button.js +85 -0
- package/dist/controls/rich-text/button.js.map +1 -0
- package/{controls → dist/controls}/rich-text/catalog.d.ts +7 -4
- package/{controls → dist/controls}/rich-text/catalog.js +94 -68
- package/dist/controls/rich-text/catalog.js.map +1 -0
- package/dist/controls/rich-text/checklist.d.ts +24 -0
- package/dist/controls/rich-text/checklist.js +115 -0
- package/dist/controls/rich-text/checklist.js.map +1 -0
- package/{controls → dist/controls}/rich-text/codec.d.ts +9 -1
- package/{controls → dist/controls}/rich-text/codec.js +7 -2
- package/dist/controls/rich-text/codec.js.map +1 -0
- package/dist/controls/rich-text/columns.d.ts +41 -0
- package/dist/controls/rich-text/columns.js +181 -0
- package/dist/controls/rich-text/columns.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 +53 -9
- package/{controls → dist/controls}/rich-text/dom.js +388 -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 +226 -44
- package/dist/controls/rich-text/editor.js.map +1 -0
- package/dist/controls/rich-text/embed.d.ts +28 -0
- package/dist/controls/rich-text/embed.js +210 -0
- package/dist/controls/rich-text/embed.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/dist/controls/rich-text/footnote.d.ts +41 -0
- package/dist/controls/rich-text/footnote.js +185 -0
- package/dist/controls/rich-text/footnote.js.map +1 -0
- package/dist/controls/rich-text/gallery.d.ts +28 -0
- package/dist/controls/rich-text/gallery.js +167 -0
- package/dist/controls/rich-text/gallery.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/{controls → dist/controls}/rich-text/link-form.d.ts +3 -1
- 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/dist/controls/rich-text/related.d.ts +36 -0
- package/dist/controls/rich-text/related.js +213 -0
- package/dist/controls/rich-text/related.js.map +1 -0
- package/dist/controls/rich-text/toc.d.ts +46 -0
- package/dist/controls/rich-text/toc.js +161 -0
- package/dist/controls/rich-text/toc.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/dist/controls/slot-register.d.ts +6 -0
- package/{controls → dist/controls}/slot-register.js +2 -5
- 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 +70 -0
- package/dist/core/core.js +187 -0
- package/dist/core/core.js.map +1 -0
- package/dist/core/facets.d.ts +355 -0
- package/dist/core/facets.js +342 -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 +58 -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 +1511 -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 +36 -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 +58 -0
- package/dist/ui/autocomplete.js +194 -0
- package/dist/ui/autocomplete.js.map +1 -0
- package/{ui → dist/ui}/button.d.ts +3 -3
- package/{ui → dist/ui}/button.js +8 -11
- 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 +83 -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.d.ts +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.d.ts +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.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/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.d.ts +0 -0
- /package/{controls → dist/controls}/table/index.d.ts +0 -0
- /package/{controls → dist/controls}/table/prod.d.ts +0 -0
- /package/{controls → dist/controls}/table/refs.d.ts +0 -0
- /package/{controls → dist/controls}/table/stored.d.ts +0 -0
- /package/{controls → dist/controls}/table/table-editor.d.ts +0 -0
- /package/{controls → dist/controls}/table/table-link.d.ts +0 -0
- /package/{controls → dist/controls}/table/table.d.ts +0 -0
- /package/{engine → dist/engine}/array.d.ts +0 -0
- /package/{engine → dist/engine}/bits.d.ts +0 -0
- /package/{engine → dist/engine}/field-list.d.ts +0 -0
- /package/{engine → dist/engine}/field-shell.d.ts +0 -0
- /package/{engine → dist/engine}/kit-field.d.ts +0 -0
- /package/{engine → dist/engine}/slot.d.ts +0 -0
- /package/{index.d.ts → dist/index.d.ts} +0 -0
- /package/{lib → dist/lib}/cn.d.ts +0 -0
- /package/{lib → dist/lib}/columns.d.ts +0 -0
- /package/{lib → dist/lib}/frames.d.ts +0 -0
- /package/{lib → dist/lib}/icons.d.ts +0 -0
- /package/{lib → dist/lib}/path.d.ts +0 -0
- /package/{lib → dist/lib}/utils.d.ts +0 -0
- /package/{schema → dist/schema}/adapters.d.ts +0 -0
- /package/{schema → dist/schema}/scale.d.ts +0 -0
- /package/{schema → dist/schema}/sources.d.ts +0 -0
- /package/{schema → dist/schema}/table.d.ts +0 -0
- /package/{types.d.ts → dist/types.d.ts} +0 -0
- /package/{ui → dist/ui}/choice-switch.d.ts +0 -0
- /package/{ui → dist/ui}/controls.d.ts +0 -0
- /package/{ui → dist/ui}/field-context.d.ts +0 -0
- /package/{ui → dist/ui}/mode-bar.d.ts +0 -0
- /package/{ui → dist/ui}/path-crumbs.d.ts +0 -0
- /package/{ui → dist/ui}/presence.d.ts +0 -0
- /package/{ui → dist/ui}/select.d.ts +0 -0
- /package/{ui → dist/ui}/shortcut-hint.d.ts +0 -0
- /package/{ui → dist/ui}/surfaces.d.ts +0 -0
- /package/{ui → dist/ui}/variants.d.ts +0 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type SelectOption } from "./select";
|
|
3
|
+
export interface AutocompleteProps {
|
|
4
|
+
id?: string;
|
|
5
|
+
"aria-label"?: string;
|
|
6
|
+
"aria-describedby"?: string;
|
|
7
|
+
/** the text (controlled) */
|
|
8
|
+
value?: string;
|
|
9
|
+
defaultValue?: string;
|
|
10
|
+
/** every keystroke, and the label of a picked suggestion */
|
|
11
|
+
onValueChange?: (text: string) => void;
|
|
12
|
+
options: SelectOption[];
|
|
13
|
+
/** a suggestion was picked (click, or Enter on a highlighted row) */
|
|
14
|
+
onSelect?: (option: SelectOption) => void;
|
|
15
|
+
/** Enter with no suggestion highlighted: commit the typed text */
|
|
16
|
+
onEnter?: (text: string) => void;
|
|
17
|
+
/** default: Select's ranking; null = the caller already filtered (async options) */
|
|
18
|
+
filter?: ((options: SelectOption[], query: string) => SelectOption[]) | null;
|
|
19
|
+
placeholder?: string;
|
|
20
|
+
size?: "sm" | "md" | "lg";
|
|
21
|
+
/** decorative icon before the input */
|
|
22
|
+
leading?: React.ReactNode;
|
|
23
|
+
/** an interactive control inside the field before the input (the link-type menu); rendered as is */
|
|
24
|
+
leadingSlot?: React.ReactNode;
|
|
25
|
+
loading?: boolean;
|
|
26
|
+
invalid?: boolean;
|
|
27
|
+
disabled?: boolean;
|
|
28
|
+
/** open the suggestions when the field takes focus (default true, as V2) */
|
|
29
|
+
openOnFocus?: boolean;
|
|
30
|
+
/** controlled open; the list shows while open and it has rows or a note */
|
|
31
|
+
open?: boolean;
|
|
32
|
+
onOpenChange?: (open: boolean) => void;
|
|
33
|
+
/** render the list in the flow under the field instead of a floating popup (panels, popovers) */
|
|
34
|
+
inlineList?: boolean;
|
|
35
|
+
/** a status row shown, with the list kept open, when no row matches */
|
|
36
|
+
emptyNote?: React.ReactNode;
|
|
37
|
+
/** a status row under the rows when there are rows (a partial-load error) */
|
|
38
|
+
listNote?: React.ReactNode;
|
|
39
|
+
/** highlight row 0 on every keystroke that leaves text, so Enter picks it; empty text highlights nothing */
|
|
40
|
+
highlightFirst?: boolean;
|
|
41
|
+
/** emphasise the query inside row labels (default true; V2's link rows draw the plain title) */
|
|
42
|
+
highlightMatches?: boolean;
|
|
43
|
+
/** the listbox's accessible name */
|
|
44
|
+
listLabel?: string;
|
|
45
|
+
/** a pick also writes the row's label into the text (default true); false = a pick only calls onSelect */
|
|
46
|
+
fillOnSelect?: boolean;
|
|
47
|
+
/** replaces the built-in clear (setText("")) on the X */
|
|
48
|
+
onClear?: () => void;
|
|
49
|
+
/** a control inside the field after the clear button (the file-library button) */
|
|
50
|
+
trailingSlot?: React.ReactNode;
|
|
51
|
+
/** data-* attributes on the list's layer (the floating positioner, or the inline wrapper) */
|
|
52
|
+
listAttrs?: Record<`data-${string}`, string>;
|
|
53
|
+
inputRef?: React.Ref<HTMLInputElement>;
|
|
54
|
+
onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
|
|
55
|
+
className?: string;
|
|
56
|
+
menuClassName?: string;
|
|
57
|
+
}
|
|
58
|
+
export declare function Autocomplete({ id, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, value, defaultValue, onValueChange, options, onSelect, onEnter, filter, placeholder, size, leading, leadingSlot, loading, invalid, disabled, openOnFocus, open: openProp, onOpenChange, inlineList, emptyNote, listNote, highlightFirst, highlightMatches, listLabel, fillOnSelect, onClear, trailingSlot, listAttrs, inputRef, onBlur, className, menuClassName, }: AutocompleteProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { cn } from "../lib/cn.js";
|
|
2
|
+
import { useFieldDescribedBy, useFieldId, useFieldLabelledBy, useLabelFor } from "./field-context.js";
|
|
3
|
+
import { Spinner } from "./spinner.js";
|
|
4
|
+
import { KIT_SCOPE } from "./surfaces.js";
|
|
5
|
+
import { IconButton } from "./button.js";
|
|
6
|
+
import { Highlight, filterOptions, nodeText } from "./select.js";
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { IconX } from "@tabler/icons-react";
|
|
10
|
+
import { Autocomplete as Autocomplete$1 } from "@base-ui/react/autocomplete";
|
|
11
|
+
//#region src/ui/autocomplete.tsx
|
|
12
|
+
var H = {
|
|
13
|
+
sm: "h-7",
|
|
14
|
+
md: "h-8",
|
|
15
|
+
lg: "h-9"
|
|
16
|
+
};
|
|
17
|
+
var NOTE = "px-2 py-1.5 text-kit-xs text-kit-fg-3";
|
|
18
|
+
function Autocomplete({ id, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, value, defaultValue = "", onValueChange, options, onSelect, onEnter, filter = filterOptions, placeholder, size = "md", leading, leadingSlot, loading, invalid, disabled, openOnFocus = true, open: openProp, onOpenChange, inlineList = false, emptyNote, listNote, highlightFirst = false, highlightMatches = true, listLabel, fillOnSelect = true, onClear, trailingSlot, listAttrs, inputRef, onBlur, className, menuClassName }) {
|
|
19
|
+
const fieldId = useFieldId();
|
|
20
|
+
const labelledBy = useFieldLabelledBy();
|
|
21
|
+
const labelFor = useLabelFor(id ?? fieldId);
|
|
22
|
+
const describedBy = useFieldDescribedBy();
|
|
23
|
+
const [inner, setInner] = React.useState(defaultValue);
|
|
24
|
+
const text = value ?? inner;
|
|
25
|
+
const setText = (t) => {
|
|
26
|
+
if (value === void 0) setInner(t);
|
|
27
|
+
onValueChange?.(t);
|
|
28
|
+
};
|
|
29
|
+
const [innerOpen, setInnerOpen] = React.useState(false);
|
|
30
|
+
const open = openProp ?? innerOpen;
|
|
31
|
+
const setOpen = (o) => {
|
|
32
|
+
if (openProp === void 0) setInnerOpen(o);
|
|
33
|
+
onOpenChange?.(o);
|
|
34
|
+
};
|
|
35
|
+
const [highlighted, setHighlighted] = React.useState(void 0);
|
|
36
|
+
const shown = React.useMemo(() => filter ? filter(options, text) : options, [
|
|
37
|
+
filter,
|
|
38
|
+
options,
|
|
39
|
+
text
|
|
40
|
+
]);
|
|
41
|
+
const hasEmptyNote = emptyNote != null && emptyNote !== false;
|
|
42
|
+
const visible = open && (shown.length > 0 || hasEmptyNote);
|
|
43
|
+
const firstStandsIn = highlightFirst && visible && text.trim() !== "" && !highlighted && shown.length > 0 && !shown[0].disabled;
|
|
44
|
+
const pick = (o) => {
|
|
45
|
+
onSelect?.(o);
|
|
46
|
+
if (fillOnSelect) setText(nodeText(o.label));
|
|
47
|
+
setOpen(false);
|
|
48
|
+
};
|
|
49
|
+
const named = id ?? fieldId ?? ariaLabel;
|
|
50
|
+
const rows = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
51
|
+
/* @__PURE__ */ jsx(Autocomplete$1.List, {
|
|
52
|
+
"aria-label": listLabel,
|
|
53
|
+
className: "max-h-72 overflow-y-auto overscroll-contain empty:hidden",
|
|
54
|
+
children: shown.map((o, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [o.group && (i === 0 || shown[i - 1].group !== o.group) ? /* @__PURE__ */ jsx("div", {
|
|
55
|
+
role: "presentation",
|
|
56
|
+
className: "px-2 pb-1 pt-2 text-kit-xs font-medium text-kit-fg-3 first:pt-1",
|
|
57
|
+
children: o.group
|
|
58
|
+
}) : null, /* @__PURE__ */ jsxs(Autocomplete$1.Item, {
|
|
59
|
+
value: o,
|
|
60
|
+
disabled: o.disabled,
|
|
61
|
+
onClick: () => onSelect?.(o),
|
|
62
|
+
"data-first-active": firstStandsIn && i === 0 ? "" : void 0,
|
|
63
|
+
className: "flex h-8 cursor-pointer select-none items-center gap-2 rounded-kit-md px-2 text-kit-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-40 data-[highlighted]:bg-kit-hover data-[first-active]:bg-kit-hover",
|
|
64
|
+
children: [
|
|
65
|
+
o.icon ? /* @__PURE__ */ jsx("span", {
|
|
66
|
+
"aria-hidden": true,
|
|
67
|
+
className: "flex shrink-0 text-kit-fg-3 [&_svg]:size-4",
|
|
68
|
+
children: o.icon
|
|
69
|
+
}) : null,
|
|
70
|
+
/* @__PURE__ */ jsx("span", {
|
|
71
|
+
className: "min-w-0 shrink truncate text-kit-fg",
|
|
72
|
+
children: highlightMatches && typeof o.label === "string" ? /* @__PURE__ */ jsx(Highlight, {
|
|
73
|
+
text: o.label,
|
|
74
|
+
query: text
|
|
75
|
+
}) : o.label
|
|
76
|
+
}),
|
|
77
|
+
o.description ? /* @__PURE__ */ jsx("span", {
|
|
78
|
+
className: "min-w-0 flex-1 truncate text-kit-xs text-kit-fg-3",
|
|
79
|
+
children: o.description
|
|
80
|
+
}) : /* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
81
|
+
o.meta ? /* @__PURE__ */ jsx("span", {
|
|
82
|
+
className: "shrink-0 text-kit-2xs text-kit-fg-3",
|
|
83
|
+
children: o.meta
|
|
84
|
+
}) : null
|
|
85
|
+
]
|
|
86
|
+
})] }, o.value))
|
|
87
|
+
}),
|
|
88
|
+
shown.length === 0 && hasEmptyNote ? /* @__PURE__ */ jsx("p", {
|
|
89
|
+
role: "status",
|
|
90
|
+
className: NOTE,
|
|
91
|
+
children: emptyNote
|
|
92
|
+
}) : null,
|
|
93
|
+
shown.length > 0 && listNote != null && listNote !== false ? /* @__PURE__ */ jsx("p", {
|
|
94
|
+
role: "status",
|
|
95
|
+
className: NOTE,
|
|
96
|
+
children: listNote
|
|
97
|
+
}) : null
|
|
98
|
+
] });
|
|
99
|
+
return /* @__PURE__ */ jsxs(Autocomplete$1.Root, {
|
|
100
|
+
items: shown,
|
|
101
|
+
filter: null,
|
|
102
|
+
mode: "list",
|
|
103
|
+
value: text,
|
|
104
|
+
onValueChange: (t, details) => {
|
|
105
|
+
if (!fillOnSelect && details.reason === "item-press") return;
|
|
106
|
+
setText(t);
|
|
107
|
+
},
|
|
108
|
+
itemToStringValue: (o) => nodeText(o.label),
|
|
109
|
+
open: visible,
|
|
110
|
+
onOpenChange: setOpen,
|
|
111
|
+
inline: inlineList,
|
|
112
|
+
autoHighlight: highlightFirst,
|
|
113
|
+
onItemHighlighted: (o) => setHighlighted(o),
|
|
114
|
+
openOnInputClick: true,
|
|
115
|
+
loopFocus: true,
|
|
116
|
+
disabled,
|
|
117
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
118
|
+
className: cn("flex min-w-0 items-center rounded-kit-md border border-kit-field-border bg-kit-field-bg shadow-kit-field transition-[border-color,box-shadow] duration-150 hover:border-kit-field-border-hover focus-within:border-kit-field-border-focus focus-within:shadow-kit-ring-field", invalid && "border-[var(--kit-field-invalid)] hover:border-[var(--kit-field-invalid)]", disabled && "cursor-not-allowed bg-kit-subtle opacity-60", H[size], className),
|
|
119
|
+
children: [
|
|
120
|
+
leadingSlot,
|
|
121
|
+
leading ? /* @__PURE__ */ jsx("span", {
|
|
122
|
+
"aria-hidden": true,
|
|
123
|
+
className: "ml-2.5 flex shrink-0 text-kit-fg-3 [&_svg]:size-4",
|
|
124
|
+
children: leading
|
|
125
|
+
}) : null,
|
|
126
|
+
/* @__PURE__ */ jsx(Autocomplete$1.Input, {
|
|
127
|
+
ref: inputRef,
|
|
128
|
+
id: id ?? fieldId,
|
|
129
|
+
"aria-label": ariaLabel,
|
|
130
|
+
"aria-labelledby": ariaLabel ? void 0 : labelFor ?? (named ? void 0 : labelledBy),
|
|
131
|
+
"aria-describedby": [ariaDescribedBy, describedBy].filter(Boolean).join(" ") || void 0,
|
|
132
|
+
"aria-invalid": invalid || void 0,
|
|
133
|
+
placeholder,
|
|
134
|
+
autoComplete: "off",
|
|
135
|
+
spellCheck: false,
|
|
136
|
+
onFocus: () => openOnFocus && setOpen(true),
|
|
137
|
+
onBlur,
|
|
138
|
+
onKeyDownCapture: (e) => {
|
|
139
|
+
if (e.key === "Escape" && visible) {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
e.stopPropagation();
|
|
142
|
+
setOpen(false);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
onKeyDown: (e) => {
|
|
146
|
+
if (e.key !== "Enter") return;
|
|
147
|
+
if (firstStandsIn) {
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
pick(shown[0]);
|
|
150
|
+
} else if (!highlighted || !visible) onEnter?.(text);
|
|
151
|
+
},
|
|
152
|
+
className: "h-full min-w-0 flex-1 bg-transparent px-2 text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3 disabled:cursor-not-allowed"
|
|
153
|
+
}),
|
|
154
|
+
loading ? /* @__PURE__ */ jsx(Spinner, {
|
|
155
|
+
size: "sm",
|
|
156
|
+
tone: "muted",
|
|
157
|
+
label: "Loading suggestions",
|
|
158
|
+
className: "mr-2"
|
|
159
|
+
}) : text && !disabled ? /* @__PURE__ */ jsx(IconButton, {
|
|
160
|
+
label: "Clear",
|
|
161
|
+
size: "xs",
|
|
162
|
+
variant: "ghost",
|
|
163
|
+
className: "mr-1",
|
|
164
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
165
|
+
onClick: () => onClear ? onClear() : setText(""),
|
|
166
|
+
children: /* @__PURE__ */ jsx(IconX, { stroke: 1.5 })
|
|
167
|
+
}) : null,
|
|
168
|
+
trailingSlot
|
|
169
|
+
]
|
|
170
|
+
}), inlineList ? visible ? /* @__PURE__ */ jsx("div", {
|
|
171
|
+
...listAttrs,
|
|
172
|
+
className: cn("mt-1 rounded-kit-md border border-kit-line bg-kit-surface p-1", menuClassName),
|
|
173
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
174
|
+
children: rows
|
|
175
|
+
}) : null : /* @__PURE__ */ jsx(Autocomplete$1.Portal, { children: /* @__PURE__ */ jsx(Autocomplete$1.Positioner, {
|
|
176
|
+
align: "start",
|
|
177
|
+
side: "bottom",
|
|
178
|
+
sideOffset: 4,
|
|
179
|
+
collisionPadding: 12,
|
|
180
|
+
className: "z-[var(--kit-z-menu,80)]",
|
|
181
|
+
"data-floating-layer": "",
|
|
182
|
+
...KIT_SCOPE,
|
|
183
|
+
...listAttrs,
|
|
184
|
+
children: /* @__PURE__ */ jsx(Autocomplete$1.Popup, {
|
|
185
|
+
className: cn("w-[max(var(--anchor-width),280px)] max-w-[min(420px,calc(100vw-24px))] rounded-kit-lg border bg-kit-surface p-1 text-kit-fg shadow-lg outline-none data-[open]:animate-kit-pop-in", menuClassName),
|
|
186
|
+
children: rows
|
|
187
|
+
})
|
|
188
|
+
}) })]
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
//#endregion
|
|
192
|
+
export { Autocomplete };
|
|
193
|
+
|
|
194
|
+
//# sourceMappingURL=autocomplete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autocomplete.js","names":[],"sources":["../../src/ui/autocomplete.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Autocomplete as AutocompletePrimitive } from \"@base-ui/react/autocomplete\";\nimport { IconX } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { IconButton } from \"./button\";\nimport { useFieldDescribedBy, useFieldId, useFieldLabelledBy, useLabelFor } from \"./field-context\";\nimport { filterOptions, Highlight, nodeText, type SelectOption } from \"./select\";\nimport { Spinner } from \"./spinner\";\nimport { KIT_SCOPE } from \"./surfaces\";\n\n/* ── Autocomplete ────────────────────────────────────────────────────────\n Free text with suggestions: the value is whatever is typed; a suggestion fills it in. Select only picks fixed options.\n V2 has no component, only the pattern (kit controls link.tsx:504-650, invite-flow.tsx:197); kit-ports-spec.md §2.\n Field = the Input look; the list opens on focus or typing, only while it has rows (free text is a valid value, so\n there is no \"No matches\"); nothing is highlighted until the arrows move, so Enter commits the typed text (onEnter).\n Ranking is Select's filterOptions + Highlight.\n The link field (LinkPicker) opts into V2 link.tsx's extras: an in-flow list (inlineList), a status note when nothing\n matches (emptyNote) or under the rows (listNote), the link-type menu inside the field (leadingSlot), row 0 highlighted\n while typing (highlightFirst), a controlled open, plain row titles (highlightMatches={false}), and Escape that closes\n only the list while it is open (link.tsx:603-618). */\n\nexport interface AutocompleteProps {\n id?: string;\n \"aria-label\"?: string;\n \"aria-describedby\"?: string;\n /** the text (controlled) */\n value?: string;\n defaultValue?: string;\n /** every keystroke, and the label of a picked suggestion */\n onValueChange?: (text: string) => void;\n options: SelectOption[];\n /** a suggestion was picked (click, or Enter on a highlighted row) */\n onSelect?: (option: SelectOption) => void;\n /** Enter with no suggestion highlighted: commit the typed text */\n onEnter?: (text: string) => void;\n /** default: Select's ranking; null = the caller already filtered (async options) */\n filter?: ((options: SelectOption[], query: string) => SelectOption[]) | null;\n placeholder?: string;\n size?: \"sm\" | \"md\" | \"lg\";\n /** decorative icon before the input */\n leading?: React.ReactNode;\n /** an interactive control inside the field before the input (the link-type menu); rendered as is */\n leadingSlot?: React.ReactNode;\n loading?: boolean;\n invalid?: boolean;\n disabled?: boolean;\n /** open the suggestions when the field takes focus (default true, as V2) */\n openOnFocus?: boolean;\n /** controlled open; the list shows while open and it has rows or a note */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** render the list in the flow under the field instead of a floating popup (panels, popovers) */\n inlineList?: boolean;\n /** a status row shown, with the list kept open, when no row matches */\n emptyNote?: React.ReactNode;\n /** a status row under the rows when there are rows (a partial-load error) */\n listNote?: React.ReactNode;\n /** highlight row 0 on every keystroke that leaves text, so Enter picks it; empty text highlights nothing */\n highlightFirst?: boolean;\n /** emphasise the query inside row labels (default true; V2's link rows draw the plain title) */\n highlightMatches?: boolean;\n /** the listbox's accessible name */\n listLabel?: string;\n /** a pick also writes the row's label into the text (default true); false = a pick only calls onSelect */\n fillOnSelect?: boolean;\n /** replaces the built-in clear (setText(\"\")) on the X */\n onClear?: () => void;\n /** a control inside the field after the clear button (the file-library button) */\n trailingSlot?: React.ReactNode;\n /** data-* attributes on the list's layer (the floating positioner, or the inline wrapper) */\n listAttrs?: Record<`data-${string}`, string>;\n inputRef?: React.Ref<HTMLInputElement>;\n onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;\n className?: string;\n menuClassName?: string;\n}\n\nconst H = { sm: \"h-7\", md: \"h-8\", lg: \"h-9\" } as const;\n/* V2 link.tsx:507-509 */\nconst NOTE = \"px-2 py-1.5 text-kit-xs text-kit-fg-3\";\n\nexport function Autocomplete({\n id,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n value,\n defaultValue = \"\",\n onValueChange,\n options,\n onSelect,\n onEnter,\n filter = filterOptions,\n placeholder,\n size = \"md\",\n leading,\n leadingSlot,\n loading,\n invalid,\n disabled,\n openOnFocus = true,\n open: openProp,\n onOpenChange,\n inlineList = false,\n emptyNote,\n listNote,\n highlightFirst = false,\n highlightMatches = true,\n listLabel,\n fillOnSelect = true,\n onClear,\n trailingSlot,\n listAttrs,\n inputRef,\n onBlur,\n className,\n menuClassName,\n}: AutocompleteProps) {\n const fieldId = useFieldId();\n const labelledBy = useFieldLabelledBy();\n const labelFor = useLabelFor(id ?? fieldId);\n const describedBy = useFieldDescribedBy();\n const [inner, setInner] = React.useState(defaultValue);\n const text = value ?? inner;\n const setText = (t: string) => {\n if (value === undefined) setInner(t);\n onValueChange?.(t);\n };\n const [innerOpen, setInnerOpen] = React.useState(false);\n const open = openProp ?? innerOpen;\n const setOpen = (o: boolean) => {\n if (openProp === undefined) setInnerOpen(o);\n onOpenChange?.(o);\n };\n const [highlighted, setHighlighted] = React.useState<SelectOption | undefined>(undefined);\n const shown = React.useMemo(() => (filter ? filter(options, text) : options), [filter, options, text]);\n const hasEmptyNote = emptyNote != null && emptyNote !== false;\n const visible = open && (shown.length > 0 || hasEmptyNote);\n /* highlightFirst: row 0 stands in as the active row while text is typed and nothing else is highlighted (V2\n link.tsx sets its own active index to 0 on each keystroke); Base UI's autoHighlight normally does the same. */\n const firstStandsIn = highlightFirst && visible && text.trim() !== \"\" && !highlighted && shown.length > 0 && !shown[0].disabled;\n const pick = (o: SelectOption) => {\n onSelect?.(o);\n if (fillOnSelect) setText(nodeText(o.label));\n setOpen(false);\n };\n const named = id ?? fieldId ?? ariaLabel;\n\n const rows = (\n <>\n <AutocompletePrimitive.List aria-label={listLabel} className=\"max-h-72 overflow-y-auto overscroll-contain empty:hidden\">\n {shown.map((o, i) => (\n <React.Fragment key={o.value}>\n {o.group && (i === 0 || shown[i - 1].group !== o.group) ? (\n <div role=\"presentation\" className=\"px-2 pb-1 pt-2 text-kit-xs font-medium text-kit-fg-3 first:pt-1\">\n {o.group}\n </div>\n ) : null}\n <AutocompletePrimitive.Item\n value={o}\n disabled={o.disabled}\n onClick={() => onSelect?.(o)}\n data-first-active={firstStandsIn && i === 0 ? \"\" : undefined}\n className=\"flex h-8 cursor-pointer select-none items-center gap-2 rounded-kit-md px-2 text-kit-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-40 data-[highlighted]:bg-kit-hover data-[first-active]:bg-kit-hover\"\n >\n {o.icon ? (\n <span aria-hidden className=\"flex shrink-0 text-kit-fg-3 [&_svg]:size-4\">\n {o.icon}\n </span>\n ) : null}\n <span className=\"min-w-0 shrink truncate text-kit-fg\">\n {highlightMatches && typeof o.label === \"string\" ? <Highlight text={o.label} query={text} /> : o.label}\n </span>\n {o.description ? <span className=\"min-w-0 flex-1 truncate text-kit-xs text-kit-fg-3\">{o.description}</span> : <span className=\"flex-1\" />}\n {o.meta ? <span className=\"shrink-0 text-kit-2xs text-kit-fg-3\">{o.meta}</span> : null}\n </AutocompletePrimitive.Item>\n </React.Fragment>\n ))}\n </AutocompletePrimitive.List>\n {shown.length === 0 && hasEmptyNote ? (\n <p role=\"status\" className={NOTE}>\n {emptyNote}\n </p>\n ) : null}\n {shown.length > 0 && listNote != null && listNote !== false ? (\n <p role=\"status\" className={NOTE}>\n {listNote}\n </p>\n ) : null}\n </>\n );\n\n return (\n <AutocompletePrimitive.Root\n items={shown}\n filter={null}\n mode=\"list\"\n value={text}\n onValueChange={(t, details) => {\n // Base UI writes a pressed row's label into the input; a host that swaps the field for a chip opts out\n if (!fillOnSelect && details.reason === \"item-press\") return;\n setText(t);\n }}\n itemToStringValue={(o: SelectOption) => nodeText(o.label)}\n open={visible}\n onOpenChange={setOpen}\n inline={inlineList}\n // highlight row 0 while typing; Base UI highlights nothing for empty text, so Enter there commits it (onEnter)\n autoHighlight={highlightFirst}\n onItemHighlighted={(o) => setHighlighted(o as SelectOption | undefined)}\n openOnInputClick\n loopFocus\n disabled={disabled}\n >\n <div\n className={cn(\n \"flex min-w-0 items-center rounded-kit-md border border-kit-field-border bg-kit-field-bg shadow-kit-field transition-[border-color,box-shadow] duration-150 hover:border-kit-field-border-hover focus-within:border-kit-field-border-focus focus-within:shadow-kit-ring-field\",\n invalid && \"border-[var(--kit-field-invalid)] hover:border-[var(--kit-field-invalid)]\",\n disabled && \"cursor-not-allowed bg-kit-subtle opacity-60\",\n H[size],\n className,\n )}\n >\n {leadingSlot}\n {leading ? (\n <span aria-hidden className=\"ml-2.5 flex shrink-0 text-kit-fg-3 [&_svg]:size-4\">\n {leading}\n </span>\n ) : null}\n <AutocompletePrimitive.Input\n ref={inputRef}\n id={id ?? fieldId}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabel ? undefined : (labelFor ?? (named ? undefined : labelledBy))}\n aria-describedby={[ariaDescribedBy, describedBy].filter(Boolean).join(\" \") || undefined}\n aria-invalid={invalid || undefined}\n placeholder={placeholder}\n autoComplete=\"off\"\n spellCheck={false}\n onFocus={() => openOnFocus && setOpen(true)}\n onBlur={onBlur}\n onKeyDownCapture={(e) => {\n // V2 link.tsx:603-618: while the list shows, Escape closes only the list; the next one reaches the panel\n if (e.key === \"Escape\" && visible) {\n e.preventDefault();\n e.stopPropagation();\n setOpen(false);\n }\n }}\n onKeyDown={(e) => {\n if (e.key !== \"Enter\") return;\n if (firstStandsIn) {\n e.preventDefault();\n pick(shown[0]);\n } else if (!highlighted || !visible) onEnter?.(text);\n }}\n className=\"h-full min-w-0 flex-1 bg-transparent px-2 text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3 disabled:cursor-not-allowed\"\n />\n {loading ? (\n <Spinner size=\"sm\" tone=\"muted\" label=\"Loading suggestions\" className=\"mr-2\" />\n ) : text && !disabled ? (\n <IconButton label=\"Clear\" size=\"xs\" variant=\"ghost\" className=\"mr-1\" onMouseDown={(e) => e.preventDefault()} onClick={() => (onClear ? onClear() : setText(\"\"))}>\n <IconX stroke={1.5} />\n </IconButton>\n ) : null}\n {trailingSlot}\n </div>\n {inlineList ? (\n visible ? (\n /* V2 link.tsx:646-649: the in-flow list under the field */\n <div {...listAttrs} className={cn(\"mt-1 rounded-kit-md border border-kit-line bg-kit-surface p-1\", menuClassName)} onMouseDown={(e) => e.preventDefault()}>\n {rows}\n </div>\n ) : null\n ) : (\n <AutocompletePrimitive.Portal>\n <AutocompletePrimitive.Positioner align=\"start\" side=\"bottom\" sideOffset={4} collisionPadding={12} className=\"z-[var(--kit-z-menu,80)]\" data-floating-layer=\"\" {...KIT_SCOPE} {...listAttrs}>\n <AutocompletePrimitive.Popup\n className={cn(\n \"w-[max(var(--anchor-width),280px)] max-w-[min(420px,calc(100vw-24px))] rounded-kit-lg border bg-kit-surface p-1 text-kit-fg shadow-lg outline-none data-[open]:animate-kit-pop-in\",\n menuClassName,\n )}\n >\n {rows}\n </AutocompletePrimitive.Popup>\n </AutocompletePrimitive.Positioner>\n </AutocompletePrimitive.Portal>\n )}\n </AutocompletePrimitive.Root>\n );\n}\n"],"mappings":"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"}
|
|
@@ -8,8 +8,8 @@ import { type VariantProps } from "./variants";
|
|
|
8
8
|
* The keyboard focus ring is the global :focus-visible outline, suppressed under pointer modality (DESIGN.md 3.7).
|
|
9
9
|
*/
|
|
10
10
|
export declare const buttonVariants: (props?: {
|
|
11
|
-
variant?: "
|
|
12
|
-
size?: "
|
|
11
|
+
variant?: "link" | "ai" | "primary" | "secondary" | "accent" | "ghost" | "soft" | "danger" | "danger-ghost" | null | undefined;
|
|
12
|
+
size?: "sm" | "md" | "lg" | "xs" | "xl" | null | undefined;
|
|
13
13
|
} | undefined) => string;
|
|
14
14
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
15
15
|
/** Render the single child element (a link, say) with the button's classes and props. */
|
|
@@ -21,7 +21,7 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
|
|
|
21
21
|
export declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
22
22
|
/** Square icon-only button. Always pass `label` (used for aria-label + tooltip). */
|
|
23
23
|
export declare const iconButtonVariants: (props?: {
|
|
24
|
-
size?: "
|
|
24
|
+
size?: "sm" | "md" | "lg" | "xs" | null | undefined;
|
|
25
25
|
variant?: "outline" | "ghost" | "soft" | null | undefined;
|
|
26
26
|
} | undefined) => string;
|
|
27
27
|
/**
|
package/{ui → dist/ui}/button.js
RENAMED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { cn } from "../lib/cn.js";
|
|
2
2
|
import { SPARKLE_PATH } from "../brand/logo.js";
|
|
3
|
+
import { Spinner } from "./spinner.js";
|
|
3
4
|
import { TooltipLayer, TooltipRoot } from "./tooltip-root.js";
|
|
4
5
|
import { variants } from "./variants.js";
|
|
5
6
|
import * as React from "react";
|
|
6
|
-
import { IconLoader2, IconPlus } from "@tabler/icons-react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { IconPlus } from "@tabler/icons-react";
|
|
8
9
|
import { Tooltip } from "@base-ui/react/tooltip";
|
|
9
|
-
//#region src/
|
|
10
|
+
//#region src/ui/button.tsx
|
|
10
11
|
/**
|
|
11
12
|
* Button: the only button in the kit.
|
|
12
13
|
* Heights: xs 24 · sm 28 · md 32 (default) · lg 36 · xl 40. Radius 6.
|
|
@@ -17,8 +18,8 @@ import { Tooltip } from "@base-ui/react/tooltip";
|
|
|
17
18
|
var buttonVariants = variants("relative inline-flex items-center justify-center gap-1.5 whitespace-nowrap font-medium tracking-[-0.01em] select-none transition-[background-color,border-color,color,box-shadow,opacity] duration-150 ease-out disabled:pointer-events-none disabled:opacity-45 [&_svg]:shrink-0 [&_svg]:opacity-90", {
|
|
18
19
|
variants: {
|
|
19
20
|
variant: {
|
|
20
|
-
primary: "bg-kit-inverse text-kit-fg-inverse shadow-
|
|
21
|
-
accent: "bg-kit-accent text-kit-accent-on shadow-kit-xs hover:bg-kit-accent-hover",
|
|
21
|
+
primary: "bg-kit-inverse text-kit-fg-inverse shadow-kit-button-primary hover:bg-kit-inverse-hover active:bg-kit-inverse btn-solid",
|
|
22
|
+
accent: "bg-kit-accent text-kit-accent-on shadow-kit-xs hover:bg-kit-accent-hover btn-solid",
|
|
22
23
|
secondary: "border border-kit-line-strong bg-kit-control-bg text-kit-fg shadow-kit-xs hover:bg-kit-subtle active:bg-kit-hover",
|
|
23
24
|
ghost: "text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg active:bg-kit-selected",
|
|
24
25
|
soft: "bg-kit-muted text-kit-fg hover:bg-kit-selected",
|
|
@@ -44,7 +45,6 @@ var buttonVariants = variants("relative inline-flex items-center justify-center
|
|
|
44
45
|
size: "md"
|
|
45
46
|
}
|
|
46
47
|
});
|
|
47
|
-
var SOLID_DISABLED = "[.dark_&]:disabled:bg-[#2a2a2d] [.dark_&]:disabled:text-[#9e9ea1] [.dark_&]:disabled:opacity-100 [.dark_&]:disabled:shadow-none";
|
|
48
48
|
function mergeRefs(...refs) {
|
|
49
49
|
return (node) => {
|
|
50
50
|
for (const ref of refs) if (typeof ref === "function") ref(node);
|
|
@@ -55,7 +55,7 @@ var Button = React.forwardRef(({ className, variant, size, asChild, loading, lef
|
|
|
55
55
|
const classes = cn(buttonVariants({
|
|
56
56
|
variant,
|
|
57
57
|
size
|
|
58
|
-
}),
|
|
58
|
+
}), className);
|
|
59
59
|
if (asChild && React.isValidElement(children)) return React.cloneElement(children, {
|
|
60
60
|
...props,
|
|
61
61
|
...children.props,
|
|
@@ -70,10 +70,7 @@ var Button = React.forwardRef(({ className, variant, size, asChild, loading, lef
|
|
|
70
70
|
className: classes,
|
|
71
71
|
...props,
|
|
72
72
|
children: [
|
|
73
|
-
loading ? /* @__PURE__ */ jsx(
|
|
74
|
-
className: "animate-spin",
|
|
75
|
-
"aria-hidden": true
|
|
76
|
-
}) : leftIcon,
|
|
73
|
+
loading ? /* @__PURE__ */ jsx(Spinner, {}) : leftIcon,
|
|
77
74
|
variant === "ai" && !leftIcon && !loading ? /* @__PURE__ */ jsx(Sparkle, {}) : null,
|
|
78
75
|
children,
|
|
79
76
|
rightIcon
|
|
@@ -82,7 +79,7 @@ var Button = React.forwardRef(({ className, variant, size, asChild, loading, lef
|
|
|
82
79
|
});
|
|
83
80
|
Button.displayName = "Button";
|
|
84
81
|
/** Square icon-only button. Always pass `label` (used for aria-label + tooltip). */
|
|
85
|
-
var iconButtonVariants = variants("relative inline-flex items-center justify-center shrink-0 text-kit-fg-2 transition-colors duration-150 hover:bg-kit-hover hover:text-kit-fg active:scale-[0.96] disabled:opacity-40 disabled:pointer-events-none data-[active=true]:bg-kit-selected data-[active=true]:text-kit-fg
|
|
82
|
+
var iconButtonVariants = variants("relative inline-flex items-center justify-center shrink-0 text-kit-fg-2 transition-colors duration-150 hover:bg-kit-hover hover:text-kit-fg active:scale-[0.96] disabled:opacity-40 disabled:pointer-events-none data-[active=true]:bg-kit-selected data-[active=true]:text-kit-fg", {
|
|
86
83
|
variants: {
|
|
87
84
|
size: {
|
|
88
85
|
xs: "size-6 rounded-kit-md [&_svg]:size-3.5",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.js","names":[],"sources":["../../src/ui/button.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\";\nimport { IconPlus } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { SPARKLE_PATH } from \"../brand/logo\";\nimport { Spinner } from \"./spinner\";\nimport { TooltipLayer, TooltipRoot } from \"./tooltip-root\";\nimport { variants, type VariantProps } from \"./variants\";\n\n/**\n * Button: the only button in the kit.\n * Heights: xs 24 · sm 28 · md 32 (default) · lg 36 · xl 40. Radius 6.\n * Variants: primary (ink) · accent (violet, reserved for the ONE create action per screen)\n * secondary (bordered) · ghost · soft · danger · danger-ghost · link · ai (gradient sparkle)\n * The keyboard focus ring is the global :focus-visible outline, suppressed under pointer modality (DESIGN.md 3.7).\n */\nexport const buttonVariants = variants(\n \"relative inline-flex items-center justify-center gap-1.5 whitespace-nowrap font-medium tracking-[-0.01em] select-none transition-[background-color,border-color,color,box-shadow,opacity] duration-150 ease-out disabled:pointer-events-none disabled:opacity-45 [&_svg]:shrink-0 [&_svg]:opacity-90\",\n {\n variants: {\n variant: {\n // .btn-solid: in dark a disabled primary/accent takes the solid --kit-disabled-bg / --kit-disabled-fg pair; light keeps the opacity dim.\n primary: \"bg-kit-inverse text-kit-fg-inverse shadow-kit-button-primary hover:bg-kit-inverse-hover active:bg-kit-inverse btn-solid\",\n accent: \"bg-kit-accent text-kit-accent-on shadow-kit-xs hover:bg-kit-accent-hover btn-solid\",\n secondary: \"border border-kit-line-strong bg-kit-control-bg text-kit-fg shadow-kit-xs hover:bg-kit-subtle active:bg-kit-hover\",\n ghost: \"text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg active:bg-kit-selected\",\n soft: \"bg-kit-muted text-kit-fg hover:bg-kit-selected\",\n danger: \"bg-kit-danger text-kit-danger-on shadow-kit-xs hover:brightness-95\",\n \"danger-ghost\": \"text-kit-danger-fg hover:bg-kit-danger-soft\",\n link: \"text-kit-accent-fg underline-offset-4 hover:underline px-0 h-auto active:scale-100\",\n ai: \"border border-kit-line bg-kit-control-bg text-kit-fg shadow-kit-xs hover:border-kit-accent-line hover:bg-kit-accent-softer\",\n },\n size: {\n xs: \"h-6 rounded-kit-md px-2 text-kit-xs [&_svg]:size-3.5\",\n sm: \"h-7 rounded-kit-md px-2.5 text-kit-sm [&_svg]:size-3.5\",\n md: \"h-8 rounded-kit-md px-3 text-kit-sm [&_svg]:size-4\",\n lg: \"h-9 rounded-kit-md px-3.5 text-kit-base [&_svg]:size-4\",\n xl: \"h-10 rounded-kit-md px-4 text-kit-base [&_svg]:size-[18px]\",\n },\n },\n compoundVariants: [{ variant: \"link\", className: \"h-auto px-0\" }],\n defaultVariants: { variant: \"secondary\", size: \"md\" },\n },\n);\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {\n /** Render the single child element (a link, say) with the button's classes and props. */\n asChild?: boolean;\n loading?: boolean;\n leftIcon?: React.ReactNode;\n rightIcon?: React.ReactNode;\n}\n\ntype ChildProps = { className?: string; ref?: React.Ref<unknown> };\n\nfunction mergeRefs<T>(...refs: (React.Ref<T> | undefined)[]) {\n return (node: T | null) => {\n for (const ref of refs) {\n if (typeof ref === \"function\") ref(node);\n else if (ref) (ref as React.RefObject<T | null>).current = node;\n }\n };\n}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild, loading, leftIcon, rightIcon, children, disabled, ...props }, ref) => {\n const classes = cn(buttonVariants({ variant, size }), className);\n if (asChild && React.isValidElement<ChildProps>(children)) {\n return React.cloneElement(children, {\n ...props,\n ...children.props,\n className: cn(classes, children.props.className),\n ref: mergeRefs(ref as React.Ref<unknown>, children.props.ref),\n });\n }\n return (\n <button ref={ref} type={props.type ?? \"button\"} disabled={disabled || loading} aria-busy={loading || undefined} className={classes} {...props}>\n {/* the kit Spinner (decorative: the button says it is busy); the size variant's [&_svg] rule sizes its glyph */}\n {loading ? <Spinner /> : leftIcon}\n {variant === \"ai\" && !leftIcon && !loading ? <Sparkle /> : null}\n {children}\n {rightIcon}\n </button>\n );\n },\n);\nButton.displayName = \"Button\";\n\n/** Square icon-only button. Always pass `label` (used for aria-label + tooltip). */\nexport const iconButtonVariants = variants(\n \"relative inline-flex items-center justify-center shrink-0 text-kit-fg-2 transition-colors duration-150 hover:bg-kit-hover hover:text-kit-fg active:scale-[0.96] disabled:opacity-40 disabled:pointer-events-none data-[active=true]:bg-kit-selected data-[active=true]:text-kit-fg\",\n {\n variants: {\n size: {\n xs: \"size-6 rounded-kit-md [&_svg]:size-3.5\",\n sm: \"size-7 rounded-kit-md [&_svg]:size-4\",\n md: \"size-8 rounded-kit-md [&_svg]:size-4\",\n lg: \"size-9 rounded-kit-md [&_svg]:size-[18px]\",\n },\n variant: {\n ghost: \"\",\n outline: \"border border-kit-line bg-kit-control-bg shadow-kit-xs hover:border-kit-line-strong\",\n soft: \"bg-kit-muted\",\n },\n },\n defaultVariants: { size: \"md\", variant: \"ghost\" },\n },\n);\n\n/**\n * a11y: true while rendering inside a tooltip (or a surface that manages its own hints), so an IconButton nested\n * there doesn't add a second tooltip. Provided by HintTooltip and overlay.tsx's <Tooltip>.\n */\nexport const TooltipScope = React.createContext(false);\n\n/**\n * The plain ink hint (DESIGN.md 8.23: top, 6px offset, 8px collision padding, portalled, z 90, 350ms). The child\n * element is the trigger and must take a ref and DOM props. input, display and action-tray use it so they never\n * import overlay.tsx; overlay's <Tooltip> adds the shortcut slot on top of the same layer.\n */\nexport function HintTooltip({\n content,\n side = \"top\",\n delay = 350,\n children,\n}: {\n content: React.ReactNode;\n side?: \"top\" | \"bottom\" | \"left\" | \"right\";\n delay?: number;\n children: React.ReactElement;\n}) {\n return (\n <TooltipScope.Provider value>\n <TooltipRoot>\n <TooltipPrimitive.Trigger delay={delay} render={children} />\n <TooltipLayer side={side}>\n <span className=\"line-clamp-[8] min-w-0 whitespace-normal [overflow-wrap:anywhere]\">{content}</span>\n </TooltipLayer>\n </TooltipRoot>\n </TooltipScope.Provider>\n );\n}\n\nexport interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof iconButtonVariants> {\n label: string;\n active?: boolean;\n /** Hover/focus hint. Defaults to `label`; pass `false` to opt out, or a node to customise. */\n tooltip?: React.ReactNode | false;\n tooltipSide?: \"top\" | \"bottom\" | \"left\" | \"right\";\n}\n\nexport const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(\n ({ className, size, variant, label, active, children, tooltip, tooltipSide = \"top\", ...props }, ref) => {\n const inTooltip = React.useContext(TooltipScope);\n const btn = (\n <button\n ref={ref}\n type=\"button\"\n aria-label={label}\n data-active={active ? \"true\" : undefined}\n className={cn(iconButtonVariants({ size, variant }), className)}\n {...props}\n >\n {children}\n </button>\n );\n // Every icon-only button gets a visible hint on hover AND keyboard focus (brief §11), unless a\n // parent tooltip already provides one or the caller opted out.\n if (inTooltip || tooltip === false || !label) return btn;\n return (\n <HintTooltip content={tooltip ?? label} side={tooltipSide}>\n {btn}\n </HintTooltip>\n );\n },\n);\nIconButton.displayName = \"IconButton\";\n\n/** The AI sparkle in the official brand gradient. Used everywhere AI appears. */\nexport function Sparkle({ className, size = 16 }: { className?: string; size?: number }) {\n const id = React.useId().replace(/:/g, \"\");\n return (\n <svg width={size} height={size} viewBox=\"2 2 16 16\" className={cn(\"shrink-0\", className)} aria-hidden>\n <defs>\n <linearGradient id={`sp${id}`} x1=\"6.89\" y1=\"4.59\" x2=\"18\" y2=\"23.67\" gradientUnits=\"userSpaceOnUse\">\n <stop offset=\"0.0817\" style={{ stopColor: \"var(--kit-brand-violet)\" }} />\n <stop offset=\"0.4667\" style={{ stopColor: \"var(--kit-brand-coral)\" }} />\n <stop offset=\"1\" style={{ stopColor: \"var(--kit-brand-rose)\" }} />\n </linearGradient>\n </defs>\n <path d={SPARKLE_PATH} fill={`url(#sp${id})`} />\n </svg>\n );\n}\n\n/** D15 progressive disclosure: \"+ Add a message\" / \"+ Limit to specific sites\": reveals an optional input. */\nexport function RevealLink({ className, children, ...props }: React.ButtonHTMLAttributes<HTMLButtonElement>) {\n return (\n <button\n type=\"button\"\n className={cn(\n \"inline-flex h-7 items-center gap-1 rounded-kit-md text-kit-sm font-medium text-kit-fg-2 transition-colors hover:text-kit-fg [&_svg]:size-3.5\",\n className,\n )}\n {...props}\n >\n <IconPlus stroke={2} aria-hidden />\n {children}\n </button>\n );\n}\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { Segmented } from "./controls.js";
|
|
|
2
2
|
import { Select, nodeText } from "./select.js";
|
|
3
3
|
import "react";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
|
-
//#region src/
|
|
5
|
+
//#region src/ui/choice-switch.tsx
|
|
6
6
|
/** Most options a segmented switch may hold. */
|
|
7
7
|
var SEGMENTED_MAX = 3;
|
|
8
8
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choice-switch.js","names":[],"sources":["../../src/ui/choice-switch.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Segmented } from \"./controls\";\nimport { Select, nodeText } from \"./select\";\n\n/* ── Pickers: segmented vs dropdown (D46) ──────────────────────────────────\n A tab-style switch is for 2–3 short options people flip often. Four or more options, or labels that would wrap or\n truncate in a 340px inspector, become a dropdown (the D34 Select, with a one-line description where an option\n isn't self-explanatory). `fitsSegmented` is the single test; `ChoiceSwitch` applies it for dynamic lists\n (variants, schema options, presets) so call sites never have to count. */\n\n/** Most options a segmented switch may hold. */\nexport const SEGMENTED_MAX = 3;\n/**\n * Longest label (characters) that stays on one line when the row shares a 340px inspector:\n * two options get ~134px each (about 18 characters at 13px), three get ~84px (about 12).\n */\nexport const SEGMENTED_MAX_LABEL = { 2: 18, 3: 12 } as const;\n\nexport function fitsSegmented(labels: React.ReactNode[]): boolean {\n const n = labels.length;\n if (n < 2 || n > SEGMENTED_MAX) return false;\n const max = SEGMENTED_MAX_LABEL[n as 2 | 3];\n return labels.every((l) => nodeText(l).trim().length <= max);\n}\n\nexport interface ChoiceSwitchItem<T extends string> {\n value: T;\n label: React.ReactNode;\n /** one line under the option in the dropdown; ignored while it renders as a segmented switch */\n description?: string;\n icon?: React.ReactNode;\n disabled?: boolean;\n}\n\nexport function ChoiceSwitch<T extends string>({\n value,\n onChange,\n items,\n \"aria-label\": ariaLabel,\n size = \"sm\",\n layout = \"auto\",\n disabled,\n className,\n segmentedClassName,\n selectClassName,\n layoutId,\n placeholder,\n}: {\n value: T;\n onChange: (v: T) => void;\n items: ChoiceSwitchItem<T>[];\n \"aria-label\"?: string;\n size?: \"sm\" | \"md\";\n /** \"auto\" applies D46; force a look only when a design reason overrides the rule */\n layout?: \"auto\" | \"segmented\" | \"dropdown\";\n disabled?: boolean;\n /** applied to whichever control renders */\n className?: string;\n segmentedClassName?: string;\n selectClassName?: string;\n layoutId?: string;\n placeholder?: string;\n}) {\n const segmented = layout === \"segmented\" || (layout === \"auto\" && fitsSegmented(items.map((i) => i.label)));\n if (segmented)\n return (\n <Segmented<T>\n size={size}\n aria-label={ariaLabel}\n value={value}\n onChange={(v) => !disabled && onChange(v)}\n layoutId={layoutId}\n className={[className, segmentedClassName].filter(Boolean).join(\" \") || undefined}\n items={items.map((i) => ({ value: i.value, label: i.label, icon: i.icon, disabled: disabled || i.disabled }))}\n />\n );\n return (\n <Select\n size={size}\n aria-label={ariaLabel}\n value={value || undefined}\n disabled={disabled}\n placeholder={placeholder}\n onValueChange={(v) => onChange(v as T)}\n className={[className, selectClassName].filter(Boolean).join(\" \") || undefined}\n options={items.map((i) => ({ value: i.value, label: i.label, description: i.description, icon: i.icon, disabled: i.disabled }))}\n />\n );\n}\n"],"mappings":";;;;;;AAWA,IAAa,gBAAgB;;;;;AAK7B,IAAa,sBAAsB;CAAE,GAAG;CAAI,GAAG;AAAG;AAElD,SAAgB,cAAc,QAAoC;CAChE,MAAM,IAAI,OAAO;CACjB,IAAI,IAAI,KAAK,IAAA,GAAmB,OAAO;CACvC,MAAM,MAAM,oBAAoB;CAChC,OAAO,OAAO,OAAO,MAAM,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,GAAG;AAC7D;AAWA,SAAgB,aAA+B,EAC7C,OACA,UACA,OACA,cAAc,WACd,OAAO,MACP,SAAS,QACT,UACA,WACA,oBACA,iBACA,UACA,eAgBC;CAED,IADkB,WAAW,eAAgB,WAAW,UAAU,cAAc,MAAM,KAAK,MAAM,EAAE,KAAK,CAAC,GAEvG,OACE,oBAAC,WAAD;EACQ;EACN,cAAY;EACL;EACP,WAAW,MAAM,CAAC,YAAY,SAAS,CAAC;EAC9B;EACV,WAAW,CAAC,WAAW,kBAAkB,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;EACxE,OAAO,MAAM,KAAK,OAAO;GAAE,OAAO,EAAE;GAAO,OAAO,EAAE;GAAO,MAAM,EAAE;GAAM,UAAU,YAAY,EAAE;EAAS,EAAE;CAC7G,CAAA;CAEL,OACE,oBAAC,QAAD;EACQ;EACN,cAAY;EACZ,OAAO,SAAS,KAAA;EACN;EACG;EACb,gBAAgB,MAAM,SAAS,CAAM;EACrC,WAAW,CAAC,WAAW,eAAe,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;EACrE,SAAS,MAAM,KAAK,OAAO;GAAE,OAAO,EAAE;GAAO,OAAO,EAAE;GAAO,aAAa,EAAE;GAAa,MAAM,EAAE;GAAM,UAAU,EAAE;EAAS,EAAE;CAC/H,CAAA;AAEL"}
|
|
@@ -1,50 +1,49 @@
|
|
|
1
1
|
import { cn } from "../lib/cn.js";
|
|
2
2
|
import { useFieldLabelledBy, useLabelFor } from "./field-context.js";
|
|
3
|
-
import { INK_ACTIVE } from "./surfaces.js";
|
|
4
3
|
import { TooltipLayer, TooltipRoot } from "./tooltip-root.js";
|
|
5
4
|
import { TooltipScope } from "./button.js";
|
|
6
5
|
import { useShortcutHints } from "./shortcut-hint.js";
|
|
7
6
|
import * as React from "react";
|
|
8
|
-
import { IconCheck, IconMinus } from "@tabler/icons-react";
|
|
9
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { IconCheck, IconMinus } from "@tabler/icons-react";
|
|
10
9
|
import { AnimatePresence, motion, useReducedMotion } from "framer-motion";
|
|
11
|
-
import { Switch } from "@base-ui/react/switch";
|
|
12
|
-
import { Checkbox } from "@base-ui/react/checkbox";
|
|
13
|
-
import { RadioGroup } from "@base-ui/react/radio-group";
|
|
14
|
-
import { Radio } from "@base-ui/react/radio";
|
|
10
|
+
import { Switch as Switch$1 } from "@base-ui/react/switch";
|
|
11
|
+
import { Checkbox as Checkbox$1 } from "@base-ui/react/checkbox";
|
|
12
|
+
import { RadioGroup as RadioGroup$1 } from "@base-ui/react/radio-group";
|
|
13
|
+
import { Radio as Radio$1 } from "@base-ui/react/radio";
|
|
15
14
|
import { Tooltip } from "@base-ui/react/tooltip";
|
|
16
|
-
import { Slider } from "@base-ui/react/slider";
|
|
17
|
-
import { ToggleGroup } from "@base-ui/react/toggle-group";
|
|
15
|
+
import { Slider as Slider$1 } from "@base-ui/react/slider";
|
|
16
|
+
import { ToggleGroup as ToggleGroup$1 } from "@base-ui/react/toggle-group";
|
|
18
17
|
import { Toggle } from "@base-ui/react/toggle";
|
|
19
|
-
import { Progress } from "@base-ui/react/progress";
|
|
20
|
-
//#region src/
|
|
18
|
+
import { Progress as Progress$1 } from "@base-ui/react/progress";
|
|
19
|
+
//#region src/ui/controls.tsx
|
|
21
20
|
var PILL_SPRING = {
|
|
22
21
|
type: "spring",
|
|
23
22
|
stiffness: 520,
|
|
24
23
|
damping: 42
|
|
25
24
|
};
|
|
26
|
-
function Switch
|
|
25
|
+
function Switch({ className, size = "md", ...props }) {
|
|
27
26
|
const sm = size === "sm";
|
|
28
27
|
const labelledBy = useFieldLabelledBy();
|
|
29
28
|
const labelFor = useLabelFor(props.id);
|
|
30
|
-
return /* @__PURE__ */ jsx(Switch.Root, {
|
|
29
|
+
return /* @__PURE__ */ jsx(Switch$1.Root, {
|
|
31
30
|
className: cn("group relative inline-flex shrink-0 items-center rounded-full bg-kit-switch-off transition-colors duration-200 data-[checked]:bg-kit-success data-[disabled]:opacity-40", sm ? "h-4 w-7" : "h-5 w-9", className),
|
|
32
31
|
"aria-labelledby": props["aria-labelledby"] ?? (props["aria-label"] ? void 0 : labelFor ?? (props.id ? void 0 : labelledBy)),
|
|
33
32
|
...props,
|
|
34
|
-
children: /* @__PURE__ */ jsx(Switch.Thumb, { className: cn("pointer-events-none block rounded-full bg-kit-control-thumb shadow-kit-sm transition-transform duration-200 ease-kit-spring", sm ? "size-3 translate-x-0.5 data-[checked]:translate-x-[14px]" : "size-4 translate-x-0.5 data-[checked]:translate-x-[18px]") })
|
|
33
|
+
children: /* @__PURE__ */ jsx(Switch$1.Thumb, { className: cn("pointer-events-none block rounded-full bg-kit-control-thumb shadow-kit-sm transition-transform duration-200 ease-[var(--kit-ease-spring)]", sm ? "size-3 translate-x-0.5 data-[checked]:translate-x-[14px]" : "size-4 translate-x-0.5 data-[checked]:translate-x-[18px]") })
|
|
35
34
|
});
|
|
36
35
|
}
|
|
37
36
|
/** `checked` keeps V2's tri-state value: true, false or "indeterminate". */
|
|
38
|
-
function Checkbox
|
|
37
|
+
function Checkbox({ className, checked, ...props }) {
|
|
39
38
|
const indeterminate = checked === "indeterminate";
|
|
40
39
|
const labelFor = useLabelFor(props.id);
|
|
41
|
-
return /* @__PURE__ */ jsx(Checkbox.Root, {
|
|
40
|
+
return /* @__PURE__ */ jsx(Checkbox$1.Root, {
|
|
42
41
|
"aria-labelledby": props["aria-labelledby"] ?? (props["aria-label"] ? void 0 : labelFor),
|
|
43
|
-
className: cn("peer flex size-4 shrink-0 items-center justify-center rounded-kit-sm border border-kit-line-strong bg-kit-control-bg shadow-kit-xs transition-colors hover:border-[var(--kit-emphasis-line)] data-[checked]:border-kit-inverse data-[checked]:bg-kit-inverse data-[indeterminate]:border-kit-inverse data-[indeterminate]:bg-kit-inverse
|
|
42
|
+
className: cn("peer flex size-4 shrink-0 items-center justify-center rounded-kit-sm border border-kit-line-strong bg-kit-control-bg shadow-kit-xs transition-colors hover:border-[var(--kit-emphasis-line)] data-[checked]:border-kit-inverse data-[checked]:bg-kit-inverse data-[indeterminate]:border-kit-inverse data-[indeterminate]:bg-kit-inverse", className),
|
|
44
43
|
checked: checked === void 0 ? void 0 : checked === true,
|
|
45
44
|
indeterminate,
|
|
46
45
|
...props,
|
|
47
|
-
children: /* @__PURE__ */ jsx(Checkbox.Indicator, {
|
|
46
|
+
children: /* @__PURE__ */ jsx(Checkbox$1.Indicator, {
|
|
48
47
|
className: "text-kit-fg-inverse",
|
|
49
48
|
children: indeterminate ? /* @__PURE__ */ jsx(IconMinus, {
|
|
50
49
|
className: "size-3",
|
|
@@ -56,12 +55,12 @@ function Checkbox$1({ className, checked, ...props }) {
|
|
|
56
55
|
})
|
|
57
56
|
});
|
|
58
57
|
}
|
|
59
|
-
var RadioGroup
|
|
60
|
-
function Radio
|
|
61
|
-
return /* @__PURE__ */ jsx(Radio.Root, {
|
|
62
|
-
className: cn("flex size-4 shrink-0 items-center justify-center rounded-full border border-kit-line-strong bg-kit-control-bg shadow-kit-xs transition-colors hover:border-[var(--kit-emphasis-line)] data-[checked]:border-kit-accent
|
|
58
|
+
var RadioGroup = RadioGroup$1;
|
|
59
|
+
function Radio({ className, ...props }) {
|
|
60
|
+
return /* @__PURE__ */ jsx(Radio$1.Root, {
|
|
61
|
+
className: cn("flex size-4 shrink-0 items-center justify-center rounded-full border border-kit-line-strong bg-kit-control-bg shadow-kit-xs transition-colors hover:border-[var(--kit-emphasis-line)] data-[checked]:border-kit-accent", className),
|
|
63
62
|
...props,
|
|
64
|
-
children: /* @__PURE__ */ jsx(Radio.Indicator, { className: "block size-2 rounded-full bg-kit-accent" })
|
|
63
|
+
children: /* @__PURE__ */ jsx(Radio$1.Indicator, { className: "block size-2 rounded-full bg-kit-accent" })
|
|
65
64
|
});
|
|
66
65
|
}
|
|
67
66
|
/** Large selectable card used for choices (plans, project kinds, roles). */
|
|
@@ -70,7 +69,7 @@ function ChoiceCard({ selected, onSelect, icon, title, description, badge, class
|
|
|
70
69
|
type: "button",
|
|
71
70
|
onClick: onSelect,
|
|
72
71
|
"aria-pressed": selected,
|
|
73
|
-
className: cn("group relative flex w-full flex-col gap-1.5 rounded-kit-lg border bg-kit-control-bg px-3 py-2.5 text-left transition-[border-color,box-shadow,background-color] duration-150
|
|
72
|
+
className: cn("focus-inset group relative flex w-full flex-col gap-1.5 rounded-kit-lg border bg-kit-control-bg px-3 py-2.5 text-left transition-[border-color,box-shadow,background-color] duration-150", selected ? "border-[var(--kit-emphasis-line)] shadow-kit-ring-field" : "border-kit-line hover:border-kit-line-strong hover:shadow-kit-sm", className),
|
|
74
73
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
75
74
|
className: "flex items-start gap-3",
|
|
76
75
|
children: [
|
|
@@ -108,19 +107,19 @@ function ChoiceList({ className, children, ...props }) {
|
|
|
108
107
|
children
|
|
109
108
|
});
|
|
110
109
|
}
|
|
111
|
-
function Slider
|
|
110
|
+
function Slider({ className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, label, ...props }) {
|
|
112
111
|
const name = ariaLabel ?? label;
|
|
113
112
|
const v = props.value ?? props.defaultValue ?? [0];
|
|
114
113
|
const thumbs = Array.isArray(v) ? v.length : 1;
|
|
115
|
-
return /* @__PURE__ */ jsx(Slider.Root, {
|
|
114
|
+
return /* @__PURE__ */ jsx(Slider$1.Root, {
|
|
116
115
|
className: cn("w-full", className),
|
|
117
116
|
...props,
|
|
118
|
-
children: /* @__PURE__ */ jsxs(Slider.Control, {
|
|
117
|
+
children: /* @__PURE__ */ jsxs(Slider$1.Control, {
|
|
119
118
|
className: "relative flex h-5 w-full touch-none select-none items-center",
|
|
120
|
-
children: [/* @__PURE__ */ jsx(Slider.Track, {
|
|
119
|
+
children: [/* @__PURE__ */ jsx(Slider$1.Track, {
|
|
121
120
|
className: "relative h-1 w-full grow overflow-hidden rounded-full bg-[var(--kit-track-line)]",
|
|
122
|
-
children: /* @__PURE__ */ jsx(Slider.Indicator, { className: "absolute h-full bg-kit-fg-2" })
|
|
123
|
-
}), Array.from({ length: thumbs }, (_, i) => /* @__PURE__ */ jsx(Slider.Thumb, {
|
|
121
|
+
children: /* @__PURE__ */ jsx(Slider$1.Indicator, { className: "absolute h-full bg-kit-fg-2" })
|
|
122
|
+
}), Array.from({ length: thumbs }, (_, i) => /* @__PURE__ */ jsx(Slider$1.Thumb, {
|
|
124
123
|
index: thumbs > 1 ? i : void 0,
|
|
125
124
|
getAriaLabel: name ? () => name : void 0,
|
|
126
125
|
"aria-labelledby": name ? void 0 : ariaLabelledby,
|
|
@@ -143,7 +142,7 @@ function SegmentTooltip({ content, shortcut, children }) {
|
|
|
143
142
|
children: content
|
|
144
143
|
}), shortcut && hints ? /* @__PURE__ */ jsx("kbd", {
|
|
145
144
|
"data-hint": "shortcuts",
|
|
146
|
-
className:
|
|
145
|
+
className: "mt-px shrink-0 rounded-kit-sm bg-kit-ink-active px-1 font-kit-sans text-kit-2xs",
|
|
147
146
|
children: shortcut
|
|
148
147
|
}) : null]
|
|
149
148
|
})] })
|
|
@@ -281,14 +280,27 @@ function Segmented({ value, onChange, items, size = "md", className, layoutId, i
|
|
|
281
280
|
})
|
|
282
281
|
});
|
|
283
282
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
var ToggleGroupSingle = React.createContext(false);
|
|
284
|
+
function ToggleGroup({ className, ...props }) {
|
|
285
|
+
const single = !props.multiple;
|
|
286
|
+
return /* @__PURE__ */ jsx(ToggleGroupSingle.Provider, {
|
|
287
|
+
value: single,
|
|
288
|
+
children: /* @__PURE__ */ jsx(ToggleGroup$1, {
|
|
289
|
+
className: cn("inline-flex items-center gap-px rounded-kit-md border border-kit-line bg-kit-field-bg p-[2px]", className),
|
|
290
|
+
...single ? { role: "radiogroup" } : {},
|
|
291
|
+
...props
|
|
292
|
+
})
|
|
288
293
|
});
|
|
289
294
|
}
|
|
290
295
|
function ToggleItem({ className, ...props }) {
|
|
296
|
+
const single = React.useContext(ToggleGroupSingle);
|
|
291
297
|
return /* @__PURE__ */ jsx(Toggle, {
|
|
298
|
+
...single ? { render: (p, state) => /* @__PURE__ */ jsx("button", {
|
|
299
|
+
...p,
|
|
300
|
+
role: "radio",
|
|
301
|
+
"aria-checked": state.pressed,
|
|
302
|
+
"aria-pressed": void 0
|
|
303
|
+
}) } : {},
|
|
292
304
|
className: cn("inline-flex h-6 min-w-6 items-center justify-center gap-1 rounded-kit-sm px-1.5 text-kit-xs font-medium text-kit-fg-3 transition-colors hover:bg-kit-hover hover:text-kit-fg data-[pressed]:bg-kit-selected data-[pressed]:text-kit-fg [&_svg]:size-3.5", className),
|
|
293
305
|
...props
|
|
294
306
|
});
|
|
@@ -301,19 +313,19 @@ var progressTones = {
|
|
|
301
313
|
ink: "bg-[var(--kit-bar-fill)]",
|
|
302
314
|
brand: "bg-[var(--kit-bar-fill)]"
|
|
303
315
|
};
|
|
304
|
-
function Progress
|
|
316
|
+
function Progress({ value, className, tone = "success", size = "md", label = "Progress" }) {
|
|
305
317
|
const pct = Math.min(100, Math.max(0, value));
|
|
306
|
-
return /* @__PURE__ */ jsx(Progress.Root, {
|
|
318
|
+
return /* @__PURE__ */ jsx(Progress$1.Root, {
|
|
307
319
|
value: pct,
|
|
308
320
|
"aria-label": label,
|
|
309
321
|
className: cn("relative w-full overflow-hidden rounded-full bg-[var(--kit-track)]", size === "sm" ? "h-1" : "h-1.5", className),
|
|
310
|
-
children: /* @__PURE__ */ jsx(Progress.Indicator, {
|
|
311
|
-
className: cn("
|
|
322
|
+
children: /* @__PURE__ */ jsx(Progress$1.Indicator, {
|
|
323
|
+
className: cn("h-full rounded-full transition-[width] duration-500 ease-[var(--kit-ease-out-soft)]", progressTones[tone]),
|
|
312
324
|
style: { width: `${pct}%` }
|
|
313
325
|
})
|
|
314
326
|
});
|
|
315
327
|
}
|
|
316
328
|
//#endregion
|
|
317
|
-
export { Checkbox
|
|
329
|
+
export { Checkbox, ChoiceCard, ChoiceList, Progress, Radio, RadioGroup, Segmented, Slider, Switch, ToggleGroup, ToggleItem };
|
|
318
330
|
|
|
319
331
|
//# sourceMappingURL=controls.js.map
|