diff --git a/.prettierrc b/.prettierrc index e69b455b3c..ad50d4c953 100644 --- a/.prettierrc +++ b/.prettierrc @@ -5,7 +5,9 @@ "arrowParens": "always", "semi": false, "htmlWhitespaceSensitivity": "ignore", + "plugins": ["prettier-plugin-svelte"], "overrides": [ + { "files": "*.svelte", "options": { "parser": "svelte" } }, { "files": "*.md", "options": { diff --git a/bun.lockb b/bun.lockb index 931716e907..5ea8f7a740 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/packages/react/src/components/avatar/examples/root-provider.tsx b/packages/react/src/components/avatar/examples/root-provider.tsx index 2c90455ef8..60d48637e0 100644 --- a/packages/react/src/components/avatar/examples/root-provider.tsx +++ b/packages/react/src/components/avatar/examples/root-provider.tsx @@ -5,11 +5,13 @@ export const RootProvider = () => { return ( <> - + PA - + ) diff --git a/packages/svelte/.gitignore b/packages/svelte/.gitignore deleted file mode 100644 index ac7211b403..0000000000 --- a/packages/svelte/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -.DS_Store -node_modules -/build -/dist -/.svelte-kit -/package -.env -.env.* -!.env.example -vite.config.js.timestamp-* -vite.config.ts.timestamp-* diff --git a/packages/svelte/.npmrc b/packages/svelte/.npmrc deleted file mode 100644 index b6f27f1359..0000000000 --- a/packages/svelte/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/packages/svelte/.storybook/main.css b/packages/svelte/.storybook/main.css new file mode 100644 index 0000000000..63365cacef --- /dev/null +++ b/packages/svelte/.storybook/main.css @@ -0,0 +1,36 @@ +@import url("./styles/accordion.css"); +@import url("./styles/avatar.css"); +@import url("./styles/carousel.css"); +@import url("./styles/checkbox.css"); +@import url("./styles/collapsible.css"); +@import url("./styles/color-picker.css"); +@import url("./styles/combobox.css"); +@import url("./styles/date-picker.css"); +@import url("./styles/dialog.css"); +@import url("./styles/field.css"); +@import url("./styles/file-upload.css"); +@import url("./styles/hover-card.css"); +@import url("./styles/menu.css"); +@import url("./styles/number-input.css"); +@import url("./styles/pagination.css"); +@import url("./styles/pin-input.css"); +@import url("./styles/popover.css"); +@import url("./styles/presence.css"); +@import url("./styles/progress.css"); +@import url("./styles/qr-code.css"); +@import url("./styles/radio-group.css"); +@import url("./styles/segment-group.css"); +@import url("./styles/select.css"); +@import url("./styles/signature-pad.css"); +@import url("./styles/slider.css"); +@import url("./styles/splitter.css"); +@import url("./styles/steps.css"); +@import url("./styles/switch.css"); +@import url("./styles/tabs.css"); +@import url("./styles/tags-input.css"); +@import url("./styles/time-picker.css"); +@import url("./styles/timer.css"); +@import url("./styles/toast.css"); +@import url("./styles/toggle-group.css"); +@import url("./styles/tooltip.css"); +@import url("./styles/tree-view.css"); diff --git a/packages/svelte/.storybook/main.ts b/packages/svelte/.storybook/main.ts new file mode 100644 index 0000000000..e9e60a9005 --- /dev/null +++ b/packages/svelte/.storybook/main.ts @@ -0,0 +1,21 @@ +import type { StorybookConfig } from '@storybook/sveltekit' + +const config: StorybookConfig = { + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|svelte)'], + framework: '@storybook/sveltekit', + addons: [ + { + name: '@storybook/addon-essentials', + options: { backgrounds: false, controls: false, actions: false }, + }, + '@storybook/addon-a11y', + ], + core: { + disableTelemetry: true, + }, + docs: { + autodocs: false, + }, +} + +export default config diff --git a/packages/svelte/.storybook/preview.ts b/packages/svelte/.storybook/preview.ts new file mode 100644 index 0000000000..e13704db3a --- /dev/null +++ b/packages/svelte/.storybook/preview.ts @@ -0,0 +1,15 @@ +import type { Preview } from '@storybook/react' +import './main.css' + +const preview: Preview = { + parameters: { + options: { + storySort: { + method: 'alphabetical', + }, + }, + layout: 'padded', + }, +} + +export default preview diff --git a/packages/svelte/.storybook/styles/accordion.css b/packages/svelte/.storybook/styles/accordion.css new file mode 100644 index 0000000000..e83b9d5680 --- /dev/null +++ b/packages/svelte/.storybook/styles/accordion.css @@ -0,0 +1,53 @@ +@keyframes slideDown { + from { + opacity: 0.01; + height: 0; + } + to { + opacity: 1; + height: var(--height); + } +} + +@keyframes slideUp { + from { + opacity: 1; + height: var(--height); + } + to { + opacity: 0.01; + height: 0; + } +} + + +[data-scope='accordion'][data-part='item-indicator'][data-state='open'] { + rotate: 90deg; +} + +[data-scope='accordion'][data-part='item-trigger'] { + display: inline-flex; + align-items: center; + gap: 8px; +} + +[data-scope='accordion'][data-part='item-trigger'] svg { + width: 1em; + height: 1em; +} + + +[data-scope="accordion"][data-part="item-content"] { + overflow: hidden; + max-width: 400px; + background-color: cadetblue; + color:white; +} + +[data-scope="accordion"][data-part="item-content"][data-state="open"] { + animation: slideDown 250ms cubic-bezier(0, 0, 0.38, 0.9); +} + +[data-scope="accordion"][data-part="item-content"][data-state="closed"] { + animation: slideUp 200ms cubic-bezier(0, 0, 0.38, 0.9); +} diff --git a/packages/svelte/.storybook/styles/avatar.css b/packages/svelte/.storybook/styles/avatar.css new file mode 100644 index 0000000000..6d2c3c4713 --- /dev/null +++ b/packages/svelte/.storybook/styles/avatar.css @@ -0,0 +1,28 @@ +[data-scope='avatar'][data-part='root'] { + width: 80px; + height: 80px; + border-radius: 9999px; +} + +[data-scope='avatar'][data-part='image'] { + width: 80px; + height: 80px; + object-fit: cover; + border-radius: inherit; +} + +[data-scope='avatar'][data-part='fallback'] { + width: 80px; + height: 80px; + font-size: 14px; + line-height: 1; + font-weight: 600; + color: white; + background-color: #777; +} + +[data-scope='avatar'][data-part='fallback']:not([hidden]) { + display: flex; + align-items: center; + justify-content: center; +} diff --git a/packages/svelte/.storybook/styles/carousel.css b/packages/svelte/.storybook/styles/carousel.css new file mode 100644 index 0000000000..20baa44a9d --- /dev/null +++ b/packages/svelte/.storybook/styles/carousel.css @@ -0,0 +1,5 @@ +[data-scope='carousel'][data-part='viewport'] { + max-width: 600px; + margin-top: 40px; + overflow-x: hidden; +} diff --git a/packages/svelte/.storybook/styles/checkbox.css b/packages/svelte/.storybook/styles/checkbox.css new file mode 100644 index 0000000000..e2dba355a5 --- /dev/null +++ b/packages/svelte/.storybook/styles/checkbox.css @@ -0,0 +1,36 @@ +[data-scope='checkbox'][data-part='root'] { + cursor: pointer; + display: flex; + flex-direction: column; + gap: 8px; +} + +[data-scope='checkbox'][data-part='group'] { + display: flex; + gap: 24px; +} + +[data-scope='checkbox'][data-part='control'] { + border: 2px solid; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + + &[data-invalid] { + border-color: red; + } + + &[data-disabled] { + opacity: 0.5; + } +} + + +[data-scope='checkbox'][data-part='indicator']:not([hidden]) { + display: flex; + align-items: center; + justify-content: center; +} diff --git a/packages/svelte/.storybook/styles/collapsible.css b/packages/svelte/.storybook/styles/collapsible.css new file mode 100644 index 0000000000..0a6bb5ba14 --- /dev/null +++ b/packages/svelte/.storybook/styles/collapsible.css @@ -0,0 +1,38 @@ + +@keyframes slideDown { + from { + opacity: 0.01; + height: 0; + } + to { + opacity: 1; + height: var(--height); + } + } + + @keyframes slideUp { + from { + opacity: 1; + height: var(--height); + } + to { + opacity: 0.01; + height: 0; + } + } + + [data-scope="collapsible"][data-part="content"] { + overflow: hidden; + max-width: 400px; + background-color: cadetblue; + color:white; + } + + [data-scope="collapsible"][data-part="content"][data-state="open"] { + animation: slideDown 250ms cubic-bezier(0, 0, 0.38, 0.9); + } + + [data-scope="collapsible"][data-part="content"][data-state="closed"] { + animation: slideUp 200ms cubic-bezier(0, 0, 0.38, 0.9); + } + \ No newline at end of file diff --git a/packages/svelte/.storybook/styles/color-picker.css b/packages/svelte/.storybook/styles/color-picker.css new file mode 100644 index 0000000000..4808910fee --- /dev/null +++ b/packages/svelte/.storybook/styles/color-picker.css @@ -0,0 +1,81 @@ +[data-scope='color-picker'][data-part='root'] { + display: flex; + flex-direction: column; + gap: 10px; + margin-bottom: 10px; + max-width: 400px; +} + +[data-scope='color-picker'][data-part='control'] { + display: flex; + gap: 4px; +} + +[data-scope='color-picker'][data-part='content'] { + width: 260px; + box-sizing: border-box; + padding: 24px; + border: 1px solid #d5d5d5; + background: white; +} + +[data-scope='color-picker'][data-part='value-text'] { + min-width: fit-content; +} + +[data-scope='color-picker'][data-part='content']:not(:is([hidden])) { + display: flex; + flex-direction: column; + gap: 16px; +} + +[data-scope='color-picker'][data-part='area'] { + height: 200px; + border-radius: 4px; + border: 1px solid #ebebeb; +} + +[data-scope='color-picker'][data-part='area-background'] { + background: rgb(142, 142, 142); + border-radius: 4px; + height: 200px; +} + +[data-scope='color-picker'][data-part='area-thumb'], +[data-scope='color-picker'][data-part='channel-slider-thumb'] { + border: 2px solid white; + border-radius: 9999px; + box-sizing: border-box; + transform: translate(-50%, -50%); + box-shadow: + black 0px 0px 0px 1px, + black 0px 0px 0px 1px inset; + width: 16px; + height: 16px; +} + +[data-scope='color-picker'][data-part='channel-slider-track'] { + height: 20px; + border-radius: 4px; +} + +[data-scope='color-picker'][data-part='channel-input'] { + border-radius: 4px; + width: 100%; + border: 1px solid #c2c2c2; +} + +[data-scope='color-picker'][data-part='swatch-group'] { + display: flex; + gap: 8px; +} + +[data-scope='color-picker'][data-part='swatch'] { + width: 20px; + height: 20px; + flex-shrink: 0; +} + +[data-scope='color-picker'][data-part='transparency-grid'] { + border-radius: 4px; +} diff --git a/packages/svelte/.storybook/styles/combobox.css b/packages/svelte/.storybook/styles/combobox.css new file mode 100644 index 0000000000..d4e7696125 --- /dev/null +++ b/packages/svelte/.storybook/styles/combobox.css @@ -0,0 +1,47 @@ +[data-scope='combobox'][data-part='content'][data-state='open'] { + animation: fadeIn 0.25s ease-out; +} + +[data-scope='combobox'][data-part='content'][data-state='closed'] { + animation: fadeOut 0.2s ease-in; +} + +[data-scope='combobox'][data-part='content'] { + border: 1px solid gainsboro; + padding: 12px; +} + +[data-scope='combobox'][data-part='item'] { + display: flex; + justify-content: space-between; +} +[data-scope='combobox'][data-part='item'][data-highlighted] { + background-color: lightblue; +} + + +[data-scope='combobox'][data-part='item'][data-disabled] { + color: silver; +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeOut { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-10px); + } +} diff --git a/packages/svelte/.storybook/styles/date-picker.css b/packages/svelte/.storybook/styles/date-picker.css new file mode 100644 index 0000000000..a29214278b --- /dev/null +++ b/packages/svelte/.storybook/styles/date-picker.css @@ -0,0 +1,78 @@ +[data-scope='date-picker'][data-part='table-cell-trigger'] { + padding: 4px; + min-width: 30px; + min-height: 30px; + border-radius: 4px; + text-align: center; + user-select: none; + -webkit-tap-highlight-color: transparent; +} + +[data-scope='date-picker'][data-part='table-cell-trigger']:hover { + background: rgba(126, 126, 126, 0.171); +} + +[data-scope='date-picker'][data-part='table-cell-trigger'][data-focus] { + background: rgba(165, 151, 165, 0.085); + color: rgba(128, 0, 128, 0.959); +} + +[data-scope='date-picker'][data-part='table-cell-trigger'][data-outside-range] { + visibility: hidden; +} + +[data-scope='date-picker'][data-part='table-cell-trigger'][data-selected] { + background: purple !important; + color: white !important ; +} + +[data-scope='date-picker'][data-part='table-cell-trigger'][data-in-range]:not([data-selected]) { + background: rgb(240, 219, 240); +} + +[data-scope='date-picker'][data-part='control'] { + display: flex; + gap: 10px; + margin-top: 20px; + margin-bottom: 16px; +} + +[data-scope='date-picker'][data-part='table-cell-trigger'][data-today] { + color: purple; +} + +[data-scope='date-picker'][data-part='table-cell-trigger'][data-unavailable] { + text-decoration: line-through; + opacity: 0.4; +} + +[data-scope='date-picker'][data-part='table-cell-trigger'][data-disabled] { + opacity: 0.4; +} + +[data-scope='date-picker'][data-part='content'] { + border: 1px solid gray; + padding: 1.5rem; + min-width: 320px; + background: white; + border-radius: 8px; +} + +[data-scope='date-picker'][data-part='table'] { + min-width: 240px; + width: 100%; + border-collapse: collapse; +} + +[data-scope='date-picker'][data-part='view-trigger'] { + border: 0; + padding: 4px 20px; + border-radius: 4px; +} + +[data-scope='date-picker'][data-part='view-control'] { + display: flex; + justify-content: space-between; + align-items: center; + margin-block: 10px; +} diff --git a/packages/svelte/.storybook/styles/dialog.css b/packages/svelte/.storybook/styles/dialog.css new file mode 100644 index 0000000000..816f5b91e3 --- /dev/null +++ b/packages/svelte/.storybook/styles/dialog.css @@ -0,0 +1,102 @@ +[data-scope='dialog'][data-part='backdrop'] { + background-color: rgba(0, 0, 0, 0.8); + position: fixed; + inset: 0px; +} + +[data-scope='dialog'][data-part='backdrop'][data-state='open'] { + animation: fadeIn 0.25s ease-out; +} + +[data-scope='dialog'][data-part='backdrop'][data-state='closed'] { + animation: fadeOut 0.2s ease-in; +} + +[data-scope='dialog'][data-part='container'] { + height: 100vh; + width: 100vw; + position: fixed; + inset: 0px; + display: flex; + align-items: center; + justify-content: center; +} + +[data-scope='dialog'][data-part='title'] { + margin: 0px; + font-weight: 500; + color: rgb(26, 21, 35); + font-size: 17px; +} + +[data-scope='dialog'][data-part='description'] { + margin: 10px 0px 20px; + color: rgb(111, 110, 119); + font-size: 15px; + line-height: 1.5; +} + +[data-scope='dialog'][data-part='content'] { + background-color: white; + border-radius: 6px; + box-shadow: + rgb(14 18 22 / 35%) 0px 10px 38px -10px, + rgb(14 18 22 / 20%) 0px 10px 20px -15px; + width: 100%; + max-width: 450px; + max-height: 85vh; + padding: 24px; + position: relative; +} + +[data-scope='dialog'][data-part='content'][data-state='open'] { + animation: scaleIn 0.5s ease-out; +} + +[data-scope='dialog'][data-part='content'][data-state='closed'] { + animation: scaleOut 0.5s ease-in; +} + +[data-scope='dialog'][data-part='close-trigger'] { + position: absolute; + top: 10px; + right: 10px; +} + +[data-scope='dialog'][data-part='close-trigger']:focus { + outline: 2px blue solid; + outline-offset: 2px; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +@keyframes scaleIn { + from { + scale: 0.8; + } + to { + scale: 1; + } +} + +@keyframes scaleOut { + to { + scale: 0.8; + } +} diff --git a/packages/svelte/.storybook/styles/field.css b/packages/svelte/.storybook/styles/field.css new file mode 100644 index 0000000000..313c827ce2 --- /dev/null +++ b/packages/svelte/.storybook/styles/field.css @@ -0,0 +1,7 @@ +[data-scope='field'][data-part='root'] { + display: flex; + flex-direction: column; + gap: 6px; + align-items: start; + } + \ No newline at end of file diff --git a/packages/svelte/.storybook/styles/file-upload.css b/packages/svelte/.storybook/styles/file-upload.css new file mode 100644 index 0000000000..fae6da9e70 --- /dev/null +++ b/packages/svelte/.storybook/styles/file-upload.css @@ -0,0 +1,60 @@ +[data-scope='file-upload'][data-part='root'] { + display: flex; + flex-direction: column; + gap: 0.5rem; + width: 80%; +} + +[data-scope='file-upload'][data-part='dropzone'] { + display: flex; + align-items: center; + flex-direction: column; + gap: 0.5rem; + border-width: 2px; + border-style: dashed; + padding-top: var(--space-8); + padding-bottom: var(--space-8); + padding-inline-start: var(--space-2); + padding-inline-end: var(--space-2); +} + +[data-scope='file-upload'][data-part='trigger'] { + display: inline-flex; + align-items: center; + justify-content: center; + text-align: start; + cursor: pointer; + font-weight: var(--fontWeights-medium); + padding-inline-start: var(--space-4); + padding-inline-end: var(--space-4); + padding-top: var(--space-1); + padding-bottom: var(--space-1); + background: var(--colors-bg-primary-subtle); + color: var(--colors-white); +} + +[data-scope='file-upload'][data-part='item-group'] { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +[data-scope='file-upload'][data-part='item'] { + display: flex; + align-items: center; + flex-direction: row; + gap: 0.5rem; + padding-inline-start: var(--space-3); + padding-inline-end: var(--space-3); + padding-top: var(--space-2); + padding-bottom: var(--space-2); + background: var(--colors-bg-subtle); + border-width: 1px; +} + +[data-scope='file-upload'][data-part='item-preview-image'] { + aspect-ratio: 1; + object-fit: cover; + width: 40px; + height: 40px; +} diff --git a/packages/svelte/.storybook/styles/hover-card.css b/packages/svelte/.storybook/styles/hover-card.css new file mode 100644 index 0000000000..1eea396239 --- /dev/null +++ b/packages/svelte/.storybook/styles/hover-card.css @@ -0,0 +1,45 @@ +[data-scope='hover-card'][data-part='trigger'] { + text-decoration: none; +} + +[data-scope='hover-card'][data-part='content'] { + padding: 0.5rem; + border: 1px solid lightgray; + background: white; + filter: drop-shadow(0px 4px 6px rgba(0, 0, 0, 0.15)); +} + +[data-scope='hover-card'][data-part='arrow'] { + --arrow-background: white; + --arrow-size: 8px; +} + +[data-scope='hover-card'][data-part='content'][data-state='open'] { + animation: fadeIn 0.25s ease-out; +} + +[data-scope='hover-card'][data-part='content'][data-state='closed'] { + animation: fadeOut 0.2s ease-in; +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeOut { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-10px); + } +} diff --git a/packages/svelte/.storybook/styles/menu.css b/packages/svelte/.storybook/styles/menu.css new file mode 100644 index 0000000000..7cd5cf2db6 --- /dev/null +++ b/packages/svelte/.storybook/styles/menu.css @@ -0,0 +1,57 @@ +[data-scope="menu"][data-part="content"] { + margin: 0; + width: 160px; + background-color: white; + border-radius: 6px; + padding: 5px; + border: 1px solid lightgray; + list-style-type: none; +} +[data-scope="menu"][data-part="trigger"] { + display: flex; + gap: 4px; +} + +[data-scope='menu'][data-part='indicator'][data-state='open'] { + rotate: 90deg; +} + +[data-scope="menu"][data-part="item"], +[data-scope="menu"][data-part="trigger-item"], +[data-scope="menu"][data-part="option-item"] { + all: unset; + font-size: 14px; + line-height: 1; + color: rgb(87, 70, 175); + display: flex; + align-items: center; + gap: 4px; + height: 25px; + position: relative; + user-select: none; + border-radius: 3px; + padding: 0px 5px; +} + +[data-scope="menu"][data-part="item"][data-highlighted], +[data-scope="menu"][data-part="trigger-item"][data-highlighted], +[data-scope="menu"][data-part="option-item"][data-highlighted] { + outline: none; + background-color: rgb(110, 86, 207); + color: rgb(253, 252, 254); +} + +[data-scope="menu"][data-part="item"][data-disabled], +[data-scope="menu"][data-part="trigger-item"][data-disabled], +[data-scope="menu"][data-part="option-item"][data-disabled] { + opacity: 0.4; +} + +[data-scope="menu"][data-part="context-trigger"] { + border: 2px dashed blue; + border-radius: 4px; + font-size: 15px; + padding-block: 40px; + width: 300px; + text-align: center; +} diff --git a/packages/svelte/.storybook/styles/number-input.css b/packages/svelte/.storybook/styles/number-input.css new file mode 100644 index 0000000000..5310b958fd --- /dev/null +++ b/packages/svelte/.storybook/styles/number-input.css @@ -0,0 +1,5 @@ +[data-scope='number-input'][data-part='scrubber'] { + width: 16px; + height: 16px; + background-color: red; +} diff --git a/packages/svelte/.storybook/styles/pagination.css b/packages/svelte/.storybook/styles/pagination.css new file mode 100644 index 0000000000..d9b66bda37 --- /dev/null +++ b/packages/svelte/.storybook/styles/pagination.css @@ -0,0 +1,9 @@ +[data-scope='pagination'][data-part='item'][data-selected] { + background-color: aqua; +} + +[data-scope='pagination'][data-part='prev-item'][data-disabled], +[data-scope='pagination'][data-part='next-item'][data-disabled] { + cursor: not-allowed; + opacity: 0.4; +} diff --git a/packages/svelte/.storybook/styles/pin-input.css b/packages/svelte/.storybook/styles/pin-input.css new file mode 100644 index 0000000000..8577a8445c --- /dev/null +++ b/packages/svelte/.storybook/styles/pin-input.css @@ -0,0 +1,18 @@ +[data-scope='pin-input'][data-part='control'] { + width: 300px; + display: flex; + margin-bottom: 12px; + gap: 12px; +} + +[data-scope='pin-input'][data-part='label'] { + display: block; + margin-bottom: 8px; +} + +[data-scope='pin-input'][data-part='input'] { + width: 48px; + height: 48px; + text-align: center; + font-size: 24px; +} diff --git a/packages/svelte/.storybook/styles/popover.css b/packages/svelte/.storybook/styles/popover.css new file mode 100644 index 0000000000..c2f0cce285 --- /dev/null +++ b/packages/svelte/.storybook/styles/popover.css @@ -0,0 +1,56 @@ +[data-scope='popover'][data-part='content'] { + background: white; + padding: 16px; + border-radius: 4px; + position: relative; + filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.2)); + min-width: 240px; +} +[data-scope='popover'][data-part='content'][data-state='open'] { + animation: fadeIn 0.25s ease-out; +} + +[data-scope='popover'][data-part='content'][data-state='closed'] { + animation: fadeOut 0.2s ease-in; +} + +[data-scope='popover'][data-part='title'] { + font-weight: bold; +} + +[data-scope='popover'][data-part='close-trigger'] { + position: absolute; + right: 4px; + top: 4px; +} + +[data-scope='popover'][data-part='anchor'] { + display: inline; + margin-left: 200px; +} + +[data-scope='popover'][data-part='indicator'][data-state='open'] { + rotate: 90deg; +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeOut { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-10px); + } +} diff --git a/packages/svelte/.storybook/styles/presence.css b/packages/svelte/.storybook/styles/presence.css new file mode 100644 index 0000000000..800edd8ba9 --- /dev/null +++ b/packages/svelte/.storybook/styles/presence.css @@ -0,0 +1,32 @@ +[data-scope='presence'][data-part='root'] { + background-color: brown; + color: white; + padding: 24px; + max-width: fit-content; +} + +[data-scope='presence'][data-part='root'][data-state='open'] { + animation: fadeIn 0.25s ease-out; +} + +[data-scope='presence'][data-part='root'][data-state='closed'] { + animation: fadeOut 0.5s ease-in; +} + +@keyframes fadeIn { + from { + opacity: 0; + scale: 0.8; + } + to { + opacity: 1; + scale: 1; + } +} + +@keyframes fadeOut { + to { + opacity: 0; + scale: 0.8; + } +} diff --git a/packages/svelte/.storybook/styles/progress.css b/packages/svelte/.storybook/styles/progress.css new file mode 100644 index 0000000000..04c753851b --- /dev/null +++ b/packages/svelte/.storybook/styles/progress.css @@ -0,0 +1,105 @@ +[data-scope='progress'][data-part='root'] { + display: flex; + flex-direction: column; + gap: 8px; +} + +/* We should consider adding some div grouping track and range for vertical prop like in slider */ +[data-scope='progress'][data-part='control'] { + position: relative; + align-items: center; + display: flex; +} + +[data-scope='progress'][data-part='control'][data-orientation='vertical'] { + height: 20rem; + width: 8px; + flex-direction: column; +} + +[data-scope='progress'][data-part='track'] { + background: silver; + height: 8px; + flex: 1; +} + +[data-scope='progress'][data-part='track'][data-orientation='horizontal'] { + height: 8px; +} + +[data-scope='progress'][data-part='track'][data-orientation='vertical'] { + width: 8px; +} + +[data-scope='progress'][data-part='range'] { + background: orange; +} + +[data-scope='progress'][data-part='range'][data-orientation='horizontal'] { + height: inherit; +} + +[data-scope='progress'][data-part='range'][data-orientation='vertical'] { + width: inherit; +} + +[data-scope='progress'][data-part='range'][data-state='indeterminate'] { + width: 210%; + background: orange; + animation: 1s cubic-bezier(0.694, 0.0482, 0.335, 1) 0s infinite normal none running + linearAnimation; +} + +@keyframes linearAnimation { + from { + transform: scaleX(1) translateX(var(--translate-x)); + } + to { + transform: scaleX(0) translateX(var(--translate-x)); + } +} + +[data-scope='progress'][data-part='circle'] { + --size: 100px; + --thickness: 10px; +} + +[data-scope='progress'][data-part='circle'][data-state='indeterminate'] { + width: 210%; + background: orange; + animation: spin 2s linear infinite; +} + +[data-scope='progress'][data-part='circle-track'] { + stroke: silver; +} + +[data-scope='progress'][data-part='circle-range'] { + stroke: orange; +} + +[data-scope='progress'][data-part='circle-range'][data-state='indeterminate'] { + width: 210%; + background: orange; + animation: circleAnimation 1.5s ease-in-out infinite; +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@keyframes circleAnimation { + from { + stroke-dasharray: 1, 400; + stroke-dashoffset: 0; + } + to { + stroke-dasharray: 400, 400; + stroke-dashoffset: -260; + } +} diff --git a/packages/svelte/.storybook/styles/qr-code.css b/packages/svelte/.storybook/styles/qr-code.css new file mode 100644 index 0000000000..a368b18545 --- /dev/null +++ b/packages/svelte/.storybook/styles/qr-code.css @@ -0,0 +1,26 @@ +[data-scope="qr-code"][data-part="root"] { + width: fit-content; +} + +[data-scope="qr-code"][data-part="frame"] { + width: 120px; + height: 120px; + background-color: white; + } + + [data-scope="qr-code"][data-part="pattern"] { + fill: black; + } + + [data-scope="qr-code"][data-part="overlay"] { + width: 32px; + height: 32px; + outline: 1px solid white; + background-color: white; + + & img { + width: 100%; + height: 100%; + } + } + \ No newline at end of file diff --git a/packages/svelte/.storybook/styles/radio-group.css b/packages/svelte/.storybook/styles/radio-group.css new file mode 100644 index 0000000000..117762e3c2 --- /dev/null +++ b/packages/svelte/.storybook/styles/radio-group.css @@ -0,0 +1,73 @@ +[data-scope='radio-group'][data-part='root'] { + position: relative; + display: flex; + align-items: center; + gap: 16px; +} + +[data-scope='radio-group'][data-part='item'] { + display: inline-flex; + align-items: center; + gap: 8px; + position: relative; + z-index: 2; +} + +[data-scope='radio-group'][data-part='item'][data-disabled] { + cursor: not-allowed; +} + +[data-scope='radio-group'][data-part='item-label'][data-disabled] { + opacity: 0.4; +} + +[data-scope='radio-group'][data-part='item-control'] { + height: 20px; + width: 20px; + background-color: #eee; + border: solid 2px grey; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; +} + +[data-scope='radio-group'][data-part='item-control'][data-focus] { + outline: 2px solid royalblue; +} + +[data-scope='radio-group'][data-part='item-control'][data-hover] { + background-color: #ccc; +} + +[data-scope='radio-group'][data-part='item-control'][data-state='checked'] { + background-color: #2196f3; + border-color: #2196f3; +} + +[data-scope='radio-group'][data-part='item-control'][data-state='checked']::after { + display: initial; +} + +[data-scope='radio-group'][data-part='item-control']::after { + content: ''; + display: none; + width: 4px; + height: 9px; + border: solid white; + border-width: 0 2px 2px 0; + transform: rotate(45deg); + position: relative; + top: -1px; +} + +[data-scope='radio-group'][data-part='indicator'] { + height: 4px; + background-color: red; + z-index: 1; + border-radius: 0.25rem; + box-shadow: + rgba(0, 0, 0, 0.05) 0px 0.0625rem 0.1875rem, + rgba(0, 0, 0, 0.1) 0px 0.0625rem 0.125rem; + background-color: rgb(255, 255, 255); +} diff --git a/packages/svelte/.storybook/styles/segment-group.css b/packages/svelte/.storybook/styles/segment-group.css new file mode 100644 index 0000000000..98a93c2008 --- /dev/null +++ b/packages/svelte/.storybook/styles/segment-group.css @@ -0,0 +1,82 @@ +[data-scope='segment-group'][data-part='root'] { + position: relative; + display: flex; + align-items: center; + gap: 16px; + width: fit-content; + padding: 4px; + background-color: #f1f3f5; + border-radius: 4px; + gap: 8px; +} + +[data-scope='segment-group'][data-part='item'] { + display: inline-flex; + align-items: center; + gap: 8px; + position: relative; + z-index: 2; + padding-left: 0; + padding: 8px; + width: 100%; + text-align: center; +} + +[data-scope='segment-group'][data-part='item'][data-disabled] { + cursor: not-allowed; +} + +[data-scope='segment-group'][data-part='item-text'][data-disabled] { + opacity: 0.4; +} + +[data-scope='segment-group'][data-part='item-control'] { + height: 20px; + width: 20px; + background-color: #eee; + border: solid 2px grey; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; +} + +[data-scope='segment-group'][data-part='item-control'][data-focus] { + outline: 2px solid royalblue; +} + +[data-scope='segment-group'][data-part='item-control'][data-hover] { + background-color: #ccc; +} + +[data-scope='segment-group'][data-part='item-control'][data-state='checked'] { + background-color: #2196f3; + border-color: #2196f3; +} + +[data-scope='segment-group'][data-part='item-control'][data-state='checked']::after { + display: initial; +} + +[data-scope='segment-group'][data-part='item-control']::after { + content: ''; + display: none; + width: 4px; + height: 9px; + border: solid white; + border-width: 0 2px 2px 0; + transform: rotate(45deg); + position: relative; + top: -1px; +} + +[data-scope='segment-group'][data-part='indicator'] { + height: 4px; + background-color: red; + z-index: 1; + border-radius: 0.25rem; + box-shadow: + rgba(0, 0, 0, 0.05) 0px 0.0625rem 0.1875rem, + rgba(0, 0, 0, 0.1) 0px 0.0625rem 0.125rem; + background-color: rgb(255, 255, 255); +} diff --git a/packages/svelte/.storybook/styles/select.css b/packages/svelte/.storybook/styles/select.css new file mode 100644 index 0000000000..c17e2940a7 --- /dev/null +++ b/packages/svelte/.storybook/styles/select.css @@ -0,0 +1,59 @@ +[data-scope='select'][data-part='content'][data-state='open'] { + animation: fadeIn 0.25s ease-out; +} + +[data-scope='select'][data-part='content'][data-state='closed'] { + animation: fadeOut 0.2s ease-in; +} + +[data-scope='select'][data-part='content'] { + border: 1px solid gainsboro; + background: white; + z-index: 1; + padding: 12px; +} + +[data-scope='select'][data-part='item-group-label'] { + font-weight: bold; +} + +[data-scope='select'][data-part='item'] { + display: flex; + justify-content: space-between; +} + +[data-scope='select'][data-part='item'][data-disabled] { + color: silver; +} + +[data-scope='select'][data-part='trigger'] { + display: inline-flex; + gap: 8px; +} + +[data-scope='select'][data-part='trigger'] svg { + width: 1em; + height: 1em; +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeOut { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-10px); + } +} diff --git a/packages/svelte/.storybook/styles/signature-pad.css b/packages/svelte/.storybook/styles/signature-pad.css new file mode 100644 index 0000000000..51d70e6d74 --- /dev/null +++ b/packages/svelte/.storybook/styles/signature-pad.css @@ -0,0 +1,36 @@ +[data-scope=signature-pad][data-part=root] { + position: relative; + display: flex; + flex-direction: column; + max-width: 400px; + width:100%; +} + +[data-scope=signature-pad][data-part=label] { + display: inline-block; + margin-block-end: 8px; +} + +[data-scope="signature-pad"][data-part="control"] { + height: 120px; + background-color: #efefef; + border-radius: 8px; +} + +[data-scope=signature-pad][data-part=guide] { + position: absolute; + bottom: 12%; + left: 8px; + right: 8px; + border-bottom: 1px dashed #2f2f2f; +} + +[data-scope=signature-pad][data-part=clear-trigger] { + position: absolute; + top: 8px; + right: 8px; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 1rem; +} \ No newline at end of file diff --git a/packages/svelte/.storybook/styles/slider.css b/packages/svelte/.storybook/styles/slider.css new file mode 100644 index 0000000000..dd9c1a9c83 --- /dev/null +++ b/packages/svelte/.storybook/styles/slider.css @@ -0,0 +1,129 @@ +.slider > * { + width: 100%; +} + +[data-scope="slider"][data-part="root"] { + max-width: 320px; + width: 100%; + display: flex; + flex-direction: column; +} + +[data-scope="slider"][data-part="root"][data-orientation="vertical"] { + height: 240px; +} + +[data-scope="slider"][data-part="control"] { + --slider-thumb-size: 20px; + --slider-track-height: 4px; + display: flex; + align-items: center; + justify-content: center; + position: relative; +} + +[data-scope="slider"][data-part="control"][data-orientation="horizontal"] { + height: var(--slider-thumb-size); +} + +[data-scope="slider"][data-part="control"][data-orientation="vertical"] { + width: var(--slider-thumb-size); +} + +[data-scope="slider"][data-part="thumb"] { + all: unset; + width: var(--slider-thumb-size); + height: var(--slider-thumb-size); + border-radius: 999px; + background: white; + box-shadow: rgba(0, 0, 0, 0.14) 0px 2px 10px; +} + +[data-scope="slider"][data-part="thumb"]:focus-visible { + box-shadow: rgb(0 0 0 / 22%) 0px 0px 0px 5px; +} + +[data-scope="slider"][data-part="thumb"]:hover:not([data-disabled]) { + background-color: rgb(245, 242, 255); +} + +[data-scope="slider"][data-part="thumb"][data-disabled] { + background-color: lightgray; +} + +[data-scope="slider"] .control-area { + margin-top: 12px; + display: flex; +} + +.slider [data-orientation="horizontal"] .control-area { + flex-direction: column; + width: 100%; +} + +.slider [data-orientation="vertical"] .control-area { + flex-direction: row; + height: 100%; +} + +[data-scope="slider"][data-part="track"] { + background: rgba(0, 0, 0, 0.2); + border-radius: 9999px; +} + +[data-scope="slider"][data-part="track"][data-orientation="horizontal"] { + height: var(--slider-track-height); + width: 100%; +} + +[data-scope="slider"][data-part="track"][data-orientation="vertical"] { + height: 100%; + width: var(--slider-track-height); +} + +[data-scope="slider"][data-part="range"] { + background: magenta; + border-radius: inherit; +} + +[data-scope="slider"][data-part="range"][data-disabled] { + background: rgba(0, 0, 0, 0.4); +} + +[data-scope="slider"][data-part="range"][data-orientation="horizontal"] { + height: 100%; +} + +[data-scope="slider"][data-part="range"][data-orientation="vertical"] { + width: 100%; +} + +[data-scope="slider"][data-part="value-text"] { + margin-inline-start: 12px; +} + +[data-scope="slider"][data-part="marker-group"][data-orientation="vertical"] { + height: 100%; +} + +[data-scope="slider"][data-part="marker"] { + color: lightgray; +} + +[data-scope="slider"][data-part="marker"]:is([data-state="under-value"], [data-state="at-value"]) { + color: red; +} + +[data-scope="slider"][data-part="dragging-indicator"] { + background: magenta; + border-radius: 4px; + padding: 2px 4px; + color: white; + &[data-orientation="horizontal"] { + top: calc(var(--slider-thumb-size) + 8px); + } + + &[data-orientation="vertical"] { + left: calc(var(--slider-thumb-size) + 8px); + } +} diff --git a/packages/svelte/.storybook/styles/splitter.css b/packages/svelte/.storybook/styles/splitter.css new file mode 100644 index 0000000000..0246a07d8c --- /dev/null +++ b/packages/svelte/.storybook/styles/splitter.css @@ -0,0 +1,27 @@ +[data-scope='splitter'][data-part='root'] { + gap: 4px; +} + +[data-scope='splitter'][data-part='root'][data-orientation='horizontal'] { + min-height: 300px; +} + +[data-scope='splitter'][data-part='root'][data-orientation='vertical'] { + min-height: 300px; +} + +[data-scope='splitter'][data-part='panel'] { + display: flex; + align-items: center; + justify-content: center; + border: 1px solid lightgray; + overflow: auto; +} + +[data-scope='splitter'][data-part='panel']:has([data-scope='splitter'][data-part='panel']) { + border: none; +} + +[data-scope='splitter'][data-part='resize-trigger'][data-orientation='vertical'] { + min-height: 12px; +} diff --git a/packages/svelte/.storybook/styles/steps.css b/packages/svelte/.storybook/styles/steps.css new file mode 100644 index 0000000000..9db55611b7 --- /dev/null +++ b/packages/svelte/.storybook/styles/steps.css @@ -0,0 +1,119 @@ +[data-scope="steps"][data-part="root"] { + width: 100%; + max-width: 400px; + display: flex; + gap: 16px; + + &[data-orientation="vertical"] { + flex-direction: row; + } + &[data-orientation="horizontal"] { + flex-direction: column; + } + } + + [data-scope="steps"][data-part="list"] { + display: flex; + justify-content: space-between; + --steps-gutter: 12px; + --steps-size: 24px; + --steps-icon-size: 20px; + + &[data-orientation="vertical"] { + flex-direction: column; + align-items: flex-start; + } + + &[data-orientation="horizontal"] { + flex-direction: row; + align-items: center; + } + } + + [data-scope="steps"][data-part="separator"] { + flex: 1; + background-color: gray; + + &[data-orientation="vertical"] { + position: absolute; + width: 2px; + height: 100%; + max-height: calc(100% - var(--steps-size) - var(--steps-gutter) * 2); + top: calc(var(--steps-size) + var(--steps-gutter)); + inset-inline-start: calc(var(--steps-size) / 2 - 1px); + } + + &[data-orientation="horizontal"] { + width: 100%; + height: 2px; + margin-inline: var(--steps-gutter); + } + + &[data-complete] { + background-color: blue; + } + } + + [data-scope="steps"][data-part="indicator"] { + display: flex; + justify-content: center; + align-items: center; + flex-shrink: 0; + border-radius: 9999px; + font-weight: 600; + width: var(--steps-size); + height: var(--steps-size); + + & svg { + flex-shrink: 0; + width: var(--steps-icon-size); + height: var(--steps-icon-size); + } + + &[data-incomplete] { + border-width: 2px; + } + + &[data-current] { + background-color: lightgray; + border-width: 2px; + border-color: blue; + color: darkblue; + } + + &[data-complete] { + background-color: blue; + color: white; + } + } + + [data-scope="steps"][data-part="item"] { + position: relative; + display: flex; + flex: 1 0 0; + + &:last-of-type { + flex: initial; + + & [data-part="separator"] { + display: none; + } + } + + &[data-orientation="vertical"] { + align-items: flex-start; + } + + &[data-orientation="horizontal"] { + align-items: center; + } + } + + [data-scope="steps"][data-part="trigger"] { + display: flex; + align-items: center; + gap: 12px; + text-align: start; + border-radius: 5px; + } + \ No newline at end of file diff --git a/packages/svelte/.storybook/styles/switch.css b/packages/svelte/.storybook/styles/switch.css new file mode 100644 index 0000000000..10204f389b --- /dev/null +++ b/packages/svelte/.storybook/styles/switch.css @@ -0,0 +1,84 @@ +[data-scope='switch'][data-part='root'] { + display: flex; + align-items: center; + position: relative; + width: fit-content; + + --switch-track-diff: calc(var(--switch-track-width) - var(--switch-track-height)); + --switch-thumb-x: var(--switch-track-diff); + --switch-track-width: 1.875rem; + --switch-track-height: 1rem; +} + +[data-scope='switch'][data-part='control'] { + display: inline-flex; + flex-shrink: 0; + -webkit-box-pack: start; + justify-content: flex-start; + box-sizing: content-box; + cursor: pointer; + border-radius: 9999px; + padding: 0.125rem; + width: var(--switch-track-width); + height: var(--switch-track-height); + transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, + transform; + transition-duration: 150ms; + + --switch-bg: #cbd5e0; + background: var(--switch-bg); +} + +[data-scope='switch'][data-part='control'][data-state='checked'] { + --switch-bg: #3182ce; +} + +[data-scope='switch'][data-part='control'][data-focus] { + box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.6); +} + +[data-scope='switch'][data-part='control'][data-disabled] { + opacity: 0.4; + cursor: not-allowed; +} + +[data-scope='switch'][data-part='thumb'] { + background: white; + transition-property: transform; + transition-duration: 200ms; + border-radius: inherit; + width: var(--switch-track-height); + height: var(--switch-track-height); + position: relative; +} + +[data-scope='switch'][data-part='thumb']:before { + transition: background-color 0.2s ease-in-out; + position: absolute; + --thumb-size: calc(var(--switch-track-height) + 0.7rem); + height: var(--thumb-size); + width: var(--thumb-size); + background-color: transparent; + content: ''; + z-index: 1; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + border-radius: inherit; +} + +[data-scope='switch'][data-part='thumb'][data-hover]:before { + background-color: rgba(0, 0, 0, 0.048); +} +[data-scope='switch'][data-part='thumb'][data-hover][data-state='checked']:before { + background-color: rgba(144, 202, 249, 0.295); +} + +[data-scope='switch'][data-part='thumb'][data-state='checked'] { + transform: translateX(var(--switch-thumb-x)); +} + +[data-scope='switch'][data-part='label'] { + user-select: none; + margin-inline-start: 0.5rem; +} diff --git a/packages/svelte/.storybook/styles/tabs.css b/packages/svelte/.storybook/styles/tabs.css new file mode 100644 index 0000000000..c8be01fd32 --- /dev/null +++ b/packages/svelte/.storybook/styles/tabs.css @@ -0,0 +1,123 @@ +[data-scope='tabs'][data-part='root'] { + max-width: 20em; +} + +[data-scope='tabs'][data-part='root'][data-orientation='vertical'] { + display: flex; +} + +[data-scope='tabs'][data-part='list'] { + margin: 0 0 -0.1em; + overflow: visible; +} + +[data-scope='tabs'][data-part='list'][data-orientation='vertical'] { + display: flex; + flex-direction: column; +} + +[data-scope='tabs'][data-part='trigger'] { + position: relative; + margin: 0; + padding: 0.3em 0.5em 0.4em; + border: 1px solid hsl(219, 1%, 72%); + border-radius: 0.2em 0.2em 0 0; + box-shadow: 0 0 0.2em hsl(219, 1%, 72%); + overflow: visible; + font-size: inherit; + background: hsl(220, 20%, 94%); +} + +[data-scope='tabs'][data-part='trigger']:hover, +[data-scope='tabs'][data-part='trigger']:focus, +[data-scope='tabs'][data-part='trigger']:active { + outline: 0; + border-radius: 0; + color: inherit; +} + +[data-scope='tabs'][data-part='trigger'][data-state='active'] { + border-radius: 0; + background: hsl(220, 43%, 99%); + outline: 0; +} + +[data-scope='tabs'][data-part='trigger'][data-state='active']:not(:focus):not(:hover)::before { + border-top: 5px solid hsl(218, 96%, 48%); +} + +[data-scope='tabs'][data-part='trigger'][data-state='active']::after { + position: absolute; + z-index: 3; + bottom: -1px; + right: 0; + left: 0; + height: 0.3em; + background: hsl(220, 43%, 99%); + box-shadow: none; + content: ''; +} + +[data-scope='tabs'][data-part='trigger']:hover::before, +[data-scope='tabs'][data-part='trigger']:focus::before { + border-color: hsl(20, 96%, 48%); +} + +[data-scope='tabs'][data-part='trigger']:hover::before, +[data-scope='tabs'][data-part='trigger']:focus::before, +[data-scope='tabs'][data-part='trigger'][data-state='active']::before { + position: absolute; + bottom: 100%; + right: -1px; + left: -1px; + border-radius: 0.2em 0.2em 0 0; + border-top: 3px solid hsl(20, 96%, 48%); + content: ''; +} + +[data-scope='tabs'][data-part='content'] { + position: relative; + z-index: 2; + padding: 0.5em 0.5em 0.7em; + border: 1px solid hsl(219, 1%, 72%); + border-radius: 0 0.2em 0.2em 0.2em; + box-shadow: 0 0 0.2em hsl(219, 1%, 72%); + background: hsl(220, 43%, 99%); +} + +[data-scope='tabs'][data-part='content'] p { + margin: 0; +} + +[data-scope='tabs'][data-part='content'] * + p { + margin-top: 1em; +} + +[data-scope='tabs'][data-part='content']:focus { + border-color: hsl(20, 96%, 48%); + box-shadow: 0 0 0.2em hsl(20, 96%, 48%); + outline: 0; +} + +[data-scope='tabs'][data-part='content']:focus::after { + position: absolute; + bottom: 0; + right: -1px; + left: -1px; + border-bottom: 3px solid hsl(20, 96%, 48%); + border-radius: 0 0 0.2em 0.2em; + content: ''; +} + +[data-scope='tabs'][data-part='indicator'] { + background-color: red; + z-index: 10; +} + +[data-scope='tabs'][data-part='indicator'][data-orientation='horizontal'] { + height: 4px; +} + +[data-scope='tabs'][data-part='indicator'][data-orientation='vertical'] { + width: 4px; +} diff --git a/packages/svelte/.storybook/styles/tags-input.css b/packages/svelte/.storybook/styles/tags-input.css new file mode 100644 index 0000000000..aab9433792 --- /dev/null +++ b/packages/svelte/.storybook/styles/tags-input.css @@ -0,0 +1,14 @@ +[data-scope='tags-input'][data-part='item-preview'] { + border-radius: 4px; + padding: 0 8px; + margin-right: 8px; +} + +[data-scope='tags-input'][data-part='control'] { + display: flex; + gap: 2px; +} + +[data-scope='tags-input'][data-part='item-preview'][data-highlighted] { + background-color: aqua; +} diff --git a/packages/svelte/.storybook/styles/time-picker.css b/packages/svelte/.storybook/styles/time-picker.css new file mode 100644 index 0000000000..e542980db9 --- /dev/null +++ b/packages/svelte/.storybook/styles/time-picker.css @@ -0,0 +1,61 @@ +[hidden] { + display: none !important; +} + +[data-scope="time-picker"][data-part="content"] { + border: 1px solid gray; + background: white; + border-radius: 8px; + overflow: hidden; + display: flex; + max-height: 200px; +} + +[data-scope="time-picker"][data-part="column"] { + display: flex; + gap: 4px; + flex-direction: column; + overflow-y: scroll; + padding: 4px; + + &[data-focus] { + background: rgb(247, 247, 247); + } + + /* hide scroll bar */ + scrollbar-width: none; + -ms-overflow-style: none; + &::-webkit-scrollbar { + display: none; + } + & + & { + border-inline-start: 1px solid rgb(209, 209, 209); + } +} + +[data-scope="time-picker"][data-part="spacer"] { + display: block; + flex-shrink: 0; + height: calc(100% - 36px); +} + +[data-scope="time-picker"][data-part="cell"] { + background: none; + border: none; + padding: 8px; + border-radius: 4px; + + &[data-now] { + background: lightblue; + } + + &[data-selected] { + background: purple; + color: white; + } + + &[data-disabled] { + opacity: 0.25; + cursor: not-allowed; + } +} diff --git a/packages/svelte/.storybook/styles/timer.css b/packages/svelte/.storybook/styles/timer.css new file mode 100644 index 0000000000..9998eb13fe --- /dev/null +++ b/packages/svelte/.storybook/styles/timer.css @@ -0,0 +1,26 @@ +[data-scope="timer"][data-part="root"] { + display: flex; + flex-direction: column; + gap: 1rem; +} + +[data-scope="timer"][data-part="area"] { + display: flex; + align-items: center; +} + +[data-scope="timer"][data-part="item"] { + font-size: 2rem; + font-weight: 500; +} + +[data-scope="timer"][data-part="separator"] { + font-size: 1rem; + font-weight: 500; + margin-inline: 0.5rem; +} + +[data-scope="timer"][data-part="control"] { + display: flex; + gap: 4px; +} diff --git a/packages/svelte/.storybook/styles/toast.css b/packages/svelte/.storybook/styles/toast.css new file mode 100644 index 0000000000..cd406fdf77 --- /dev/null +++ b/packages/svelte/.storybook/styles/toast.css @@ -0,0 +1,122 @@ +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@keyframes shrink { + from { + transform: scaleX(1); + } + to { + transform: scaleX(0); + } +} + +[data-scope="toast"][data-part="root"] { + background: white; + padding: 8px 12px; + box-shadow: + 0 3px 10px rgba(0, 0, 0, 0.1), + 0 3px 3px rgba(0, 0, 0, 0.05); + width: 360px; + overflow-wrap: anywhere; + translate: var(--x) var(--y); + scale: var(--scale); + z-index: var(--z-index); + height: var(--height); + opacity: var(--opacity); + + will-change: translate, opacity, scale; + transition: + translate 400ms, + scale 400ms, + opacity 400ms, + height 400ms, + box-shadow 200ms; + transition-timing-function: cubic-bezier(0.21, 1.02, 0.73, 1); + + &[data-state="closed"] { + transition: + translate 400ms, + scale 400ms, + opacity 200ms; + transition-timing-function: cubic-bezier(0.06, 0.71, 0.55, 1); + } +} + +[data-scope="toast"][data-part="close-trigger"] { + position: absolute; + right: 8px; + top: 8px; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + font-size: 18px; + padding: 0; + + & svg { + width: 1em; + height: 1em; + } +} + +[data-scope="toast"][data-part="title"] { + display: flex; + align-items: center; + gap: 12px; +} + +[data-scope="toast"][data-part="root"][data-type="error"] { + background: red; + color: white; +} + +[data-scope="toast"][data-part="root"][data-type="info"] { + background: blue; + color: white; +} + +[data-scope="toast"][data-part="root"][data-type="warning"] { + background: orange; +} + +[data-scope="toast"][data-part="root"][data-type="success"] { + background: green; + color: white; +} + +[data-scope="toast"] .spinner { + animation: spin 1s linear infinite; +} + +[data-scope="toast"][data-part="progressbar"] { + height: 4px; + background: rgb(116, 116, 116); + width: 100%; + position: absolute; + bottom: 0; + inset-inline: 0; + animation-name: shrink; + animation-fill-mode: forwards; +} + +[data-scope="toast"][data-part="progressbar"][data-type="loading"] { + animation-name: none; +} + +@media (max-width: 640px) { + [data-scope="toast"][data-part="group"] { + width: 100%; + } + + [data-scope="toast"][data-part="root"] { + inset-inline: 0; + width: calc(100% - var(--gap) * 2); + } +} diff --git a/packages/svelte/.storybook/styles/toggle-group.css b/packages/svelte/.storybook/styles/toggle-group.css new file mode 100644 index 0000000000..e90bf37b44 --- /dev/null +++ b/packages/svelte/.storybook/styles/toggle-group.css @@ -0,0 +1,3 @@ +[data-state='on'] { + border-color: blue; +} diff --git a/packages/svelte/.storybook/styles/tooltip.css b/packages/svelte/.storybook/styles/tooltip.css new file mode 100644 index 0000000000..4b862ffc5e --- /dev/null +++ b/packages/svelte/.storybook/styles/tooltip.css @@ -0,0 +1,38 @@ +[data-scope='tooltip'][data-part='content'] { + background: black; + color: white; + padding: 6px 8px; + border-radius: 4px; + font-size: 14px; +} + +[data-scope='tooltip'][data-part='content'][data-state='open'] { + animation: fadeIn 0.5s ease-out; +} + +[data-scope='tooltip'][data-part='content'][data-state='closed'] { + animation: fadeOut 0.5s ease-in; +} + +[data-scope='tooltip'][data-part='arrow'] { + --arrow-size: 8px; + --arrow-background: black; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} diff --git a/packages/svelte/.storybook/styles/tree-view.css b/packages/svelte/.storybook/styles/tree-view.css new file mode 100644 index 0000000000..2e695815c0 --- /dev/null +++ b/packages/svelte/.storybook/styles/tree-view.css @@ -0,0 +1,98 @@ +[data-scope="tree-view"][data-part="tree"] { + margin-top: 20px; + width: 240px; +} + +[data-scope="tree-view"][data-part="item"], +[data-scope="tree-view"][data-part="branch-control"] { + user-select: none; + --padding-inline: 16px; + padding-inline-start: calc(var(--depth) * var(--padding-inline)); + padding-inline-end: var(--padding-inline); + display: flex; + align-items: center; + gap: 8px; + border-radius: 2px; + min-height: 32px; + + & svg { + width: 16px; + height: 16px; + opacity: 0.5; + } + + &:hover { + background: rgb(243, 243, 243); + } + + &[data-selected] { + background: rgb(226, 226, 226); + } + + &:focus { + outline: 1px solid rgb(148, 148, 148); + outline-offset: -1px; + } +} + +[data-scope="tree-view"][data-part="item-text"], +[data-scope="tree-view"][data-part="branch-text"] { + flex: 1; +} + +[data-scope="tree-view"][data-part="branch-content"] { + position: relative; + isolation: isolate; +} + +[data-scope="tree-view"][data-part="branch-indent-guide"] { + position: absolute; + content: ""; + border-left: 1px solid rgb(226, 226, 226); + height: 100%; + translate: calc(var(--depth) * 1.25rem); + z-index: 0; +} + +[data-scope="tree-view"][data-part="branch-indicator"] { + display: flex; + align-items: center; + &[data-state="open"] svg { + transform: rotate(90deg); + } +} + +@keyframes slideDown { + from { + opacity: 0.01; + height: 0; + } + to { + opacity: 1; + height: var(--height); + } +} + +@keyframes slideUp { + from { + opacity: 1; + height: var(--height); + } + to { + opacity: 0.01; + height: 0; + } +} + +[data-scope="tree-view"][data-part="branch-content"] { + overflow: hidden; + max-width: 400px; +} + +[data-scope="tree-view"][data-part="branch-content"][data-state="open"] { + animation: slideDown 250ms cubic-bezier(0, 0, 0.38, 0.9); +} + +[data-scope="tree-view"][data-part="branch-content"][data-state="closed"] { + animation: slideUp 200ms cubic-bezier(0, 0, 0.38, 0.9); +} diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md new file mode 100644 index 0000000000..fd338bec53 --- /dev/null +++ b/packages/svelte/CHANGELOG.md @@ -0,0 +1,11 @@ +--- +id: changelog +title: Changelog +description: All notable changes will be documented in this file. +--- + +## [Unreleased] + +### Added + +- Added `Avatar` component. diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 759c0d8d1a..0174aca797 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,44 +1,84 @@ { "name": "@ark-ui/svelte", "version": "0.0.1", - "scripts": { - "dev": "vite dev", - "preview": "vite preview", - "package": "svelte-kit sync && svelte-package && publint", - "prepublishOnly": "npm run package", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "test": "vitest" + "description": "A collection of unstyled, accessible UI components for Svelte", + "keywords": ["avatar", "svelte"], + "license": "MIT", + "homepage": "https://ark-ui.com", + "repository": { + "type": "git", + "url": "git+https://github.com/chakra-ui/ark.git", + "directory": "packages/svelte" }, + "bugs": { + "url": "https://github.com/chakra-ui/ark/issues" + }, + "type": "module", + "svelte": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": ["dist", "!dist/**/*.stories.*", "!dist/**/examples/**", "!dist/**/*.test.*"], "exports": { ".": { - "types": "./dist/index.d.ts", - "svelte": "./dist/index.js" + "types": "./src/lib/index.ts", + "svelte": "./src/lib/index.ts" + }, + "./*": { + "types": "./src/lib/components/*/index.ts", + "svelte": "./src/lib/components/*/index.ts" } }, - "files": ["dist", "!dist/**/*.test.*", "!dist/**/*.spec.*"], - "peerDependencies": { - "svelte": "5.1.3" + "scripts": { + "build": "svelte-kit sync && svelte-package", + "dev": "vite dev", + "storybook": "storybook dev -p 6006", + "test": "vitest", + "test:ci": "vitest --run", + "typecheck": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "release-it": "release-it --config ../../release-it.json", + "prepack": "clean-package", + "postpack": "clean-package restore" + }, + "clean-package": { + "replace": { + "exports.\\..svelte": "./dist/index.js", + "exports.\\..types": "./dist/index.d.ts", + "exports.\\./*.svelte": "./dist/components/*/index.js", + "exports.\\./*.types": "./dist/components/*/index.d.ts" + } + }, + "publishConfig": { + "access": "public" }, + "sideEffects": false, "dependencies": { "@zag-js/avatar": "0.77.1", "@zag-js/core": "0.77.1", - "@zag-js/svelte": "0.77.1" + "@zag-js/svelte": "0.77.1", + "nanoid": "5.0.9" }, "devDependencies": { + "@release-it/keep-a-changelog": "5.0.0", + "@storybook/addon-a11y": "8.4.5", + "@storybook/addon-essentials": "8.4.5", + "@storybook/sveltekit": "8.4.5", "@sveltejs/adapter-auto": "3.3.1", "@sveltejs/kit": "2.8.4", "@sveltejs/package": "2.3.7", "@sveltejs/vite-plugin-svelte": "4.0.2", - "publint": "0.2.12", - "svelte": "5.2.3", + "@testing-library/jest-dom": "6.6.3", + "@testing-library/svelte": "5.2.6", + "@testing-library/user-event": "14.5.2", + "clean-package": "2.2.0", + "release-it": "17.10.0", + "storybook": "8.4.5", + "svelte": "5.2.8", "svelte-check": "4.1.0", "tslib": "2.8.1", "typescript": "5.6.3", "vite": "5.4.11", "vitest": "2.1.5" }, - "svelte": "./dist/index.js", - "types": "./dist/index.d.ts", - "type": "module" + "peerDependencies": { + "svelte": ">=5.0.0" + } } diff --git a/packages/svelte/src/index.test.ts b/packages/svelte/src/index.test.ts deleted file mode 100644 index 31ae142976..0000000000 --- a/packages/svelte/src/index.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { describe, expect, it } from 'vitest' - -describe('sum test', () => { - it('adds 1 + 2 to equal 3', () => { - expect(1 + 2).toBe(3) - }) -}) diff --git a/packages/svelte/src/lib/components/avatar/avatar-context.svelte b/packages/svelte/src/lib/components/avatar/avatar-context.svelte new file mode 100644 index 0000000000..a16494ee51 --- /dev/null +++ b/packages/svelte/src/lib/components/avatar/avatar-context.svelte @@ -0,0 +1,17 @@ + + + + +{@render api?.(avatar)} diff --git a/packages/svelte/src/lib/components/avatar/avatar-fallback.svelte b/packages/svelte/src/lib/components/avatar/avatar-fallback.svelte index a398b0c811..f731263ec7 100644 --- a/packages/svelte/src/lib/components/avatar/avatar-fallback.svelte +++ b/packages/svelte/src/lib/components/avatar/avatar-fallback.svelte @@ -1,20 +1,18 @@ - - + - -
-{@render children()} +
+ {@render props.children?.()}
- - \ No newline at end of file diff --git a/packages/svelte/src/lib/components/avatar/avatar-image.svelte b/packages/svelte/src/lib/components/avatar/avatar-image.svelte index 76cba371ac..d588f29b7c 100644 --- a/packages/svelte/src/lib/components/avatar/avatar-image.svelte +++ b/packages/svelte/src/lib/components/avatar/avatar-image.svelte @@ -1,18 +1,16 @@ - - + - - - - \ No newline at end of file + diff --git a/packages/svelte/src/lib/components/avatar/avatar-root-provider.svelte b/packages/svelte/src/lib/components/avatar/avatar-root-provider.svelte new file mode 100644 index 0000000000..d91940c2b8 --- /dev/null +++ b/packages/svelte/src/lib/components/avatar/avatar-root-provider.svelte @@ -0,0 +1,26 @@ + + + + +
+ {@render props.children?.()} +
diff --git a/packages/svelte/src/lib/components/avatar/avatar-root.svelte b/packages/svelte/src/lib/components/avatar/avatar-root.svelte index b279ce328d..6971cfda60 100644 --- a/packages/svelte/src/lib/components/avatar/avatar-root.svelte +++ b/packages/svelte/src/lib/components/avatar/avatar-root.svelte @@ -1,21 +1,28 @@ - - -
- {@render children()} + +
+ {@render props.children?.()}
diff --git a/packages/svelte/src/lib/components/avatar/avatar.anatomy.ts b/packages/svelte/src/lib/components/avatar/avatar.anatomy.ts new file mode 100644 index 0000000000..c738affd3f --- /dev/null +++ b/packages/svelte/src/lib/components/avatar/avatar.anatomy.ts @@ -0,0 +1 @@ +export { anatomy as avatarAnatomy } from '@zag-js/avatar' diff --git a/packages/svelte/src/lib/components/avatar/avatar.stories.ts b/packages/svelte/src/lib/components/avatar/avatar.stories.ts new file mode 100644 index 0000000000..198153c88e --- /dev/null +++ b/packages/svelte/src/lib/components/avatar/avatar.stories.ts @@ -0,0 +1,28 @@ +import type { Meta } from '@storybook/svelte' +import BasicExample from './examples/basic.svelte' +import ContextExample from './examples/context.svelte' +import RootProviderExample from './examples/root-provider.svelte' + +const meta = { + title: 'Components / Avatar', +} as Meta + +export default meta + +export const Basic = { + render: () => ({ + Component: BasicExample, + }), +} + +export const RootProvider = { + render: () => ({ + Component: RootProviderExample, + }), +} + +export const Context = { + render: () => ({ + Component: ContextExample, + }), +} diff --git a/packages/svelte/src/lib/components/avatar/avatar.test.ts b/packages/svelte/src/lib/components/avatar/avatar.test.ts new file mode 100644 index 0000000000..af64016475 --- /dev/null +++ b/packages/svelte/src/lib/components/avatar/avatar.test.ts @@ -0,0 +1,10 @@ +import { render, screen } from '@testing-library/svelte' +import { describe, expect, it } from 'vitest' +import ComponentUnderTest from './examples/basic.svelte' + +describe('Avatar', async () => { + it("should render the user's initials", async () => { + render(ComponentUnderTest) + expect(screen.getByText('PA')).toBeInTheDocument() + }) +}) diff --git a/packages/svelte/src/lib/components/avatar/avatar.ts b/packages/svelte/src/lib/components/avatar/avatar.ts new file mode 100644 index 0000000000..61b5ca7714 --- /dev/null +++ b/packages/svelte/src/lib/components/avatar/avatar.ts @@ -0,0 +1,25 @@ +export type { StatusChangeDetails } from '@zag-js/avatar' +export { + default as Context, + type AvatarContextProps as ContextProps, +} from './avatar-context.svelte' +export { + default as Fallback, + type AvatarFallbackProps as FallbackProps, + type AvatarFallbackBaseProps as FallbackBaseProps, +} from './avatar-fallback.svelte' +export { + default as Image, + type AvatarImageProps as ImageProps, + type AvatarImageBaseProps as ImageBaseProps, +} from './avatar-image.svelte' +export { + default as RootProvider, + type AvatarRootProviderProps as RootProviderProps, + type AvatarRootProviderBaseProps as RootProviderBaseProps, +} from './avatar-root-provider.svelte' +export { + default as Root, + type AvatarRootBaseProps as RootBaseProps, + type AvatarRootProps as RootProps, +} from './avatar-root.svelte' diff --git a/packages/svelte/src/lib/components/avatar/examples/basic.svelte b/packages/svelte/src/lib/components/avatar/examples/basic.svelte new file mode 100644 index 0000000000..b4b5c32a6b --- /dev/null +++ b/packages/svelte/src/lib/components/avatar/examples/basic.svelte @@ -0,0 +1,8 @@ + + + + PA + + diff --git a/packages/svelte/src/lib/components/avatar/examples/context.svelte b/packages/svelte/src/lib/components/avatar/examples/context.svelte new file mode 100644 index 0000000000..2c00d54bf1 --- /dev/null +++ b/packages/svelte/src/lib/components/avatar/examples/context.svelte @@ -0,0 +1,18 @@ + + + + + {#snippet api(avatar)} + + {#if avatar().loaded} +

PA

+ {:else} +

Loading

+ {/if} +
+ {/snippet} +
+ +
diff --git a/packages/svelte/src/lib/components/avatar/examples/root-provider.svelte b/packages/svelte/src/lib/components/avatar/examples/root-provider.svelte new file mode 100644 index 0000000000..ee8899ff27 --- /dev/null +++ b/packages/svelte/src/lib/components/avatar/examples/root-provider.svelte @@ -0,0 +1,18 @@ + + + + + + PA + + diff --git a/packages/svelte/src/lib/components/avatar/index.ts b/packages/svelte/src/lib/components/avatar/index.ts index 8360879d4f..018bba0cf3 100644 --- a/packages/svelte/src/lib/components/avatar/index.ts +++ b/packages/svelte/src/lib/components/avatar/index.ts @@ -1,11 +1,27 @@ export type { StatusChangeDetails as AvatarStatusChangeDetails } from '@zag-js/avatar' -// export { default as AvatarContext, type AvatarContextProps } from './avatar-context.svelte' -export { default as AvatarFallback, type AvatarFallbackProps } from './avatar-fallback.svelte' -export { default as AvatarImage, type AvatarImageProps } from './avatar-image.svelte' +export { default as AvatarContext } from './avatar-context.svelte' +export { + default as AvatarFallback, + type AvatarFallbackProps, + type AvatarFallbackBaseProps, +} from './avatar-fallback.svelte' +export { + default as AvatarImage, + type AvatarImageProps, + type AvatarImageBaseProps, +} from './avatar-image.svelte' export { default as AvatarRoot, + type AvatarRootBaseProps, type AvatarRootProps, } from './avatar-root.svelte' export { useAvatarContext, type UseAvatarContext } from './use-avatar-context' +export { useAvatar, type UseAvatarProps, type UseAvatarReturn } from './use-avatar.svelte' +export { + default as AvatarRootProvider, + type AvatarRootProviderProps, + type AvatarRootProviderBaseProps, +} from './avatar-root-provider.svelte' +export { avatarAnatomy } from './avatar.anatomy' -// export * as Avatar from './avatar' +export * as Avatar from './avatar' diff --git a/packages/svelte/src/lib/components/avatar/use-avatar-context.ts b/packages/svelte/src/lib/components/avatar/use-avatar-context.ts index a2dc8cf55c..aebd6fd0e1 100644 --- a/packages/svelte/src/lib/components/avatar/use-avatar-context.ts +++ b/packages/svelte/src/lib/components/avatar/use-avatar-context.ts @@ -1,4 +1,4 @@ -import { createContext } from '../../utils' +import { createContext } from '$lib/utils/create-context' import type { UseAvatarReturn } from './use-avatar.svelte' export interface UseAvatarContext extends UseAvatarReturn {} diff --git a/packages/svelte/src/lib/components/avatar/use-avatar.svelte.ts b/packages/svelte/src/lib/components/avatar/use-avatar.svelte.ts index 7907ffb732..45fa66f7ca 100644 --- a/packages/svelte/src/lib/components/avatar/use-avatar.svelte.ts +++ b/packages/svelte/src/lib/components/avatar/use-avatar.svelte.ts @@ -1,19 +1,19 @@ +import type { Accessor, Optional } from '$lib/types' +import { createId } from '$lib/utils/create-id' import * as avatar from '@zag-js/avatar' import { type PropTypes, normalizeProps, useMachine } from '@zag-js/svelte' -import type { Optional } from '../../../typts' export interface UseAvatarProps extends Optional, 'id'> {} -export interface UseAvatarReturn extends avatar.Api {} +export interface UseAvatarReturn extends Accessor> {} -export const useAvatar = (props: UseAvatarProps) => { - const [snapshot, send] = useMachine(avatar.machine({ id: '1' })) - const _api = avatar.connect(snapshot, send, normalizeProps) - const api = $derived(_api) - - return new Proxy(api, { - get(_, key: keyof typeof api) { - return api[key] - }, +export const useAvatar = (props: UseAvatarProps = {}) => { + const context = $derived({ + id: createId(), + ...props, }) + + const [state, send] = useMachine(avatar.machine(context), { context }) + const api = $derived(() => avatar.connect(state, send, normalizeProps)) + return api } diff --git a/packages/svelte/src/lib/types.ts b/packages/svelte/src/lib/types.ts new file mode 100644 index 0000000000..bf034f9fe9 --- /dev/null +++ b/packages/svelte/src/lib/types.ts @@ -0,0 +1,9 @@ +import type { SvelteHTMLElements } from 'svelte/elements' + +export type Assign = Omit & U +export type Optional = Pick, K> & Omit + +export type CollectionItem = string | object + +export type HTMLProps = SvelteHTMLElements[T] +export type Accessor = () => T diff --git a/packages/svelte/src/lib/utils/create-id.ts b/packages/svelte/src/lib/utils/create-id.ts new file mode 100644 index 0000000000..e7c2bbb68a --- /dev/null +++ b/packages/svelte/src/lib/utils/create-id.ts @@ -0,0 +1,4 @@ +import { nanoid } from 'nanoid/non-secure' + +// TODO https://github.com/sveltejs/svelte/issues/7517 +export const createId = () => nanoid(10) diff --git a/packages/svelte/src/lib/utils/create-split-props.ts b/packages/svelte/src/lib/utils/create-split-props.ts new file mode 100644 index 0000000000..d5b6d221ea --- /dev/null +++ b/packages/svelte/src/lib/utils/create-split-props.ts @@ -0,0 +1,25 @@ +type EnsureKeys< + ExpectedKeys extends (keyof Target)[], + Target, +> = keyof Target extends ExpectedKeys[number] + ? unknown + : `Missing required keys: ${Exclude & string}` + +export const createSplitProps = + () => + ( + props: Props, + keys: Keys & EnsureKeys, + ) => + (keys as string[]).reduce<[Target, Omit>]>( + (previousValue, currentValue) => { + const [target, source] = previousValue + const key = currentValue as keyof Target & keyof typeof source + if (source[key] !== undefined) { + target[key] = source[key] + } + delete source[key] + return [target, source] + }, + [{} as Target, { ...props }], + ) diff --git a/packages/svelte/src/lib/utils/index.ts b/packages/svelte/src/lib/utils/index.ts deleted file mode 100644 index 365408a04a..0000000000 --- a/packages/svelte/src/lib/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { createContext } from './create-context' diff --git a/packages/svelte/src/routes/+page.svelte b/packages/svelte/src/routes/+page.svelte index a660466dac..fb3ee53272 100644 --- a/packages/svelte/src/routes/+page.svelte +++ b/packages/svelte/src/routes/+page.svelte @@ -1,10 +1,8 @@ - -

Welcome to your library project

- - CS - - - \ No newline at end of file + + + CS + + diff --git a/packages/svelte/src/test-setup.ts b/packages/svelte/src/test-setup.ts new file mode 100644 index 0000000000..a9d0dd31aa --- /dev/null +++ b/packages/svelte/src/test-setup.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom/vitest' diff --git a/packages/svelte/src/typts.d.ts b/packages/svelte/src/typts.d.ts deleted file mode 100644 index dd849ceb51..0000000000 --- a/packages/svelte/src/typts.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type Assign = Omit & U -export type Optional = Pick, K> & Omit -export type CollectionItem = string | object diff --git a/packages/svelte/src/typts.ts b/packages/svelte/src/typts.ts deleted file mode 100644 index 182c69dd66..0000000000 --- a/packages/svelte/src/typts.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type Assign = Omit & U -export type Optional = Pick, K> & Omit - -export type CollectionItem = string | object diff --git a/packages/svelte/static/favicon.png b/packages/svelte/static/favicon.png deleted file mode 100644 index 825b9e65af..0000000000 Binary files a/packages/svelte/static/favicon.png and /dev/null differ diff --git a/packages/svelte/vite.config.ts b/packages/svelte/vite.config.ts index 7808fb1b8d..bd8e4ac09a 100644 --- a/packages/svelte/vite.config.ts +++ b/packages/svelte/vite.config.ts @@ -1,9 +1,12 @@ import { sveltekit } from '@sveltejs/kit/vite' +import { svelteTesting } from '@testing-library/svelte/vite' import { defineConfig } from 'vitest/config' export default defineConfig({ - plugins: [sveltekit()], + plugins: [sveltekit(), svelteTesting()], test: { + environment: 'jsdom', + setupFiles: ['./src/test-setup.ts'], include: ['src/**/*.{test,spec}.{js,ts}'], }, }) diff --git a/scripts/package.json b/scripts/package.json index 1b722a07a6..128f34ed49 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -15,6 +15,7 @@ "postvue:props": "bun biome format --write ../packages/vue/src/", "play": "bun run src/play.ts", "format:vue": "prettier --write '../**/*.vue'", + "format:svelte": "prettier --write '../**/*.svelte'", "format:mdx": "prettier --write '../**/CHANGELOG.md'", "local:sync": "bun run src/symlink.ts" }, @@ -29,6 +30,7 @@ "pkg-dir": "8.0.0", "prettier": "3.4.0", "prettier-plugin-organize-imports": "4.1.0", + "prettier-plugin-svelte": "3.3.2", "ts-morph": "24.0.0", "ts-pattern": "5.5.0", "typescript": "5.6.3",