├── static
├── .nojekyll
├── favicon.png
└── robots.txt
├── .npmrc
├── src
├── lib
│ ├── components
│ │ ├── Blocks
│ │ │ ├── IconButton
│ │ │ │ └── README.md
│ │ │ ├── Progress
│ │ │ │ ├── README.md
│ │ │ │ └── Progress.svelte
│ │ │ ├── Link
│ │ │ │ ├── README.md
│ │ │ │ └── Link.svelte
│ │ │ ├── WriteBarIcon
│ │ │ │ └── README.md
│ │ │ ├── Banner
│ │ │ │ ├── BannerSubheader.svelte
│ │ │ │ └── BannerHeader.svelte
│ │ │ ├── Div
│ │ │ │ ├── README.md
│ │ │ │ └── Div.svelte
│ │ │ ├── Header
│ │ │ │ ├── HeaderSubtitle.svelte
│ │ │ │ ├── HeaderAside.svelte
│ │ │ │ └── HeaderContent.svelte
│ │ │ ├── PanelSpinner
│ │ │ │ ├── PanelSpinner.svelte
│ │ │ │ └── README.md
│ │ │ ├── Counter
│ │ │ │ └── CounterTypography.svelte
│ │ │ ├── Footer
│ │ │ │ ├── Footer.svelte
│ │ │ │ └── README.md
│ │ │ ├── Spinner
│ │ │ │ ├── README.md
│ │ │ │ └── Spinner.svelte
│ │ │ ├── Search
│ │ │ │ ├── SearchPlaceholderTypography.svelte
│ │ │ │ └── README.md
│ │ │ ├── Switch
│ │ │ │ └── README.md
│ │ │ ├── List
│ │ │ │ ├── README.md
│ │ │ │ └── List.svelte
│ │ │ ├── Card
│ │ │ │ └── README.md
│ │ │ ├── SimpleCell
│ │ │ │ └── SimpleCellTypography.svelte
│ │ │ ├── GridAvatar
│ │ │ │ └── README.md
│ │ │ ├── InfoRow
│ │ │ │ ├── README.md
│ │ │ │ └── InfoRow.svelte
│ │ │ ├── Badge
│ │ │ │ ├── Badge.svelte
│ │ │ │ └── README.md
│ │ │ ├── CardGrid
│ │ │ │ └── README.md
│ │ │ ├── InitialsAvatar
│ │ │ │ └── README.md
│ │ │ ├── Placeholder
│ │ │ │ └── README.md
│ │ │ ├── Separator
│ │ │ │ ├── README.md
│ │ │ │ └── Separator.svelte
│ │ │ ├── Cell
│ │ │ │ ├── CellDragger.svelte
│ │ │ │ └── CellCheckbox.svelte
│ │ │ ├── Gradient
│ │ │ │ └── README.md
│ │ │ ├── CellButton
│ │ │ │ ├── README.md
│ │ │ │ └── CellButton.svelte
│ │ │ ├── CardScroll
│ │ │ │ └── CardScroll.svelte
│ │ │ ├── ModalCardBase
│ │ │ │ └── README.md
│ │ │ ├── RichCell
│ │ │ │ └── README.md
│ │ │ ├── Button
│ │ │ │ └── ButtonTypography.svelte
│ │ │ ├── MiniInfoCell
│ │ │ │ └── README.md
│ │ │ ├── Removable
│ │ │ │ └── RemovableIos.svelte
│ │ │ └── Spacing
│ │ │ │ └── Spacing.svelte
│ │ ├── Layout
│ │ │ ├── Panel
│ │ │ │ └── README.md
│ │ │ ├── SplitCol
│ │ │ │ ├── README.md
│ │ │ │ ├── SplitColContext.svelte
│ │ │ │ └── SplitCol.svelte
│ │ │ ├── SplitLayout
│ │ │ │ ├── README.md
│ │ │ │ └── SplitLayout.svelte
│ │ │ ├── PanelHeader
│ │ │ │ ├── README.md
│ │ │ │ └── PanelHeaderIn.svelte
│ │ │ ├── Tabbar
│ │ │ │ ├── README.md
│ │ │ │ └── Tabbar.svelte
│ │ │ ├── PanelHeaderBack
│ │ │ │ ├── README.md
│ │ │ │ └── PanelHeaderBack.svelte
│ │ │ ├── PanelHeaderEdit
│ │ │ │ ├── README.md
│ │ │ │ └── PanelHeaderEdit.svelte
│ │ │ ├── PanelHeaderButton
│ │ │ │ ├── ButtonTypography.svelte
│ │ │ │ └── README.md
│ │ │ ├── PanelHeaderClose
│ │ │ │ ├── README.md
│ │ │ │ └── PanelHeaderClose.svelte
│ │ │ ├── PanelHeaderSubmit
│ │ │ │ ├── README.md
│ │ │ │ └── PanelHeaderSubmit.svelte
│ │ │ ├── FixedLayout
│ │ │ │ └── README.md
│ │ │ ├── HorizontalScroll
│ │ │ │ └── HorizontalScroll.svelte
│ │ │ └── AppRoot
│ │ │ │ ├── AppRootContext.svelte
│ │ │ │ └── ScrollContext.svelte
│ │ ├── Service
│ │ │ ├── ConfigProvider
│ │ │ │ ├── README.md
│ │ │ │ └── DOMContext.svelte
│ │ │ ├── AdaptivityProvider
│ │ │ │ └── README.md
│ │ │ ├── SSRWrapper
│ │ │ │ └── SSRWrapper.svelte
│ │ │ ├── DropdownIcon
│ │ │ │ └── DropdownIcon.svelte
│ │ │ ├── Tappable
│ │ │ │ └── Wave.svelte
│ │ │ └── AppearanceProvider
│ │ │ │ └── AppearanceProvider.svelte
│ │ ├── Modals
│ │ │ └── ModalDismissButton
│ │ │ │ ├── README.md
│ │ │ │ └── ModalDismissButton.svelte
│ │ ├── Forms
│ │ │ ├── FormLayout
│ │ │ │ ├── README.md
│ │ │ │ └── FormLayout.svelte
│ │ │ ├── Checkbox
│ │ │ │ ├── README.md
│ │ │ │ └── CheckboxContent.svelte
│ │ │ ├── NativeSelect
│ │ │ │ └── README.md
│ │ │ ├── VisuallyHiddenInput
│ │ │ │ └── VisuallyHiddenInput.svelte
│ │ │ ├── FormStatus
│ │ │ │ ├── README.md
│ │ │ │ └── FormStatus.svelte
│ │ │ ├── Textarea
│ │ │ │ └── README.md
│ │ │ ├── SelectMimicry
│ │ │ │ └── README.md
│ │ │ ├── File
│ │ │ │ ├── README.md
│ │ │ │ └── File.svelte
│ │ │ ├── FormField
│ │ │ │ └── README.md
│ │ │ ├── FormLayoutGroup
│ │ │ │ └── README.md
│ │ │ ├── Select
│ │ │ │ └── Select.css
│ │ │ ├── Input
│ │ │ │ └── README.md
│ │ │ ├── CustomSelectOption
│ │ │ │ └── README.md
│ │ │ └── FormItem
│ │ │ │ └── README.md
│ │ ├── Popouts
│ │ │ ├── Tooltip
│ │ │ │ └── TooltipContainer.svelte
│ │ │ ├── PopoutWrapper
│ │ │ │ └── README.md
│ │ │ ├── Alert
│ │ │ │ ├── AlertHeader.svelte
│ │ │ │ ├── AlertText.svelte
│ │ │ │ └── AlertAction.svelte
│ │ │ └── ScreenSpinner
│ │ │ │ ├── README.md
│ │ │ │ └── ScreenSpinner.svelte
│ │ ├── Typography
│ │ │ ├── Text
│ │ │ │ ├── README.md
│ │ │ │ └── Text.svelte
│ │ │ ├── Subhead
│ │ │ │ ├── README.md
│ │ │ │ └── Subhead.svelte
│ │ │ ├── Headline
│ │ │ │ ├── README.md
│ │ │ │ └── Headline.svelte
│ │ │ ├── Title
│ │ │ │ └── README.md
│ │ │ └── Caption
│ │ │ │ └── README.md
│ │ └── Advertisement
│ │ │ └── PromoBanner
│ │ │ └── README.md
│ ├── fonts
│ │ ├── VK_Sans_Display_Medium.woff
│ │ ├── VK_Sans_Display_Medium.woff2
│ │ └── fonts.css
│ ├── lib
│ │ ├── utils.ts
│ │ ├── testing.ts
│ │ ├── getClassName.ts
│ │ ├── offset.ts
│ │ ├── portal.ts
│ │ ├── platform.ts
│ │ ├── ssr.ts
│ │ ├── config.ts
│ │ ├── classNames.ts
│ │ ├── dom.ts
│ │ ├── supportEvents.ts
│ │ ├── accessibility.ts
│ │ ├── browser.ts
│ │ └── touch.ts
│ ├── styles
│ │ ├── animations.css
│ │ ├── themes.ts
│ │ ├── common.css
│ │ ├── themes.css
│ │ └── constants.css
│ ├── helpers
│ │ ├── avatar.ts
│ │ ├── getScheme.ts
│ │ ├── math.ts
│ │ └── scheme.ts
│ ├── hooks
│ │ ├── useAppearance.ts
│ │ ├── usePlatform.ts
│ │ ├── useBrowserInfo.ts
│ │ ├── useAdaptivity.ts
│ │ ├── useWaitTransitionFinish.ts
│ │ ├── useFocusVisible.ts
│ │ ├── useGlobalEventListener.ts
│ │ └── useKeyboardInputTracker.ts
│ └── types.ts
├── routes
│ ├── structure.md
│ ├── icons.md
│ ├── fonts.md
│ ├── components
│ │ ├── Blocks
│ │ │ ├── Div.svelte
│ │ │ ├── Card.svelte
│ │ │ ├── Cell.svelte
│ │ │ ├── Link.svelte
│ │ │ ├── List.svelte
│ │ │ ├── Badge.svelte
│ │ │ ├── Group.svelte
│ │ │ ├── Avatar.svelte
│ │ │ ├── Banner.svelte
│ │ │ ├── Button.svelte
│ │ │ ├── Footer.svelte
│ │ │ ├── Header.svelte
│ │ │ ├── Search.svelte
│ │ │ ├── Switch.svelte
│ │ │ ├── CardGrid.svelte
│ │ │ ├── Counter.svelte
│ │ │ ├── Gradient.svelte
│ │ │ ├── InfoRow.svelte
│ │ │ ├── Progress.svelte
│ │ │ ├── RichCell.svelte
│ │ │ ├── Spacing.svelte
│ │ │ ├── Spinner.svelte
│ │ │ ├── WriteBar.svelte
│ │ │ ├── Separator.svelte
│ │ │ ├── CellButton.svelte
│ │ │ ├── GridAvatar.svelte
│ │ │ ├── IconButton.svelte
│ │ │ ├── Pagination.svelte
│ │ │ ├── SimpleCell.svelte
│ │ │ ├── UsersStack.svelte
│ │ │ ├── ButtonGroup.svelte
│ │ │ ├── Placeholder.svelte
│ │ │ ├── MiniInfoCell.svelte
│ │ │ ├── ModalCardBase.svelte
│ │ │ ├── PanelSpinner.svelte
│ │ │ ├── WriteBarIcon.svelte
│ │ │ └── InitialsAvatar.svelte
│ │ ├── Forms
│ │ │ ├── File.svelte
│ │ │ ├── Input.svelte
│ │ │ ├── Checkbox.svelte
│ │ │ ├── FormItem.svelte
│ │ │ ├── Textarea.svelte
│ │ │ ├── FormField.svelte
│ │ │ ├── FormLayout.svelte
│ │ │ ├── FormStatus.svelte
│ │ │ ├── NativeSelect.svelte
│ │ │ ├── SelectMimicry.svelte
│ │ │ ├── FormLayoutGroup.svelte
│ │ │ ├── SegmentedControl.svelte
│ │ │ └── CustomSelectOption.svelte
│ │ ├── Layout
│ │ │ ├── Panel.svelte
│ │ │ ├── Tabbar.svelte
│ │ │ ├── SplitCol.svelte
│ │ │ ├── TabbarItem.svelte
│ │ │ ├── FixedLayout.svelte
│ │ │ ├── PanelHeader.svelte
│ │ │ ├── SplitLayout.svelte
│ │ │ ├── PanelHeaderBack.svelte
│ │ │ ├── PanelHeaderEdit.svelte
│ │ │ ├── PanelHeaderClose.svelte
│ │ │ ├── PanelHeaderButton.svelte
│ │ │ └── PanelHeaderSubmit.svelte
│ │ ├── Popouts
│ │ │ ├── Alert.svelte
│ │ │ ├── Snackbar.svelte
│ │ │ ├── PopoutWrapper.svelte
│ │ │ └── ScreenSpinner.svelte
│ │ ├── Service
│ │ │ ├── Touch.svelte
│ │ │ ├── ConfigProvider.svelte
│ │ │ └── AdaptivityProvider.svelte
│ │ ├── Typography
│ │ │ ├── Text.svelte
│ │ │ ├── Title.svelte
│ │ │ ├── Caption.svelte
│ │ │ ├── Subhead.svelte
│ │ │ └── Headline.svelte
│ │ ├── Advertisement
│ │ │ └── PromoBanner.svelte
│ │ └── Modals
│ │ │ └── ModalDismissButton.svelte
│ ├── utils.md
│ ├── ssr.md
│ ├── design.md
│ └── modes.md
├── site
│ └── lib
│ │ ├── index.ts
│ │ ├── Sidebar
│ │ ├── types.ts
│ │ ├── Components.svelte
│ │ ├── Sidebar.svelte
│ │ └── Group.svelte
│ │ └── Icon28TokenizedOutline
│ │ └── Icon28TokenizedOutline.svelte
├── global.d.ts
└── app.html
├── .husky
└── pre-commit
├── .markdownlint.yml
├── .prettierrc
├── .gitignore
├── .eslintrc.cjs
├── tasks
└── generate_scheme.cjs
├── tsconfig.json
├── .github
└── workflows
│ └── publish.yml
├── LICENSE
├── README.md
├── svelte.config.js
└── remark-example.js
/static/.nojekyll:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
2 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/IconButton/README.md:
--------------------------------------------------------------------------------
1 | # IconButton
2 |
--------------------------------------------------------------------------------
/src/routes/structure.md:
--------------------------------------------------------------------------------
1 | # Структура экранов
2 |
3 | TODO: написать
4 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | yarn lint
5 |
--------------------------------------------------------------------------------
/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sveltevk/VKSUI/HEAD/static/favicon.png
--------------------------------------------------------------------------------
/src/site/lib/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Showcase } from './Showcase/Showcase.svelte';
2 |
--------------------------------------------------------------------------------
/static/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/Panel/README.md:
--------------------------------------------------------------------------------
1 | # Panel
2 |
3 | `Panel` – это контейнер для контента.
4 |
--------------------------------------------------------------------------------
/.markdownlint.yml:
--------------------------------------------------------------------------------
1 | ---
2 | no-hard-tabs: false
3 | line_length: false
4 | no-emphasis-as-heading: false
5 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": true,
3 | "singleQuote": true,
4 | "trailingComma": "none",
5 | "printWidth": 100
6 | }
7 |
--------------------------------------------------------------------------------
/src/lib/fonts/VK_Sans_Display_Medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sveltevk/VKSUI/HEAD/src/lib/fonts/VK_Sans_Display_Medium.woff
--------------------------------------------------------------------------------
/src/lib/components/Layout/SplitCol/README.md:
--------------------------------------------------------------------------------
1 | # SplitCol
2 |
3 | Компонент-обертка для отрисовки колонки в многоколоночном интерфейсе.
4 |
--------------------------------------------------------------------------------
/src/lib/fonts/VK_Sans_Display_Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sveltevk/VKSUI/HEAD/src/lib/fonts/VK_Sans_Display_Medium.woff2
--------------------------------------------------------------------------------
/src/lib/lib/utils.ts:
--------------------------------------------------------------------------------
1 | export const generateRandomId = () => {
2 | return Math.random()
3 | .toString(36)
4 | .replace(/[^a-z]+/g, '');
5 | };
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 | .vercel
10 | .output
11 |
12 | *.log
13 |
--------------------------------------------------------------------------------
/src/global.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | declare const __version__: string;
4 | declare module '*.md';
5 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/SplitLayout/README.md:
--------------------------------------------------------------------------------
1 | # SplitLayout
2 |
3 | Компонент-контейнер для реализации интерфейса с многоколоночной структурой. Тесно связан со [SplitCol](SplitCol).
4 |
--------------------------------------------------------------------------------
/src/lib/components/Service/ConfigProvider/README.md:
--------------------------------------------------------------------------------
1 | # ConfigProvider
2 |
3 | Компонент для пробрасывания конфигурации приложению. Помимо прочего, отвечает за установку темы и платформы.
4 |
--------------------------------------------------------------------------------
/src/site/lib/Sidebar/types.ts:
--------------------------------------------------------------------------------
1 | export interface Tree {
2 | header: string;
3 | child: {
4 | name: string;
5 | link: string;
6 | tokenized?: true;
7 | }[];
8 | tree?: Tree[];
9 | }
10 |
--------------------------------------------------------------------------------
/src/lib/lib/testing.ts:
--------------------------------------------------------------------------------
1 | import { canUseDOM } from '@vkontakte/vkjs';
2 |
3 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
4 | export const isTesting = Boolean(canUseDOM && (window as any).__isVkuiTesting);
5 |
--------------------------------------------------------------------------------
/src/lib/lib/getClassName.ts:
--------------------------------------------------------------------------------
1 | import { Platform, platform } from '../lib/platform';
2 |
3 | export default function getClassName(base: string, osName: Platform = platform()): string {
4 | return `${base} ${base}--${osName}`;
5 | }
6 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Progress/README.md:
--------------------------------------------------------------------------------
1 | # Progress
2 |
3 | ```svelte scroll
4 |
7 |
8 |
11 | ```
12 |
--------------------------------------------------------------------------------
/src/lib/fonts/fonts.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'VK Sans Display';
3 | src: url('./VK_Sans_Display_Medium.woff2') format('woff2'),
4 | url('./VK_Sans_Display_Medium.woff') format('woff');
5 | font-weight: 500;
6 | font-display: fallback;
7 | }
8 |
--------------------------------------------------------------------------------
/src/routes/icons.md:
--------------------------------------------------------------------------------
1 | # Иконки
2 |
3 | Иконки хранятся отдельно в пакете `@sveltevk/icons`. У пакета есть отдельная
4 | [документация с полным списком иконок](https://sveltevk.github.io/icons). Сама
5 | библиотека использует иконки в качестве зависимости для различных компонентов.
6 |
--------------------------------------------------------------------------------
/src/lib/components/Modals/ModalDismissButton/README.md:
--------------------------------------------------------------------------------
1 | # ModalDismissButton
2 |
3 | Кнопка для закрытия модальных окон на широком экране. Для правильной отрисовки нужно расположить в контейнере с `position: "relative"` и отображать при достаточной ширине экрана (от `ViewWidth.SMALL_TABLET`)
4 |
--------------------------------------------------------------------------------
/src/routes/fonts.md:
--------------------------------------------------------------------------------
1 | # VK Sans Display
2 |
3 | Этот шрифт используется в PanelHeader, PanelHeaderContent и ModalPageHeader.
4 |
5 | В библиотеке есть отдельный css-энтрипойнт для подключения шрифта на страницу.
6 |
7 | ```js
8 | import '@vkontakte/vkui/fonts/fonts.css';
9 | ```
10 |
--------------------------------------------------------------------------------
/src/lib/styles/animations.css:
--------------------------------------------------------------------------------
1 | @keyframes vkui-rotator {
2 | 0% {
3 | transform: rotate(0deg);
4 | }
5 |
6 | 100% {
7 | transform: rotate(360deg);
8 | }
9 | }
10 |
11 | @keyframes vkui-popper-fadein {
12 | from {
13 | opacity: 0;
14 | }
15 |
16 | to {
17 | opacity: 1;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeader/README.md:
--------------------------------------------------------------------------------
1 | # PanelHeader
2 |
3 | Практически всегда содержимое панели должно начинаться с `Separator`, поэтому он рисуется в `PanelHeader` по-умолчанию.
4 |
5 | > **Важно**
6 | >
7 | > Правая часть шапки будет скрыта, если в `ConfigProvider` передан `webviewType={WebviewType.VKAPPS}`.
8 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Div.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Card.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Cell.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Link.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/List.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/File.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/Input.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Badge.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Group.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/Panel.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Link/README.md:
--------------------------------------------------------------------------------
1 | # Link
2 |
3 | Надстройка над ` `. Компонент принимает все валидные для этого элемента свойства.
4 |
5 | ```svelte
6 |
9 |
10 | Google
11 | Profile
12 | ```
13 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/Tabbar/README.md:
--------------------------------------------------------------------------------
1 | # Tabbar
2 |
3 | Компонент для навигации внутри Epic.
4 |
5 | > **Важно**
6 | >
7 | > `Tabbar` располагается фиксированно. Если внутри панели вы используете `FixedLayout`, например располагаете внизу панели `Tabs`, то у `Tabbar` нужно указать `shadow={false}`, чтобы его тень не наeзжала на "прижатый" книзу контент панели.
8 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Avatar.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Banner.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Button.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Footer.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Header.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Search.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Switch.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/Tabbar.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Popouts/Alert.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Service/Touch.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/CardGrid.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Counter.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Gradient.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/InfoRow.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Progress.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/RichCell.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Spacing.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Spinner.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/WriteBar.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/Checkbox.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/FormItem.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/Textarea.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/SplitCol.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Typography/Text.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Typography/Title.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/FormLayout/README.md:
--------------------------------------------------------------------------------
1 | # FormLayout
2 |
3 | Компонент для создания form. Содержит скрытый ` `, обеспечивающий отправку формы по enter.
4 |
5 | Чтобы избежать перезагрузки страницы, необходимо вызвать `e.preventDefault()`
6 |
7 | ```svelte
8 | e.preventDefault()}>...
9 | ```
10 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Separator.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/FormField.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/FormLayout.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/FormStatus.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Popouts/Snackbar.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/CellButton.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/GridAvatar.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/IconButton.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Pagination.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/SimpleCell.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/UsersStack.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/TabbarItem.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Typography/Caption.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Typography/Subhead.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/ButtonGroup.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/Placeholder.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/NativeSelect.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/FixedLayout.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/PanelHeader.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/SplitLayout.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Typography/Headline.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/components/Service/AdaptivityProvider/README.md:
--------------------------------------------------------------------------------
1 | # AdaptivityProvider
2 |
3 | Компонент, прокидывающий вниз данные об адаптивности. Все параметры, которые можно прокинуть через props, компонент по умолчанию вычисляет самостоятельно. Передавать их с помощью props стоит в тех случаях, когда вы точно уверены, что ваш сайт, например, будет открываться только на мобильных устройствах.
4 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/MiniInfoCell.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/ModalCardBase.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/PanelSpinner.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/WriteBarIcon.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/SelectMimicry.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Blocks/InitialsAvatar.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/FormLayoutGroup.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Popouts/PopoutWrapper.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Popouts/ScreenSpinner.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/WriteBarIcon/README.md:
--------------------------------------------------------------------------------
1 | Компонент для отрисовки кнопок-иконок в [`WriteBar`](WriteBar).
2 |
3 | Надстройка над ` `. Компонент принимает все валидные для этого элемента свойства.
4 |
5 | ```svelte
6 |
7 |
8 |
9 |
10 |
11 | ```
12 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/SegmentedControl.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/PanelHeaderBack.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/PanelHeaderEdit.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Service/ConfigProvider.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Advertisement/PromoBanner.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/PanelHeaderClose.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Forms/CustomSelectOption.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/PanelHeaderButton.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Layout/PanelHeaderSubmit.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Modals/ModalDismissButton.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/components/Service/AdaptivityProvider.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/helpers/avatar.ts:
--------------------------------------------------------------------------------
1 | import type { InitialsAvatarNumberGradients } from '@sveltevk/vksui/components/Blocks/InitialsAvatar/InitialsAvatar.svelte';
2 |
3 | /**
4 | * Вычисляет цвет InitialsAvatar на основании переданного идентификатора объекта
5 | */
6 | export function calcInitialsAvatarColor(objectId: number): InitialsAvatarNumberGradients {
7 | return ((objectId % 6) + 1) as InitialsAvatarNumberGradients;
8 | }
9 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Banner/BannerSubheader.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 | {#if size === 'm'}
9 |
10 | {:else}
11 |
12 | {/if}
13 |
--------------------------------------------------------------------------------
/src/lib/lib/offset.ts:
--------------------------------------------------------------------------------
1 | export interface OffsetRectInterface {
2 | top: number;
3 | left: number;
4 | width: number;
5 | height: number;
6 | }
7 |
8 | export function getOffsetRect(elem: HTMLElement): OffsetRectInterface {
9 | const box = elem.getBoundingClientRect();
10 |
11 | return {
12 | top: box.top,
13 | left: box.left,
14 | width: elem.offsetWidth,
15 | height: elem.offsetHeight
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/src/routes/utils.md:
--------------------------------------------------------------------------------
1 | # Utils
2 |
3 | ## usePlatform
4 |
5 | Компоненты библиотеки имеют разный внешний вид в зависимости от платформы – iOS или Android. Вам может понадобиться определить платформу в коде приложения. Для этого используйте `usePlatform`
6 |
7 | ## calcInitialsAvatarColor
8 |
9 | Используется для определения цвета [`InitialsAvatar`](components/Blocks/InitialsAvatar) по переданному идентификатору объекта.
10 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Banner/BannerHeader.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 | {#if size === 'm'}
9 |
10 | {:else}
11 |
12 | {/if}
13 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Div/README.md:
--------------------------------------------------------------------------------
1 | # Div
2 |
3 | Компонент с установленными паддингами, которые отличаются в зависимости от платформы. Необходим, когда есть какой-то кастомный блок, у которого должны быть стандартные отступы.
4 |
5 | ## Пример
6 |
7 | ```svelte scroll
8 |
11 |
12 |
13 | Edit Info
14 |
15 | ```
16 |
--------------------------------------------------------------------------------
/src/lib/components/Service/ConfigProvider/DOMContext.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Header/HeaderSubtitle.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 | {#if mode === 'secondary'}
9 |
10 | {:else}
11 |
12 | {/if}
13 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/PanelSpinner/PanelSpinner.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/Checkbox/README.md:
--------------------------------------------------------------------------------
1 | # Checkbox
2 |
3 | ```svelte scroll
4 |
7 |
8 |
9 |
10 | Я участвую в сборе
11 | Закрепить сообщение
12 | Автоматически зачислять на карту
13 |
14 |
15 | ```
16 |
--------------------------------------------------------------------------------
/src/routes/ssr.md:
--------------------------------------------------------------------------------
1 | # Серверный рендеринг
2 |
3 | Библиотека полностью поддерживает SSR и [Svelte Kit](https://kit.svelte.dev/). Для корректного рендеринга компонентов на сервере, достаточно обернуть ваше приложение в `SSRWrapper`, передав туда значение заголовка `userAgent`. Это нужно для определения платформы пользователя (iOS или Android) на стороне сервера.
4 |
5 | ```svelte
6 |
7 | Hello
8 |
9 | ```
10 |
--------------------------------------------------------------------------------
/src/lib/hooks/useAppearance.ts:
--------------------------------------------------------------------------------
1 | import { getContext } from 'svelte';
2 | import { writable } from 'svelte/store';
3 | import type { Writable } from 'svelte/store';
4 | import { ContextKey } from '../lib/config';
5 | import type { AppearanceType } from '@vkontakte/vk-bridge';
6 |
7 | export function useAppearance(): Writable {
8 | const wAppearance = getContext(ContextKey.appearance) as Writable;
9 |
10 | return wAppearance || writable('light');
11 | }
12 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/PanelSpinner/README.md:
--------------------------------------------------------------------------------
1 | # PanelSpinner
2 |
3 | Этот компонент - обёртка над ` ` с заданными отступами и размером. Удобно использовать его во время загрузки данных.
4 |
5 | ```svelte
6 | {#await promise}
7 |
8 | {:then value}
9 |
10 |
11 | ...
12 |
13 | {:catch error}
14 |
15 |
16 | ...
17 |
18 | {/await}
19 | ```
20 |
--------------------------------------------------------------------------------
/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 | %sveltekit.head%
12 |
13 |
14 |
15 | %sveltekit.body%
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/lib/components/Popouts/Tooltip/TooltipContainer.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Header/HeaderAside.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 | {#if platform === Platform.IOS}
10 |
11 | {:else}
12 |
13 | {/if}
14 |
--------------------------------------------------------------------------------
/src/lib/hooks/usePlatform.ts:
--------------------------------------------------------------------------------
1 | import { getContext } from 'svelte';
2 | import { writable } from 'svelte/store';
3 | import type { Writable } from 'svelte/store';
4 | import { platform } from '../lib/platform';
5 | import type { PlatformType } from '../lib/platform';
6 | import { ContextKey } from '../lib/config';
7 |
8 | export function usePlatform(): Writable {
9 | const wPlatform = getContext(ContextKey.platform) as Writable;
10 |
11 | return wPlatform || writable(platform());
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/types.ts:
--------------------------------------------------------------------------------
1 | import type { PlatformType } from './lib/platform';
2 | import type { Insets } from '@vkontakte/vk-bridge';
3 |
4 | export type AlignType = 'left' | 'center' | 'right';
5 |
6 | export interface HasPlatform {
7 | /**
8 | * @ignore
9 | */
10 | platform?: PlatformType;
11 | }
12 |
13 | export interface HasInsets {
14 | /**
15 | * @ignore
16 | */
17 | insets?: Partial;
18 | }
19 |
20 | export interface Version {
21 | major: number;
22 | minor?: number;
23 | patch?: number;
24 | }
25 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/NativeSelect/README.md:
--------------------------------------------------------------------------------
1 | # NativeSelect
2 |
3 | ```svelte frame
4 |
7 |
8 |
9 | NativeSelect
10 |
11 |
12 |
13 | Мужской
14 | Женский
15 |
16 |
17 |
18 |
19 | ```
20 |
--------------------------------------------------------------------------------
/src/lib/components/Service/SSRWrapper/SSRWrapper.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/lib/lib/portal.ts:
--------------------------------------------------------------------------------
1 | export function portal(el: HTMLElement, target: HTMLElement | null) {
2 | let targetEl: HTMLElement;
3 | async function update(newTarget: HTMLElement | null) {
4 | if (newTarget === null) {
5 | return;
6 | }
7 |
8 | targetEl = newTarget;
9 | targetEl.appendChild(el);
10 | el.hidden = false;
11 | }
12 |
13 | function destroy() {
14 | if (el.parentNode) {
15 | el.parentNode.removeChild(el);
16 | }
17 | }
18 |
19 | update(target);
20 | return {
21 | update,
22 | destroy
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeaderBack/README.md:
--------------------------------------------------------------------------------
1 | # PanelHeaderBack
2 |
3 | Этот компонент используется для показа кнопки назад в панелях в рамках одного `View`. Внутри инкапсулирована логика показа нужной иконки для платформы.
4 |
5 | ```svelte frame mini
6 |
11 |
12 |
13 |
14 | Заголовок панели
15 |
16 | ```
17 |
--------------------------------------------------------------------------------
/src/lib/components/Typography/Text/README.md:
--------------------------------------------------------------------------------
1 | # Text
2 |
3 | Упрощения в Android-версии (происходят автоматически):
4 |
5 | - `semibold` превращается в `medium`
6 |
7 | ## Пример реализации
8 |
9 | ```svelte mini
10 |
13 |
14 |
15 | Text regular
16 | Text medium
17 | Text semibold
18 |
19 | ```
20 |
--------------------------------------------------------------------------------
/src/lib/components/Popouts/PopoutWrapper/README.md:
--------------------------------------------------------------------------------
1 | # PopoutWrapper
2 |
3 | Компонент-обертка для отрисовки всплывающих окон с затемнением фона. Используется внутри `Alert`, `ActionSheet` и `ScreenSpinner`. Свойства `alignY` и `alignX` служат для удобного позиционирования контента. Пример:
4 |
5 | ```svelte
6 |
9 |
10 | Some content
11 | ```
12 |
13 | Все всплывающие окна передаются в слот `popout` компонентов `View` или `Root`.
14 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Counter/CounterTypography.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 | {#if size === 's'}
11 |
12 | {:else}
13 |
14 | {/if}
15 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeaderEdit/README.md:
--------------------------------------------------------------------------------
1 | # PanelHeaderEdit
2 |
3 | Компонент для отрисовки кнопки Редактировать в шапке. Принимает свойство `isActive`, которое определяет состояние кнопки (включен ли режим редактирования).
4 |
5 | ```svelte frame mini
6 |
11 |
12 |
13 | (isActive = !isActive)} />
14 | Заголовок окна
15 |
16 | ```
17 |
18 | ```
19 |
20 | ```
21 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeaderButton/ButtonTypography.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 | {#if platform === IOS}
11 |
12 |
13 |
14 | {:else}
15 |
16 | {/if}
17 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeaderClose/README.md:
--------------------------------------------------------------------------------
1 | # PanelHeaderClose
2 |
3 | Этот компонент используется для показа кнопки "Отмена" в модальных окнах для закрытия текущего `View` в рамках `Root`. На iOS будет показан текст, передаваемый как `text`, на Android - ` `:
4 |
5 | ```svelte frame mini
6 |
11 |
12 |
13 |
14 | Заголовок модального окна
15 |
16 | ```
17 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Footer/Footer.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
14 |
15 |
25 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeaderSubmit/README.md:
--------------------------------------------------------------------------------
1 | # PanelHeaderSubmit
2 |
3 | Этот компонент используется для показа кнопки "Отмена" в модальных окнах для закрытия текущего `View` в рамках `Root`. На iOS будет показан текст, передаваемый как `text`, на Android - ` `:
4 |
5 | ```svelte frame mini
6 |
11 |
12 |
13 |
14 | Заголовок модального окна
15 |
16 | ```
17 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/FixedLayout/README.md:
--------------------------------------------------------------------------------
1 | # FixedLayout
2 |
3 | `{ position: fixed }` не дружит с `{ transform: translate }` на родителе, поэтому для позиционирования фиксированных блоков внутри панели, необходимо использовать FixedLayout в качестве обертки.
4 |
5 | Для удобства есть свойство `vertical`, с помощью которого можно "прижать" контент к верху или низу. При этому будут учитываться высота шапки и прочие системные отступы.
6 |
7 | **Важно**: блок с `{ position: fixed }` находится не в потоке. В примере можно увидеть, что у блока с основным контентом есть паддинги. Они там не случайны.
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/lib/lib/platform.ts:
--------------------------------------------------------------------------------
1 | import { canUseDOM } from './dom';
2 |
3 | export enum Platform {
4 | ANDROID = 'android',
5 | IOS = 'ios',
6 | VKCOM = 'vkcom'
7 | }
8 |
9 | export const ANDROID: Platform = Platform.ANDROID;
10 | export const IOS: Platform = Platform.IOS;
11 | export const VKCOM: Platform = Platform.VKCOM;
12 |
13 | export type PlatformType = Platform.ANDROID | Platform.IOS | Platform.VKCOM;
14 | // | string;
15 |
16 | export function platform(useragent?: string): PlatformType {
17 | const ua = useragent || (canUseDOM && navigator.userAgent) || '';
18 |
19 | return /iphone|ipad|ipod/i.test(ua) ? IOS : ANDROID;
20 | }
21 |
--------------------------------------------------------------------------------
/src/lib/lib/ssr.ts:
--------------------------------------------------------------------------------
1 | import type { Writable } from 'svelte/store';
2 | import { writable } from 'svelte/store';
3 | import { Platform, platform } from './platform';
4 |
5 | export interface SSRContextInterface {
6 | platform: Writable;
7 | userAgent?: string;
8 | }
9 |
10 | export const SSRContextKey = 'SSRContext';
11 |
12 | export interface SSRBuildContextProps {
13 | userAgent?: string;
14 | }
15 |
16 | export const SSRBuildContext = (props: SSRBuildContextProps): SSRContextInterface => {
17 | const { userAgent } = props;
18 |
19 | const contextValue = {
20 | platform: writable(platform(userAgent)),
21 | userAgent
22 | };
23 |
24 | return contextValue;
25 | };
26 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Footer/README.md:
--------------------------------------------------------------------------------
1 | # Footer
2 |
3 | Подвал для списков.
4 |
5 | ## Пример
6 |
7 | ```svelte scroll
8 |
11 |
12 |
13 |
14 |
15 |
16 | Команда ВКонтакте
17 |
18 |
19 |
20 | Robbie Williams
21 |
22 |
23 |
24 | ПостНаука
25 |
26 |
27 |
28 |
29 | ```
30 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/Checkbox/CheckboxContent.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 | {#if platform === VKCOM || sizeY === SizeType.COMPACT}
12 |
13 | {:else}
14 |
15 | {/if}
16 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeaderClose/PanelHeaderClose.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/lib/hooks/useBrowserInfo.ts:
--------------------------------------------------------------------------------
1 | import { getContext } from 'svelte';
2 | import { SSRContextKey } from '../lib/ssr';
3 | import type { SSRContextInterface } from '../lib/ssr';
4 | import { canUseDOM } from '../lib/dom';
5 | import { computeBrowserInfo } from '../lib/browser';
6 | import type { BrowserInfo } from '../lib/browser';
7 |
8 | export default function useBrowserInfo(): BrowserInfo {
9 | const ssrContext = getContext(SSRContextKey) as SSRContextInterface;
10 |
11 | let userAgent = canUseDOM && navigator.userAgent ? navigator.userAgent : '';
12 | if (ssrContext && ssrContext.platform) {
13 | userAgent = ssrContext.userAgent;
14 | }
15 |
16 | return computeBrowserInfo(userAgent);
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeaderSubmit/PanelHeaderSubmit.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/lib/components/Popouts/Alert/AlertHeader.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 | {#if platform === VKCOM}
10 |
13 | {:else if platform === IOS}
14 |
17 | {:else if platform === ANDROID}
18 |
21 | {/if}
22 |
--------------------------------------------------------------------------------
/src/lib/components/Typography/Subhead/README.md:
--------------------------------------------------------------------------------
1 | # Subhead
2 |
3 | Семейство заголовков.
4 |
5 | ## Пример реализации
6 |
7 | ```svelte mini
8 |
11 |
12 |
13 | Subhead
14 |
15 | ```
16 |
17 | ## Кастомизация
18 |
19 | Есть возможность переопределить жирность.
20 |
21 | ## Пример реализации
22 |
23 | ```svelte mini
24 |
25 | Subhead 3 weight 1
26 | Subhead 3 weight 2
27 | Subhead 3 weight 3
28 |
29 | ```
30 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: '@typescript-eslint/parser',
4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
5 | plugins: ['svelte3', '@typescript-eslint'],
6 | ignorePatterns: ['*.cjs'],
7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
8 | settings: {
9 | 'svelte3/typescript': () => require('typescript')
10 | },
11 | parserOptions: {
12 | sourceType: 'module',
13 | ecmaVersion: 2020
14 | },
15 | rules: {
16 | '@typescript-eslint/ban-ts-comment': 'off',
17 | '@typescript-eslint/no-non-null-assertion': 'off'
18 | },
19 | env: {
20 | browser: true,
21 | es2017: true,
22 | node: true
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/VisuallyHiddenInput/VisuallyHiddenInput.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
11 |
12 |
21 |
22 |
33 |
--------------------------------------------------------------------------------
/src/lib/components/Popouts/Alert/AlertText.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 | {#if platform === VKCOM}
10 |
11 |
12 |
13 | {:else if platform === IOS}
14 |
15 |
16 |
17 | {:else if platform === ANDROID}
18 |
19 |
20 |
21 | {/if}
22 |
--------------------------------------------------------------------------------
/src/lib/components/Typography/Headline/README.md:
--------------------------------------------------------------------------------
1 | # Headline
2 |
3 | ```svelte mini
4 |
7 |
8 |
9 | Headline 1
10 | Headline 2
11 |
12 | ```
13 |
14 | ## Кастомизация
15 |
16 | Есть возможность переопределить жирность.
17 |
18 | ```svelte mini
19 |
20 | Headline 2 weight 1
21 | Headline 2 weight 2
22 | Headline 2 weight 3
23 |
24 | ```
25 |
--------------------------------------------------------------------------------
/src/lib/lib/config.ts:
--------------------------------------------------------------------------------
1 | export enum ContextKey {
2 | isWebView = 'vkui_isWebView',
3 | webviewType = 'vkui_webviewType',
4 | scheme = 'vkui_scheme',
5 | appearance = 'vkui_appearance',
6 | classAppearance = 'vkui_classAppearance',
7 | app = 'vkui_app',
8 | transitionMotionEnabled = 'vkui_transitionMotionEnabled',
9 | platform = 'vkui_platform',
10 | hasNewTokens = 'vkui_hasNewTokens'
11 | }
12 |
13 | export enum Appearance {
14 | DARK = 'dark',
15 | LIGHT = 'light'
16 | }
17 |
18 | export enum Scheme {
19 | BRIGHT_LIGHT = 'bright_light',
20 | SPACE_GRAY = 'space_gray',
21 | VKCOM_LIGHT = 'vkcom_light',
22 | VKCOM_DARK = 'vkcom_dark'
23 | }
24 |
25 | export enum WebviewType {
26 | VKAPPS = 'vkapps',
27 | INTERNAL = 'internal'
28 | }
29 |
--------------------------------------------------------------------------------
/tasks/generate_scheme.cjs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | const path = require('path');
3 | const schemeVKUI = require('@vkontakte/appearance/main.valette/scheme');
4 | const paletteVKUI = require('@vkontakte/appearance/main.valette/palette');
5 | const schemeWeb = require('@vkontakte/appearance/main.valette/scheme_web');
6 | const paletteWeb = require('@vkontakte/appearance/main.valette/palette_web');
7 | const pkg = require('../package.json');
8 | const generateScheme = require('@vkontakte/vkjs/build/tasks/generate_scheme');
9 |
10 | const stylesDir = path.resolve(__dirname, '../src/lib/styles');
11 |
12 | generateScheme(schemeVKUI, paletteVKUI, pkg.defaultSchemeId, stylesDir);
13 | generateScheme(schemeWeb, paletteWeb, pkg.defaultSchemeId, stylesDir);
14 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Spinner/README.md:
--------------------------------------------------------------------------------
1 | # Spinner
2 |
3 | Используется для визуализации выполнения асинхронного процесса (например ajax запроса). Если нужно на момент загрузки заблокировать интерфейс, то можно использовать надстройку над Spinner – ScreenSpinner.
4 |
5 | ```svelte mini
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
24 | ```
25 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/FormStatus/README.md:
--------------------------------------------------------------------------------
1 | # FormStatus
2 |
3 | Компонент используется для отображения статуса формы. Например, когда в форме допущена ошибка, и нет возможности указать на конкретное поле. Заголовок и текст опциональны.
4 |
5 | ```svelte scroll
6 |
9 |
10 |
11 |
12 |
13 | Необходимо корректно ввести номер в международном формате
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | ```
24 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/Textarea/README.md:
--------------------------------------------------------------------------------
1 | # Textarea
2 |
3 | Надстройка над ``. Компонент принимает все валидные для этого элемента свойства.
4 |
5 | ## Пример
6 |
7 | ```svelte scroll
8 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ```
26 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Search/SearchPlaceholderTypography.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 | {#if platform === IOS}
11 |
12 |
13 |
14 | {:else if platform === VKCOM}
15 |
16 |
17 |
18 | {:else}
19 |
20 |
21 |
22 |
23 | {/if}
24 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Switch/README.md:
--------------------------------------------------------------------------------
1 | # Switch
2 |
3 | Надстройка над ` `. Компонент принимает все валидные для этого элемента свойства.
4 |
5 | ## Пример
6 |
7 | ```svelte scroll
8 |
11 |
12 |
13 |
14 |
15 | Комментарии к записям
16 |
17 |
18 |
19 | Ссылки
20 |
21 |
22 |
23 | Фотоальбомы
24 |
25 |
26 | ```
27 |
--------------------------------------------------------------------------------
/src/lib/hooks/useAdaptivity.ts:
--------------------------------------------------------------------------------
1 | import { getContext } from 'svelte';
2 | import { writable } from 'svelte/store';
3 | import type { Writable } from 'svelte/store';
4 | import { hasHover, hasMouse } from '@vkontakte/vkjs';
5 | import { SizeType, AdaptivityContextKey } from '../lib/adaptivity';
6 | import type { AdaptivityContextInterface } from '../lib/adaptivity';
7 |
8 | export function useAdaptivity(): Writable {
9 | const adaptivityContext = getContext(
10 | AdaptivityContextKey
11 | ) as Writable;
12 |
13 | return (
14 | adaptivityContext ||
15 | writable({
16 | sizeX: SizeType.COMPACT,
17 | sizeY: SizeType.REGULAR,
18 | hasMouse: hasMouse,
19 | deviceHasHover: hasHover
20 | })
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Div/Div.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
14 |
15 |
16 |
17 |
18 |
19 |
28 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/SelectMimicry/README.md:
--------------------------------------------------------------------------------
1 | # SelectMimicry
2 |
3 | Визуальная имитация компонента NativeSelect. У него нет свойства value, а children вместо массива options принимает любой ReactNode, отображая его без изменений. Используется внутри CustomSelect
4 |
5 | ```svelte frame
6 |
9 |
10 |
11 | Профиль
12 |
13 |
14 | console.log('SelectMimicry')} />
15 |
16 |
17 |
18 |
19 |
20 |
21 | ```
22 |
--------------------------------------------------------------------------------
/src/lib/lib/classNames.ts:
--------------------------------------------------------------------------------
1 | export interface ObjectClassNames {
2 | [index: string]: boolean | undefined | null;
3 | }
4 |
5 | export type ClassName = number | string | ObjectClassNames | false | null | undefined;
6 |
7 | export default function classNames(...classnames: ClassName[]) {
8 | const result: string[] = [];
9 |
10 | classnames.forEach((item: ClassName): void => {
11 | if (!item) {
12 | return;
13 | }
14 | switch (typeof item) {
15 | case 'string':
16 | result.push(item);
17 | break;
18 | case 'object':
19 | Object.keys(item).forEach((key: string) => {
20 | if (item[key]) {
21 | result.push(key);
22 | }
23 | });
24 | break;
25 | default:
26 | result.push(`${item}`);
27 | }
28 | });
29 |
30 | return result.join(' ');
31 | }
32 |
--------------------------------------------------------------------------------
/src/lib/styles/themes.ts:
--------------------------------------------------------------------------------
1 | import './bright_light.css';
2 | import './space_gray.css';
3 | import './vkcom_light.css';
4 | import './vkcom_dark.css';
5 | import '@vkontakte/vkui-tokens/themes/vkBase/cssVars/declarations/onlyVariables.css';
6 | import '@vkontakte/vkui-tokens/themes/vkBase/cssVars/declarations/onlyVariablesLocal.css';
7 | import '@vkontakte/vkui-tokens/themes/vkBaseDark/cssVars/declarations/onlyVariablesLocal.css';
8 | import '@vkontakte/vkui-tokens/themes/vkIOS/cssVars/declarations/onlyVariablesLocal.css';
9 | import '@vkontakte/vkui-tokens/themes/vkIOSDark/cssVars/declarations/onlyVariablesLocal.css';
10 | import '@vkontakte/vkui-tokens/themes/vkCom/cssVars/declarations/onlyVariablesLocal.css';
11 | import '@vkontakte/vkui-tokens/themes/vkComDark/cssVars/declarations/onlyVariablesLocal.css';
12 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/List/README.md:
--------------------------------------------------------------------------------
1 | # List
2 |
3 | Контейнер для однородных [Cell](Cell)
4 |
5 | ```svelte scroll
6 |
12 |
13 |
14 |
15 |
16 |
17 | Учетная запись
18 | |
19 |
20 |
21 | Основные
22 | |
23 |
24 |
25 | Приватность
26 | |
27 |
28 |
29 | ```
30 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/HorizontalScroll/HorizontalScroll.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
9 |
10 |
15 |
16 |
33 |
--------------------------------------------------------------------------------
/src/lib/helpers/getScheme.ts:
--------------------------------------------------------------------------------
1 | import type { AppearanceType } from '@vkontakte/vk-bridge';
2 | import { VKCOM } from '../lib/platform';
3 | import type { PlatformType } from '../lib/platform';
4 | import { Scheme } from './scheme';
5 |
6 | export interface GetSchemeProps {
7 | platform?: PlatformType;
8 | appearance: AppearanceType;
9 | }
10 |
11 | export function getScheme({ platform, appearance }: GetSchemeProps): Scheme {
12 | switch (appearance) {
13 | case 'dark':
14 | switch (platform) {
15 | case VKCOM:
16 | return Scheme.VKCOM_DARK;
17 | default:
18 | return Scheme.SPACE_GRAY;
19 | }
20 | case 'light':
21 | default:
22 | switch (platform) {
23 | case VKCOM:
24 | return Scheme.VKCOM_LIGHT;
25 | default:
26 | return Scheme.BRIGHT_LIGHT;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/lib/components/Service/DropdownIcon/DropdownIcon.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 | {#if $adaptivity.sizeY === SizeType.COMPACT}
16 |
17 | {:else}
18 |
19 | {/if}
20 |
21 |
26 |
--------------------------------------------------------------------------------
/src/lib/components/Advertisement/PromoBanner/README.md:
--------------------------------------------------------------------------------
1 | # PromoBanner
2 |
3 | ```svelte scroll
4 |
21 |
22 |
23 | ```
24 |
25 |
28 |
--------------------------------------------------------------------------------
/src/lib/components/Typography/Title/README.md:
--------------------------------------------------------------------------------
1 | # Title
2 |
3 | Семейство заголовков.
4 |
5 | ## Пример реализации
6 |
7 | ```svelte mini
8 |
11 |
12 |
13 |
Title 1
14 | Title 2
15 | Title 3
16 |
17 | ```
18 |
19 | ## Кастомизация
20 |
21 | Есть возможность переопределить жирность.
22 |
23 | ## Пример реализации
24 |
25 | ```svelte mini
26 |
27 |
Title 3 weight 1
28 | Title 3 weight 2
29 | Title 3 weight 3
30 |
31 | ```
32 |
--------------------------------------------------------------------------------
/src/lib/components/Typography/Caption/README.md:
--------------------------------------------------------------------------------
1 | # Caption
2 |
3 | ## Пример реализации
4 |
5 | ```svelte mini
6 |
9 |
10 |
11 |
Caption 1
12 | Caption 2
13 | Caption 3
14 |
15 | ```
16 |
17 | ## Кастомизация
18 |
19 | Есть возможность переопределить жирность.
20 |
21 | ## Пример реализации
22 |
23 | ```svelte mini
24 |
25 |
Caption 1 weight 1
26 | Caption 1 weight 2
27 | Caption 1 weight 3
28 |
29 | ```
30 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Card/README.md:
--------------------------------------------------------------------------------
1 | # Card
2 |
3 | ```svelte scroll
4 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | ```
35 |
--------------------------------------------------------------------------------
/src/lib/lib/dom.ts:
--------------------------------------------------------------------------------
1 | import { canUseDOM } from '@vkontakte/vkjs';
2 | import { getContext } from 'svelte';
3 | import { writable, type Writable } from 'svelte/store';
4 | export { canUseDOM, canUseEventListeners, onDOMLoaded } from '@vkontakte/vkjs';
5 |
6 | export interface DOMContextInterface {
7 | /**
8 | * @ignore
9 | */
10 | window?: Window;
11 | /**
12 | * @ignore
13 | */
14 | document?: Document;
15 | }
16 |
17 | export const DOMContextKey = 'vkui_DOMContext';
18 |
19 | /* eslint-disable no-restricted-globals */
20 | export const getDOM = (): DOMContextInterface => ({
21 | window: canUseDOM ? window : undefined,
22 | document: canUseDOM ? document : undefined
23 | });
24 | /* eslint-enable no-restricted-globals */
25 |
26 | export const useDOM = (): Writable => {
27 | return getContext(DOMContextKey) || writable(getDOM());
28 | };
29 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/SimpleCell/SimpleCellTypography.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 | {#if sizeY === SizeType.COMPACT}
13 |
14 | {:else if platform === ANDROID}
15 |
16 | {:else}
17 |
18 | {/if}
19 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/File/README.md:
--------------------------------------------------------------------------------
1 | # File
2 |
3 | Надстройка над ` `. Компонент принимает все валидные для этого элемента свойства. `File` под капотом использует `Button`. То есть все свойства, применимые к `Button`, применимы и к `File`.
4 |
5 | ## Пример
6 |
7 | ```svelte scroll
8 |
13 |
14 |
15 |
16 |
17 |
18 | Открыть галерею
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | ```
28 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "moduleResolution": "node",
4 | "module": "es2020",
5 | "lib": ["es2020", "DOM"],
6 | "target": "es2020",
7 | "importsNotUsedAsValues": "error",
8 | "preserveValueImports": true,
9 | "isolatedModules": true,
10 | "resolveJsonModule": true,
11 | "sourceMap": true,
12 | "esModuleInterop": true,
13 | "skipLibCheck": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "baseUrl": ".",
16 | "allowJs": true,
17 | "checkJs": true,
18 | "paths": {
19 | "@sveltevk/vksui": ["src/lib"],
20 | "@sveltevk/vksui/*": ["src/lib/*"],
21 | "$lib": ["src/lib"],
22 | "$lib/*": ["src/lib/*"],
23 | "$site": ["src/site"],
24 | "$site/*": ["src/site/*"],
25 | "$site/lib": ["src/site/lib"],
26 | "$site/lib/*": ["src/site/lib/*"]
27 | }
28 | },
29 | "include": ["src/**/*.js", "src/**/*.ts", "src/**/*.svelte"]
30 | }
31 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/AppRoot/AppRootContext.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/SplitCol/SplitColContext.svelte:
--------------------------------------------------------------------------------
1 |
18 |
19 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/FormField/README.md:
--------------------------------------------------------------------------------
1 | # FormField
2 |
3 | Компонент-оболочка для элементов форм (`Input`, `Select`, `Textarea` и другие).
4 |
5 | ```svelte scroll
6 |
9 |
10 |
11 | {
13 | e.preventDefault();
14 | }}
15 | >
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
40 | ```
41 |
--------------------------------------------------------------------------------
/src/lib/hooks/useWaitTransitionFinish.ts:
--------------------------------------------------------------------------------
1 | import { transitionEvent } from '../lib/supportEvents';
2 |
3 | type TransitionEndHandler = (e?: TransitionEvent) => void;
4 |
5 | export const useWaitTransitionFinish = () => {
6 | let timeoutRef: ReturnType | null = null;
7 |
8 | const waitTransitionFinish = (
9 | element: HTMLElement | null,
10 | eventHandler: TransitionEndHandler,
11 | durationFallback: number
12 | ) => {
13 | if (element) {
14 | if (transitionEvent.supported && transitionEvent.name) {
15 | element.removeEventListener(transitionEvent.name, eventHandler);
16 | element.addEventListener(transitionEvent.name, eventHandler);
17 | } else {
18 | if (timeoutRef) {
19 | clearTimeout(timeoutRef);
20 | }
21 | timeoutRef = setTimeout(eventHandler, durationFallback);
22 | }
23 | }
24 | };
25 |
26 | return {
27 | waitTransitionFinish
28 | };
29 | };
30 |
--------------------------------------------------------------------------------
/src/lib/styles/common.css:
--------------------------------------------------------------------------------
1 | .vkui > body {
2 | overflow-x: hidden;
3 | }
4 |
5 | .vkui,
6 | .vkui > body,
7 | .vkui__root {
8 | margin: 0;
9 | padding: 0;
10 | height: 100%;
11 | }
12 |
13 | .vkui,
14 | .vkui > body,
15 | .vkui__root,
16 | .vkui__portal-root {
17 | -webkit-font-smoothing: subpixel-antialiased;
18 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
19 | -webkit-tap-highlight-color: transparent;
20 | -webkit-text-size-adjust: 100%;
21 | font-family: var(--font-common);
22 | color: var(--text_primary);
23 | color-scheme: var(--vkui--colors_scheme);
24 | }
25 |
26 | .vkui__root input,
27 | .vkui__root textarea,
28 | .vkui__root select,
29 | .vkui__root button,
30 | .vkui__portal-root input,
31 | .vkui__portal-root textarea,
32 | .vkui__portal-root select,
33 | .vkui__portal-root button {
34 | font-family: inherit;
35 | }
36 |
37 | .vkui__root *:focus,
38 | .vkui__portal-root *:focus {
39 | outline: none;
40 | }
41 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/GridAvatar/README.md:
--------------------------------------------------------------------------------
1 | # GridAvatar
2 |
3 | Отображение нескольких аватаров в сетке от 1 до 4 элементов.
4 |
5 | ```svelte mini
6 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
26 |
27 |
28 |
36 | ```
37 |
--------------------------------------------------------------------------------
/src/lib/hooks/useFocusVisible.ts:
--------------------------------------------------------------------------------
1 | import { getContext } from 'svelte';
2 | import { get, writable, type Writable } from 'svelte/store';
3 |
4 | type Dispatch = (
5 | type: EventKey,
6 | detail?: {
7 | blur: FocusEvent;
8 | focus: FocusEvent;
9 | }[EventKey]
10 | ) => void;
11 |
12 | export function useFocusVisible(dispatch: Dispatch) {
13 | const focusVisible = writable(false);
14 | // FIXME: useAppRoot()
15 | const appRoot = getContext>('vkui_AppRootContext');
16 |
17 | const onFocus = (e: FocusEvent) => {
18 | console.log('focus', e);
19 | e.stopPropagation();
20 | focusVisible.set(get(appRoot).keyboardInput);
21 | dispatch('focus', e);
22 | };
23 | const onBlur = (e: FocusEvent) => {
24 | console.log('blur', e);
25 | e.stopPropagation();
26 | focusVisible.set(false);
27 | dispatch('blur', e);
28 | };
29 |
30 | return { focusVisible, onFocus, onBlur };
31 | }
32 |
--------------------------------------------------------------------------------
/src/lib/styles/themes.css:
--------------------------------------------------------------------------------
1 | @import './bright_light.css';
2 | @import './space_gray.css';
3 | @import './vkcom_light.css';
4 | @import './vkcom_dark.css';
5 | @import '../../../node_modules/@vkontakte/vkui-tokens/themes/vkBase/cssVars/declarations/onlyVariables.css';
6 | @import '../../../node_modules/@vkontakte/vkui-tokens/themes/vkBase/cssVars/declarations/onlyVariablesLocal.css';
7 | @import '../../../node_modules/@vkontakte/vkui-tokens/themes/vkBaseDark/cssVars/declarations/onlyVariablesLocal.css';
8 | @import '../../../node_modules/@vkontakte/vkui-tokens/themes/vkIOS/cssVars/declarations/onlyVariablesLocal.css';
9 | @import '../../../node_modules/@vkontakte/vkui-tokens/themes/vkIOSDark/cssVars/declarations/onlyVariablesLocal.css';
10 | @import '../../../node_modules/@vkontakte/vkui-tokens/themes/vkCom/cssVars/declarations/onlyVariablesLocal.css';
11 | @import '../../../node_modules/@vkontakte/vkui-tokens/themes/vkComDark/cssVars/declarations/onlyVariablesLocal.css';
12 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 | on:
3 | push:
4 | tags:
5 | - v*
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v2
12 | - uses: actions/setup-node@v2
13 | with:
14 | node-version: '16.x'
15 | registry-url: 'https://registry.npmjs.org'
16 |
17 | - name: Install 🔧
18 | run: yarn
19 |
20 | - name: Lint 👀
21 | run: yarn lint
22 |
23 | - name: Build 🏗️
24 | run: yarn package
25 |
26 | - name: Publish Package 📦
27 | run: yarn publish ./package
28 | env:
29 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
30 |
31 | - name: Build docs 🏗️
32 | run: yarn build
33 |
34 | - name: Publishing docs
35 | uses: JamesIves/github-pages-deploy-action@3.7.1
36 | with:
37 | BRANCH: gh-pages
38 | FOLDER: build
39 | CLEAN: false
40 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/InfoRow/README.md:
--------------------------------------------------------------------------------
1 | # InfoRow
2 |
3 | Информационный блок. Используется для отрисовки некликабельных блоков с неизменяемым контентом (то есть без инпутов, слайдеров и т.п.) Если таких блоков несколько и они объединены по смыслу, то рекомендуется оборачивать список в `Group` с указанием `header`.
4 |
5 | ```svelte scroll
6 |
9 |
10 |
11 |
12 | 3000 р.
13 |
14 |
15 |
16 | Информация о пользователе
17 |
18 | 30 января 1993
19 |
20 |
21 | Ереван
22 |
23 |
24 | Команда ВКонтакте
25 |
26 |
27 | ```
28 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeader/PanelHeaderIn.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
28 |
--------------------------------------------------------------------------------
/src/lib/components/Service/Tappable/Wave.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
46 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/List/List.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
20 |
21 |
25 |
26 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Badge/Badge.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
43 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Link/Link.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
21 |
22 |
23 |
24 |
25 |
26 |
46 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/CardGrid/README.md:
--------------------------------------------------------------------------------
1 | # CardGrid
2 |
3 | Сетка для [Card](Card). Согласно дизайну, высота Card должна масштабироваться относительно её ширины. В примерах это достигается с помощью процентного `padding-bottom`. Пропорции следующие:
4 |
5 | - `size="s"`: высота равна 92% ширины;
6 | - `size="m"`: высота равна 62% ширины;
7 | - `size="l"`: высота равна 30% ширины.
8 |
9 | ```svelte scroll
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | ```
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022-present Daniil Suvorov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/src/lib/components/Forms/FormLayoutGroup/README.md:
--------------------------------------------------------------------------------
1 | # FormLayoutGroup
2 |
3 | Компонент помогает сгруппировать несколько `FormItem` по какому-то признаку, расположив их по вертикали или по горизонтали.
4 |
5 | ```svelte scroll
6 |
11 |
12 |
13 | {
15 | e.preventDefault();
16 | }}
17 | >
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | {#if !showDates}
27 | (showDates = true)}>Указать даты поездки
28 | {:else}
29 | (showDates = false)}>
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | {/if}
38 |
39 |
40 | ```
41 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/InitialsAvatar/README.md:
--------------------------------------------------------------------------------
1 | # InitialsAvatar
2 |
3 | Компонент для отображения текстовых аватаров на фоне градиента (например, когда у пользователя нет установленного изображения). Для лучшего отображения, рекомендуется использовать длину текста **не более 2 символов**.
4 |
5 | ВКонтакте использует формулу `user_id % 6 + 1` (см. функцию [`calcInitialsAvatarColor`](/VKSUI/utils)) для определения градиента пользователя. Например, у пользователя c id 106 будет 5-й (`l-blue`) цвет градиента.
6 |
7 | ```svelte mini
8 |
14 |
15 |
16 | {#each sizes as size}
17 | {@const user = getRandomUser()}
18 |
19 | {user.initials}
20 |
21 | {/each}
22 |
23 |
24 |
32 | ```
33 |
--------------------------------------------------------------------------------
/src/site/lib/Sidebar/Components.svelte:
--------------------------------------------------------------------------------
1 |
37 |
38 |
39 | {#each searchTree as group}
40 |
41 | {:else}
42 |
43 | {/each}
44 |
--------------------------------------------------------------------------------
/src/lib/lib/supportEvents.ts:
--------------------------------------------------------------------------------
1 | import { canUseDOM } from './dom';
2 | import { isTesting } from './testing';
3 |
4 | export type VKUISupportEvents = {
5 | supported: boolean;
6 | name?: string | null;
7 | };
8 |
9 | // WebKitAnimationEvent и WebKitTransitionEvent не существуют в глобальном контексте
10 | declare const WebKitAnimationEvent: AnimationEvent;
11 | declare const WebKitTransitionEvent: TransitionEvent;
12 |
13 | const animationEvent = {
14 | supported: false
15 | };
16 |
17 | const transitionEvent: VKUISupportEvents = {
18 | supported: false,
19 | name: null
20 | };
21 |
22 | if (canUseDOM && !isTesting) {
23 | if (typeof AnimationEvent !== 'undefined') {
24 | animationEvent.supported = true;
25 | } else if (typeof WebKitAnimationEvent !== 'undefined') {
26 | animationEvent.supported = true;
27 | }
28 |
29 | if (typeof TransitionEvent !== 'undefined') {
30 | transitionEvent.supported = true;
31 | transitionEvent.name = 'transitionend';
32 | } else if (typeof WebKitTransitionEvent !== 'undefined') {
33 | transitionEvent.supported = true;
34 | transitionEvent.name = 'webkitTransitionEnd';
35 | }
36 | }
37 |
38 | export { animationEvent, transitionEvent };
39 |
--------------------------------------------------------------------------------
/src/routes/design.md:
--------------------------------------------------------------------------------
1 | # Дизайн
2 |
3 | ## Figma
4 |
5 | На странице [VK в Figma Community](https://www.figma.com/@vk) доступны четыре библиотеки:
6 |
7 | - VKUI Base Library — базовая библиотека, содержащая более 650 иконок и все цветовые токены для светлой и тёмной темы (в виде стилей);
8 | - VKUI iOS Library и VKUI Android Library — библиотеки компонентов для iOS и Android, собранные на токенах из Base Library, а также шаблоны готовых экранов;
9 | - VKUI Color Palette — палитра цветов из приложений ВКонтакте, на которых собраны цветовые токены.
10 |
11 | ## Sketch
12 |
13 | Базовая библиотека, состоящая из иконок, цветов и токенов. Необходима для работы других библиотек:
14 |
15 | - [VKUI Base Library](https://sketch.cloud/s/kjgAr)
16 |
17 | Библиотеки компонентов в виде широко настраиваемых символов. Необходимы для работы UI-китов:
18 |
19 | - [VKUI iOS Library](https://sketch.cloud/s/G4OgL)
20 | - [VKUI Android Library](https://sketch.cloud/s/wa9qp)
21 |
22 | UI-киты, где в наглядном виде собраны примеры использования компонентов вместе с цветовыми токенами для работы с тёмной темой:
23 |
24 | - [iOSUIKit](https://sketch.cloud/s/5zmlw)
25 | - [AndroidUIKit](https://sketch.cloud/s/QMalL)
26 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/Select/Select.css:
--------------------------------------------------------------------------------
1 | .Select {
2 | position: relative;
3 | cursor: pointer;
4 | box-sizing: border-box;
5 | }
6 |
7 | .Select__el {
8 | display: block;
9 | position: absolute;
10 | appearance: none;
11 | border: none;
12 | left: 0;
13 | top: 0;
14 | width: 100%;
15 | height: 100%;
16 | opacity: 0;
17 | z-index: 3;
18 | font-size: 16px;
19 | }
20 |
21 | .Select__container {
22 | flex-grow: 1;
23 | flex-shrink: 1;
24 | padding: 11px;
25 | color: var(--text_primary);
26 | box-sizing: border-box;
27 | position: relative;
28 | z-index: 2;
29 | overflow: hidden;
30 | }
31 |
32 | .Select__title {
33 | display: block;
34 | }
35 |
36 | .Select:not(.Select--multiline) .Select__title {
37 | overflow: hidden;
38 | white-space: nowrap;
39 | text-overflow: ellipsis;
40 | }
41 |
42 | .Select--not-selected .Select__title {
43 | color: var(--field_text_placeholder);
44 | }
45 |
46 | .Select--align-right .Select__title {
47 | text-align: right;
48 | }
49 |
50 | .Select--align-center .Select__title {
51 | text-align: center;
52 | }
53 |
54 | /**
55 | * sizeY === 'compact'
56 | */
57 | .Select--sizeY--compact .Select__container {
58 | padding: 7px 11px;
59 | }
60 |
--------------------------------------------------------------------------------
/src/lib/hooks/useGlobalEventListener.ts:
--------------------------------------------------------------------------------
1 | import { canUseDOM } from '@vkontakte/vkjs';
2 |
3 | export function useGlobalEventListener(
4 | element: Document | HTMLElement | Window | null | undefined,
5 | event: K,
6 | cb: ((ev: GlobalEventHandlersEventMap[K]) => void) | null | false | undefined,
7 | options?: AddEventListenerOptions
8 | ): void;
9 | export function useGlobalEventListener(
10 | element: Document | HTMLElement | Window | null | undefined,
11 | event: string,
12 | cb: ((ev: E) => void) | null | false | undefined,
13 | options?: AddEventListenerOptions
14 | ): void;
15 | export function useGlobalEventListener<
16 | K extends keyof GlobalEventHandlersEventMap,
17 | E extends Event
18 | >(
19 | element: Document | HTMLElement | Window | null | undefined,
20 | event: K | string,
21 | cb: ((ev: E) => void) | null | false | undefined,
22 | _options?: AddEventListenerOptions
23 | ) {
24 | if (!canUseDOM || !element || !cb) {
25 | return;
26 | }
27 |
28 | const options = { ..._options };
29 | element.addEventListener(event, cb, options);
30 |
31 | return () => element.removeEventListener(event, cb, options);
32 | }
33 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Placeholder/README.md:
--------------------------------------------------------------------------------
1 | # Placeholder
2 |
3 | `Placeholder` используется для каких-либо заглушек: например, в случае отсутствия элементов в списке или ошибки.
4 |
5 | - В качестве иконки желательно использовать аутлайновые иконки размера 56;
6 | - В качестве действия — большую кнопку с уровнем `primary` или `tertiary`.
7 |
8 | Если плейсхолдер используется со свойством `stretched` (показывается во всю высоту панели), то на экране не должно быть ничего другого.
9 |
10 | ```svelte scroll
11 |
16 |
17 |
18 |
19 |
20 | Подключить сообщества
21 | Подключите сообщества, от которых Вы хотите получать уведомления
22 |
23 |
24 |
25 |
26 | Введите адрес страницы в поле поиска
27 |
28 |
29 | ```
30 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/Input/README.md:
--------------------------------------------------------------------------------
1 | # Input
2 |
3 | Надстройка над ` `. Компонент принимает все валидные для этого элемента свойства.
4 |
5 | ## Пример
6 |
7 | ```svelte scroll
8 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | (value = '')}
36 | >
37 |
38 |
39 |
40 |
41 |
42 | ```
43 |
--------------------------------------------------------------------------------
/src/site/lib/Icon28TokenizedOutline/Icon28TokenizedOutline.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
26 |
27 |
36 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/CustomSelectOption/README.md:
--------------------------------------------------------------------------------
1 | # CustomSelectOption
2 |
3 | Универсальный компонент для отрисовки option в кастомных селектах. Используется внутри CustomSelect, ChipsSelect.
4 |
5 | ## Пример
6 |
7 | ```svelte mini
8 |
11 |
12 |
13 |
14 | Дмитрий Безуглый
15 |
16 |
17 |
21 | Вадим Дорохов
22 |
23 |
24 |
25 |
26 | Иван Барышев
27 |
28 |
29 |
30 | Владимир Клепов
31 |
32 |
33 |
Игорь Федоров
34 |
35 | ```
36 |
--------------------------------------------------------------------------------
/src/lib/components/Popouts/ScreenSpinner/README.md:
--------------------------------------------------------------------------------
1 | # ScreenSpinner
2 |
3 | Компонент-обертка над Spinner.
4 |
5 | Передаётся в качестве слота `popout` компонента `SplitLayout`.
6 |
7 | Рекомендуется использовать в случаях, когда требуется заблокировать интерфейс до завершения асинхронного процесса.
8 |
9 | ```svelte frame noLayout
10 |
32 |
33 |
34 |
35 |
36 | {#if popout === 'ScreenSpinner'}
37 |
38 | {/if}
39 |
40 |
41 |
42 |
43 | ScreenSpinner
44 |
45 | Запустить долгий процесс
46 |
47 |
48 |
49 |
50 |
51 | ```
52 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/FormLayout/FormLayout.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
16 |
17 |
23 |
24 |
25 |
26 | {#if Element === 'form'}
27 |
28 | {/if}
29 |
30 |
31 |
49 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeaderEdit/PanelHeaderEdit.svelte:
--------------------------------------------------------------------------------
1 |
25 |
26 |
32 | {#if isActive}
33 |
34 | {:else}
35 |
36 | {/if}
37 |
38 |
--------------------------------------------------------------------------------
/src/lib/lib/accessibility.ts:
--------------------------------------------------------------------------------
1 | export const FOCUSABLE_ELEMENTS_LIST = [
2 | 'a[href]',
3 | 'area[href]',
4 | 'input:not([disabled]):not([hidden]):not([type="hidden"]):not([aria-hidden])',
5 | 'select:not([disabled]):not([hidden]):not([aria-hidden])',
6 | 'textarea:not([disabled])',
7 | 'button:not([disabled])',
8 | 'iframe',
9 | 'audio',
10 | 'video',
11 | '[contenteditable]',
12 | '[tabindex]:not([tabindex="-1"])'
13 | ];
14 |
15 | export enum Keys {
16 | ENTER = 'Enter',
17 | SPACE = 'Space',
18 | TAB = 'Tab',
19 | ESCAPE = 'Escape'
20 | }
21 |
22 | interface AccessibleKey {
23 | code: Keys;
24 | key: string[];
25 | keyCode: number;
26 | }
27 |
28 | const ACCESSIBLE_KEYS: AccessibleKey[] = [
29 | {
30 | code: Keys.ENTER,
31 | key: ['Enter'],
32 | keyCode: 13
33 | },
34 | {
35 | code: Keys.SPACE,
36 | key: ['Space', 'Spacebar', ' '],
37 | keyCode: 32
38 | },
39 | {
40 | code: Keys.TAB,
41 | key: ['Tab'],
42 | keyCode: 9
43 | },
44 | {
45 | code: Keys.ESCAPE,
46 | key: ['Escape'],
47 | keyCode: 27
48 | }
49 | ];
50 |
51 | export function pressedKey(e: KeyboardEvent) {
52 | return (
53 | ACCESSIBLE_KEYS.find(({ key, keyCode }) => key.includes(e.key) || keyCode === e.keyCode)
54 | ?.code || null
55 | );
56 | }
57 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Progress/Progress.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
17 |
18 |
29 |
30 |
44 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Header/HeaderContent.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 | {#if platform === Platform.IOS}
13 | {#if mode === 'primary' || mode === 'tertiary'}
14 |
15 | {:else if mode === 'secondary'}
16 |
17 | {/if}
18 | {:else if platform === Platform.VKCOM}
19 | {#if mode === 'primary'}
20 |
21 | {:else if mode === 'secondary' || mode === 'tertiary'}
22 |
23 | {/if}
24 | {:else if mode === 'primary' || mode === 'tertiary'}
25 |
26 | {:else if mode === 'secondary'}
27 |
28 | {/if}
29 |
--------------------------------------------------------------------------------
/src/lib/helpers/math.ts:
--------------------------------------------------------------------------------
1 | export const clamp = (value: number, min: number, max: number) =>
2 | Math.max(min, Math.min(value, max));
3 |
4 | export function precisionRound(number: number, precision = 1) {
5 | const factor = Math.pow(10, precision);
6 | return Math.round(number * factor) / factor;
7 | }
8 |
9 | function precision(number: number) {
10 | return (`${number}`.split('.')[1] || '').length;
11 | }
12 |
13 | function decimatedClamp(val: number, min: number, max: number, step?: number) {
14 | if (step == null || step <= 0) {
15 | return clamp(val, min, max);
16 | }
17 | const prec = precision(step);
18 | // Round value to nearest min + k1 * step
19 | const decimatedOffset = precisionRound(Math.round((val - min) / step) * step, prec);
20 | // Round range length _down_ to nearest min + k2 * step
21 | const decimatedRange = precisionRound(Math.floor((max - min) / step) * step, prec);
22 | return min + clamp(decimatedOffset, 0, decimatedRange);
23 | }
24 |
25 | export function rescale(
26 | value: number,
27 | from: [number, number],
28 | to: [number, number],
29 | options: { step?: number } = {}
30 | ) {
31 | const scaled = ((value - from[0]) / (from[1] - from[0])) * (to[1] - to[0]) + to[0];
32 | return decimatedClamp(scaled, to[0], to[1], options.step);
33 | }
34 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Separator/README.md:
--------------------------------------------------------------------------------
1 | # Separator
2 |
3 | > **Важно**
4 | >
5 | > Компонент устарел. Предпочтительнее использовать компонент `Spacing`
6 |
7 | Используется для разделения какого-либо контента. Отступы справа и слева контролируются свойством `wide`.
8 |
9 | ## Пример
10 |
11 | ```svelte scroll
12 |
19 |
20 |
21 |
22 |
23 |
24 | Номер телефона
25 |
26 |
27 |
28 | Не беспокоить
29 |
30 |
31 |
32 |
33 |
34 |
35 | Учётная запись
36 |
37 |
38 |
39 | Основные
40 |
41 |
42 | ```
43 |
--------------------------------------------------------------------------------
/src/lib/components/Typography/Text/Text.svelte:
--------------------------------------------------------------------------------
1 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
53 |
--------------------------------------------------------------------------------
/src/lib/components/Typography/Subhead/Subhead.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
22 |
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VKSUI
2 |
3 | [![NPM][npm]][npm-url]
4 | [![VK chat][chat]][chat-url]
5 | [![svelte-v3][svelte]][svelte-url]
6 |
7 | VKSUI — это библиотека адаптивных Svelte-компонентов. С ее помощью вы сможете
8 | создавать веб-приложения и
9 | [VK Mini Apps](https://vk.com/miniapps) в экосистеме [ВКонтакте](https://vk.com).
10 |
11 | Библиотека основана на [VKUI](https://vkcom.github.io/VKUI/) с использованием
12 | [Svelte](https://svelte.dev/).
13 |
14 | ## ВНИМАНИЕ
15 |
16 | Данная библиотека в процессе разработки
17 |
18 | ## Документация
19 |
20 | Смотри [сайт][site-url]
21 |
22 | [npm]: https://img.shields.io/npm/v/@sveltevk/vksui.svg?color=blue
23 | [npm-url]: https://npmjs.com/package/@sveltevk/vksui
24 | [chat]: https://img.shields.io/badge/VK%20chat-%234a76a8.svg?logo=VK&logoColor=white
25 | [chat-url]: https://vk.me/join/AJQ1d3IXhxgxghIc5PFNiLCd
26 | [svelte]: https://img.shields.io/badge/svelte-v3-blueviolet.svg
27 | [svelte-url]: https://svelte.dev
28 | [license]: https://img.shields.io/github/license/sveltevk/VKSUI
29 | [license-url]: https://github.com/sveltevk/VKSUI/blob/master/LICENSE
30 | [site-url]: https://sveltevk.github.io/VKSUI/
31 | [changelog-url]: https://github.com/sveltevk/VKSUI/releases
32 | [github-url]: https://github.com/sveltevk/VKSUI
33 | [repl]: https://img.shields.io/badge/svelte-REPL-red?logoColor=white&style=flat-square
34 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Cell/CellDragger.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 | dispatch('dragStart', e.detail)}
24 | on:moveY={(e) => dispatch('dragMove', e.detail)}
25 | on:end={(e) => dispatch('dragEnd', e.detail)}
26 | on:click={(e) => e.detail.preventDefault()}
27 | >
28 | {#if $platform === IOS}
29 |
30 | {:else}
31 |
32 | {/if}
33 |
34 |
35 |
41 |
--------------------------------------------------------------------------------
/src/lib/lib/browser.ts:
--------------------------------------------------------------------------------
1 | import { IOS, Platform, platform } from './platform';
2 | import type { Version } from '../types';
3 |
4 | export interface BrowserInfo {
5 | userAgent: string;
6 | platform: Platform;
7 | platformVersion: Version | null;
8 | }
9 |
10 | const memoized: { [index: string]: BrowserInfo } = {};
11 |
12 | export function computeBrowserInfo(userAgent: string): BrowserInfo {
13 | if (memoized[userAgent]) {
14 | return memoized[userAgent];
15 | }
16 |
17 | const platformName = platform(userAgent);
18 |
19 | let platformVersion: Version | null = null;
20 |
21 | if (platformName === IOS) {
22 | platformVersion = parseiOSVersion(userAgent);
23 | }
24 |
25 | const browserInfo: BrowserInfo = {
26 | userAgent,
27 | platform: platformName,
28 | platformVersion
29 | };
30 |
31 | memoized[userAgent] = browserInfo;
32 |
33 | return browserInfo;
34 | }
35 |
36 | export function parseiOSVersion(userAgent: string): Version | null {
37 | if (!userAgent) {
38 | return null;
39 | }
40 |
41 | const match = userAgent.match(/(iphone os|cpu os|ios) \b([0-9]+_[0-9]+(?:_[0-9]+)?)\b/i);
42 | if (!match) {
43 | return null;
44 | }
45 |
46 | const [major, minor, patch] = match[2].replace(/_/g, '.').split('.');
47 |
48 | return {
49 | major: parseInt(major) || 0,
50 | minor: parseInt(minor) || 0,
51 | patch: parseInt(patch) || 0
52 | };
53 | }
54 |
--------------------------------------------------------------------------------
/src/site/lib/Sidebar/Sidebar.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 | {#each tree as group}
19 |
20 | {#if group.header}
21 |
22 | {/if}
23 | {#if group.header === 'Компоненты'}
24 |
25 | {/if}
26 | {#each group.child as el}
27 |
32 |
33 | {#if el.tokenized}
34 |
35 | {/if}
36 |
37 | {el.name}
38 |
39 | {/each}
40 |
41 | {/each}
42 |
43 |
48 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Gradient/README.md:
--------------------------------------------------------------------------------
1 | # Gradient
2 |
3 | ## Пример
4 |
5 | ```svelte scroll
6 |
21 |
22 |
23 |
24 |
25 | Алексей Мазелюк
26 | Учащийся
27 | Редактировать
28 |
29 |
30 | Учебные заведения и классы
31 |
32 |
33 | Школа №180
34 |
35 |
36 |
37 | Добавить учебное заведение
38 |
39 |
40 |
41 |
42 |
52 | ```
53 |
--------------------------------------------------------------------------------
/src/lib/components/Popouts/Alert/AlertAction.svelte:
--------------------------------------------------------------------------------
1 |
27 |
28 | {#if platform === IOS}
29 |
36 |
37 |
38 | {:else}
39 |
48 |
49 |
50 | {/if}
51 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/InfoRow/InfoRow.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
18 |
19 |
24 | {#if $$slots.header || header}
25 |
28 | {/if}
29 |
30 |
31 |
32 |
48 |
--------------------------------------------------------------------------------
/svelte.config.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import adapter from '@sveltejs/adapter-static';
3 | import preprocess from 'svelte-preprocess';
4 |
5 | import a11yEmoji from '@fec/remark-a11y-emoji';
6 | import slug from 'rehype-slug';
7 | import github from 'remark-github';
8 | import remarkExample from './remark-example.js';
9 |
10 | import sveld from 'vite-plugin-sveld';
11 |
12 | import { mdsvex } from 'mdsvex';
13 |
14 | const dev = process.env.NODE_ENV === 'development';
15 |
16 | /** @type {import('@sveltejs/kit').Config} */
17 | const config = {
18 | extensions: ['.svelte', '.md', '.svx'],
19 | preprocess: [
20 | mdsvex({
21 | extensions: ['.svx', '.md'],
22 | remarkPlugins: [remarkExample, github, a11yEmoji],
23 | rehypePlugins: [slug]
24 | }),
25 | preprocess()
26 | ],
27 |
28 | kit: {
29 | adapter: adapter(),
30 | paths: {
31 | base: dev ? '' : '/VKSUI'
32 | },
33 | vite: {
34 | define: {
35 | __version__: JSON.stringify(process.env.npm_package_version)
36 | },
37 | optimizeDeps: {
38 | include: [
39 | 'svg-baker-runtime/browser-sprite.js',
40 | 'svg-baker-runtime/browser-symbol.js',
41 | '@fontsource/jetbrains-mono'
42 | ]
43 | },
44 | plugins: [sveld()],
45 | resolve: {
46 | extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', 'svg'],
47 | alias: {
48 | $site: path.resolve('src/site'),
49 | '@sveltevk/vksui': path.resolve('src/lib')
50 | }
51 | }
52 | }
53 | }
54 | };
55 |
56 | export default config;
57 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeaderButton/README.md:
--------------------------------------------------------------------------------
1 | # PanelHeaderButton
2 |
3 | Компонент для отрисовки кнопок в шапке панели. Внутрь компонента передается либо [иконка](https://sveltevk.github.io/icons/), либо текст. Текстовые кнопки чаще всего используются в iOS, но есть исключения для Android.
4 |
5 | Кнопки могут быть переданы в `left` или `right` компонента PanelHeader
6 |
7 | ```svelte frame mini
8 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ```
23 |
24 | Если нужно несколько кнопок справа или слева, то используем `svelte:fragment`:
25 |
26 | ```svelte mini
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | ```
38 |
39 | ## VK Mini Apps
40 |
41 | Если вы разрабатываете приложение на платформе [VK Mini Apps](https://vk.com/vkappsdev), то вам будут недоступны кнопки справа, так как на их месте отображаются нативные кнопки для управления приложением.
42 |
--------------------------------------------------------------------------------
/src/lib/hooks/useKeyboardInputTracker.ts:
--------------------------------------------------------------------------------
1 | import { get, writable, type Writable } from 'svelte/store';
2 | import { Keys, pressedKey } from '../lib/accessibility';
3 | import { useDOM } from '../lib/dom';
4 | import { useGlobalEventListener } from './useGlobalEventListener';
5 |
6 | export const ENABLE_KEYBOARD_INPUT_EVENT_NAME = 'enableKeyboardInput';
7 | export const DISABLE_KEYBOARD_INPUT_EVENT_NAME = 'disableKeyboardInput';
8 |
9 | export function useKeyboardInputTracker(): Writable {
10 | const dom = useDOM();
11 |
12 | const isKeyboardInputActive = writable(false);
13 |
14 | const enableKeyboardInput = () => isKeyboardInputActive.set(true);
15 |
16 | const handleKeydown = (e: KeyboardEvent) => {
17 | if (pressedKey(e) === Keys.TAB) {
18 | enableKeyboardInput();
19 | }
20 | };
21 |
22 | const disableKeyboardInput = () => isKeyboardInputActive.set(false);
23 |
24 | const eventOptions = {
25 | passive: true,
26 | capture: true
27 | };
28 |
29 | useGlobalEventListener(get(dom).document, 'keydown', handleKeydown, eventOptions);
30 | useGlobalEventListener(get(dom).document, 'mousedown', disableKeyboardInput, eventOptions);
31 | useGlobalEventListener(get(dom).document, 'touchstart', disableKeyboardInput, eventOptions);
32 | useGlobalEventListener(
33 | get(dom).document,
34 | ENABLE_KEYBOARD_INPUT_EVENT_NAME,
35 | enableKeyboardInput,
36 | eventOptions
37 | );
38 | useGlobalEventListener(
39 | get(dom).document,
40 | DISABLE_KEYBOARD_INPUT_EVENT_NAME,
41 | disableKeyboardInput,
42 | eventOptions
43 | );
44 |
45 | return isKeyboardInputActive;
46 | }
47 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/CellButton/README.md:
--------------------------------------------------------------------------------
1 | # CellButton
2 |
3 | ```svelte scroll
4 |
10 |
11 |
12 |
13 | Добавить новую школу
14 | Удалить беседу
15 |
16 |
17 |
18 |
19 |
20 | Добавить родственника
21 |
22 |
23 |
24 | Удалить беседу
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | Добавить участников
34 |
35 |
36 |
37 |
38 |
39 | Создать беседу
40 |
41 |
42 |
43 |
44 |
45 | Создать плейлист
46 |
47 |
48 |
49 |
50 |
51 |
52 | Создать беседу
53 |
54 |
55 | ```
56 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Badge/README.md:
--------------------------------------------------------------------------------
1 | # Badge
2 |
3 | Индикатор, с помощью которого можно привлечь внимание пользователя к определенному разделу.
4 |
5 | ```svelte frame
6 |
19 |
20 |
21 | Бейдж
22 |
23 |
24 |
25 |
26 |
27 | Уведомления
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | Диалоги
37 |
38 |
39 |
40 | Сообщения
41 |
42 |
43 |
44 |
45 | ```
46 |
47 |
64 |
--------------------------------------------------------------------------------
/src/lib/lib/touch.ts:
--------------------------------------------------------------------------------
1 | export interface VKUITouchEvent extends MouseEvent, TouchEvent {}
2 | export type VKUITouchEventHander = (e: VKUITouchEvent) => void;
3 |
4 | /*
5 | * Получает координату по оси абсцисс из touch- или mouse-события
6 | */
7 | const coordX = (e: VKUITouchEvent): number =>
8 | e.clientX || (e.changedTouches && e.changedTouches[0].clientX);
9 |
10 | /*
11 | * Получает координату по оси ординат из touch- или mouse-события
12 | */
13 | const coordY = (e: VKUITouchEvent): number =>
14 | e.clientY || (e.changedTouches && e.changedTouches[0].clientY);
15 |
16 | const isClient: boolean = typeof window !== 'undefined';
17 | const touchEnabled: boolean = isClient && 'ontouchstart' in window;
18 |
19 | /*
20 | * Возвращает массив поддерживаемых событий
21 | * Если браузер поддерживает pointer events или подключена handjs, вернет события указателя.
22 | * Если нет, используем события мыши
23 | */
24 | function getSupportedEvents(): string[] {
25 | if (touchEnabled) {
26 | return ['touchstart', 'touchmove', 'touchend', 'touchcancel'];
27 | }
28 |
29 | return ['mousedown', 'mousemove', 'mouseup', 'mouseleave'];
30 | }
31 |
32 | /*
33 | * Рассчитывает "сопротивление" для iOS тач-событий
34 | */
35 | function rubber(
36 | offset: number,
37 | dimension: number,
38 | resistanceRate: number,
39 | isAndroid: boolean
40 | ): number {
41 | if (isAndroid || offset < 0) {
42 | return offset;
43 | }
44 |
45 | const offsettedResistance = offset * resistanceRate;
46 | return (offsettedResistance * dimension) / (offsettedResistance + dimension);
47 | }
48 |
49 | export { getSupportedEvents, coordX, coordY, touchEnabled, rubber };
50 |
--------------------------------------------------------------------------------
/src/lib/components/Modals/ModalDismissButton/ModalDismissButton.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
18 |
19 |
20 |
21 |
60 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/File/File.svelte:
--------------------------------------------------------------------------------
1 |
27 |
28 |
33 |
34 |
47 |
48 |
49 |
50 | Выберите файл
51 |
52 |
53 |
58 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Search/README.md:
--------------------------------------------------------------------------------
1 | # Search
2 |
3 | Надстройка над ` `. Компонент принимает все валидные для этого элемента свойства.
4 |
5 | ## Пример
6 |
7 | ```svelte scroll
8 |
41 |
42 |
43 |
44 | {#each searchThemes as theme}
45 | {theme.name}
46 | {:else}
47 |
48 | {/each}
49 |
50 | ```
51 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/CardScroll/CardScroll.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 |
14 |
15 |
22 |
23 |
73 |
--------------------------------------------------------------------------------
/src/lib/helpers/scheme.ts:
--------------------------------------------------------------------------------
1 | import type { AppearanceSchemeType, AppearanceType } from '@vkontakte/vk-bridge';
2 | import { getScheme } from './getScheme';
3 | import { VKCOM } from '../lib/platform';
4 | import type { PlatformType } from '../lib/platform';
5 |
6 | export enum Scheme {
7 | /**
8 | * @deprecated будет удалено в 5.0.0
9 | * версия оставлена для совместимости со старыми версиями клиентов
10 | */
11 | DEPRECATED_CLIENT_LIGHT = 'client_light',
12 | /**
13 | * @deprecated будет удалено в 5.0.0
14 | * версия оставлена для совместимости со старыми версиями клиентов
15 | */
16 | DEPRECATED_CLIENT_DARK = 'client_dark',
17 | /**
18 | * @deprecated будет удалено в 5.0.0
19 | * версия оставлена для совместимости с vkcom, когда там была только одна схема
20 | */
21 | VKCOM = 'vkcom',
22 |
23 | BRIGHT_LIGHT = 'bright_light',
24 | SPACE_GRAY = 'space_gray',
25 | VKCOM_LIGHT = 'vkcom_light',
26 | VKCOM_DARK = 'vkcom_dark'
27 | }
28 |
29 | export type AppearanceScheme =
30 | | AppearanceSchemeType
31 | | Scheme.VKCOM
32 | | Scheme.VKCOM_DARK
33 | | Scheme.VKCOM_LIGHT
34 | | 'inherit';
35 |
36 | export interface NormalizeSchemeProps {
37 | platform: PlatformType;
38 | scheme?: AppearanceScheme;
39 | appearance?: AppearanceType;
40 | }
41 |
42 | export function normalizeScheme({
43 | platform,
44 | scheme,
45 | appearance
46 | }: NormalizeSchemeProps): Scheme | 'inherit' {
47 | if (appearance) {
48 | return getScheme({ platform, appearance });
49 | }
50 |
51 | if (scheme === 'inherit') {
52 | return scheme;
53 | }
54 |
55 | if (platform === VKCOM && (scheme === Scheme.BRIGHT_LIGHT || scheme === Scheme.SPACE_GRAY)) {
56 | return Scheme.VKCOM_LIGHT;
57 | }
58 |
59 | return scheme as Scheme;
60 | }
61 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/PanelHeaderBack/PanelHeaderBack.svelte:
--------------------------------------------------------------------------------
1 |
21 |
22 |
34 |
35 |
44 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/ModalCardBase/README.md:
--------------------------------------------------------------------------------
1 | # ModalCardBase
2 |
3 | Низкоуровневый компонент для отрисовки карточки со сложным содержимым. Используется внутри ModalCard.
4 |
5 | **Кнопка для закрытия**
6 |
7 | Согласно дизайн-гайдам, в Android-версии специальной кнопки для закрытия не предусмотрено.
8 |
9 | ## Пример
10 |
11 | ```svelte mini
12 |
24 |
25 |
26 |
Десктопная и планшетная версии
27 |
32 | Попробовать
33 |
34 |
35 |
Мобильная версия
36 |
37 |
42 |
43 | Добавить в меню
44 |
45 |
46 |
47 | ```
48 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/RichCell/README.md:
--------------------------------------------------------------------------------
1 | # RichCell
2 |
3 | ## Пример
4 |
5 | ```svelte scroll
6 |
12 |
13 |
14 |
15 |
16 |
17 | Принять
18 | Отклонить
19 |
20 | Тарас Иванов
21 |
22 |
23 |
24 |
25 |
33 | 73 общих друга
34 |
35 |
36 | Добавить
37 | Скрыть
38 |
39 | Илья Гришин
40 |
41 |
42 |
43 | Михаил Лихачев
44 |
45 |
46 |
47 | Тимофей Чаптыков
48 |
49 |
50 | ```
51 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/SplitCol/SplitCol.svelte:
--------------------------------------------------------------------------------
1 |
25 |
26 |
37 |
38 | {#if fixed}
39 |
40 | {:else}
41 |
42 | {/if}
43 |
44 |
45 |
46 |
76 |
--------------------------------------------------------------------------------
/remark-example.js:
--------------------------------------------------------------------------------
1 | import { visit, SKIP } from 'unist-util-visit';
2 |
3 | const reScript = /(.*?)<\/script>/s;
4 | // const reStyle = /.*?<\/style>/s;
5 |
6 | export default function exampleCode() {
7 | return (tree) => {
8 | let isScript = false;
9 | let script = `import Showcase from '$site/lib/Showcase/Showcase.svelte'\n`;
10 | // TODO: Обрабатывать стили
11 |
12 | visit(tree, (node, index, parent) => {
13 | // TODO: находить уже существующий `
40 | };
41 | if (isScript) {
42 | parent.children[0] = scriptNode;
43 | } else {
44 | parent.children.splice(0, 0, scriptNode);
45 | isScript = true;
46 | skipCount++;
47 | }
48 |
49 | // CODE
50 | let code = [
51 | !isScript ? script : '',
52 | '',
53 | thisCode.trim(),
54 | ' '
55 | ].join('\n');
56 |
57 | parent.children.splice(index + skipCount - index, 0, {
58 | type: 'html',
59 | value: code
60 | });
61 | skipCount++;
62 |
63 | // HEADER
64 | parent.children.splice(index + skipCount - index, 0, {
65 | type: 'heading',
66 | depth: 2,
67 | children: [{ type: 'text', value: 'Код' }]
68 | });
69 | skipCount++;
70 |
71 | return [SKIP, skipCount + 1];
72 | });
73 | };
74 | }
75 |
--------------------------------------------------------------------------------
/src/lib/styles/constants.css:
--------------------------------------------------------------------------------
1 | :root {
2 | /* fonts */
3 | --font-common: -apple-system, system-ui, Helvetica Neue, Roboto, sans-serif;
4 | --font-display: 'VK Sans Display', -apple-system, system-ui, Helvetica Neue, Roboto, sans-serif;
5 |
6 | /* easings */
7 | --ios-easing: cubic-bezier(0.36, 0.66, 0.04, 1);
8 | --android-easing: cubic-bezier(0.4, 0, 0.2, 1);
9 |
10 | /* sizes */
11 | --tabbar_height: 48px;
12 | --panelheader_height_ios: 52px;
13 | --panelheader_height_android: 56px;
14 | --panelheader_height_vkcom: 48px;
15 | --modalheader_height_ios: 52px;
16 | --modalheader_height_android: 56px;
17 | --search_default_height: 36px;
18 | --thin-border: 1px;
19 |
20 | /* paddings */
21 | --formitem_padding: 16px;
22 |
23 | /* colors */
24 | --white: #fff;
25 | --blue_200: #5c9ce6;
26 |
27 | /* iOS insets */
28 | --safe-area-inset-top: 20px;
29 | --safe-area-inset-right: 0px;
30 | --safe-area-inset-bottom: 0px;
31 | --safe-area-inset-left: 0px;
32 |
33 | /* animations */
34 | --duration: 0.7s;
35 | }
36 |
37 | @media (min-resolution: 2dppx) {
38 | :root {
39 | --thin-border: 0.5px;
40 | }
41 | }
42 |
43 | @media (min-resolution: 3dppx) {
44 | :root {
45 | --thin-border: 0.33px;
46 | }
47 | }
48 |
49 | @supports (padding-top: constant(safe-area-inset-top)) {
50 | :root {
51 | --safe-area-inset-top: constant(safe-area-inset-top);
52 | --safe-area-inset-right: constant(safe-area-inset-right);
53 | --safe-area-inset-bottom: constant(safe-area-inset-bottom);
54 | --safe-area-inset-left: constant(safe-area-inset-left);
55 | }
56 | }
57 |
58 | @supports (padding-top: env(safe-area-inset-top)) {
59 | :root {
60 | --safe-area-inset-top: env(safe-area-inset-top);
61 | --safe-area-inset-right: env(safe-area-inset-right);
62 | --safe-area-inset-bottom: env(safe-area-inset-bottom);
63 | --safe-area-inset-left: env(safe-area-inset-left);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/lib/components/Popouts/ScreenSpinner/ScreenSpinner.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
63 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Spinner/Spinner.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
19 |
20 |
21 | {#if size === 'large'}
22 |
23 | {:else if size === 'medium'}
24 |
25 | {:else if size === 'small'}
26 |
27 | {:else}
28 |
29 | {/if}
30 |
31 |
32 |
67 |
--------------------------------------------------------------------------------
/src/lib/components/Typography/Headline/Headline.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
23 |
24 |
64 |
--------------------------------------------------------------------------------
/src/lib/components/Service/AppearanceProvider/AppearanceProvider.svelte:
--------------------------------------------------------------------------------
1 |
30 |
31 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/routes/modes.md:
--------------------------------------------------------------------------------
1 | # Режимы подключения
2 |
3 | Библиотека VKSUI поддерживает 3 режима подключения:
4 |
5 | - Full — ваше приложение полностью реализовано с помощью данной библиотеки и контролируется VKSUI.
6 | - Embedded — ваше приложение будет реализовано в виде блока, встроенного в основное приложение (например, Марусю или базовое приложение ВКонтакте).
7 | - Partial — ваше приложение реализовано с помощью сторонних решений и использует некоторые компоненты библиотеки VKSUI.
8 |
9 | Режим выставляется в компоненте `AppRoot` с помощью свойства `mode`. Любое приложение должно быть обёрнуто в этот компонент.
10 |
11 | ## Full
12 |
13 | Данный режим позволяет VKSUI полностью контролировать страницы вашего приложения.
14 | В этом случае root-элемент должен находиться непосредственно внутри ``.
15 | Режим full включен по умолчанию. Его рекомендуется использовать для [VK Mini Apps](https://vk.com/miniapps) и standalone проектов.
16 |
17 | > **Важно**
18 | >
19 | > При работе с SSR нужно изначально добавить классы vkui в теги html и vkui\_\_root корневого контейнера, чтобы избежать изменений стилей после гидратации.
20 |
21 | ## Embedded
22 |
23 | Данный режим позволяет вам подключить VKSUI не на всю страницу приложения, а только к определенному контейнеру.
24 | Как и с full режимом, VKSUI добавит свои классы в корневой контейнер.
25 |
26 | ## Partial
27 |
28 | Данный режим подходит для случаев, когда вам нужно сверстать небольшой блок, а не страницу целиком. В partial режиме не
29 | подразумевается использование компонентов из раздела Layout. Чтобы подключить VKSUI в этом режиме, необходимо вручную
30 | добавить класс `.vkui__root` на выбранный контейнер, а потом использовать VKSUI компоненты внутри него.
31 |
32 | ```html
33 |
34 | ...
35 |
36 |
37 | ...
38 |
39 | ...
40 |
41 | ...
42 |
43 | ...
44 |
45 |
46 |
47 | ```
48 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Button/ButtonTypography.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 | {#if size === 'l'}
18 | {#if isCompact}
19 |
20 |
21 |
22 | {:else if platform === ANDROID}
23 |
24 |
25 |
26 | {:else}
27 |
28 |
29 |
30 | {/if}
31 | {:else if size === 'm'}
32 | {#if isCompact}
33 |
34 |
35 |
36 | {:else}
37 |
38 |
39 |
40 | {/if}
41 | {:else if size === 's'}
42 | {#if platform === IOS}
43 |
44 |
45 |
46 | {:else if platform === VKCOM}
47 |
48 |
49 |
50 | {:else if isCompact}
51 |
52 |
53 |
54 | {:else}
55 |
56 |
57 |
58 | {/if}
59 | {/if}
60 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Cell/CellCheckbox.svelte:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
31 | {#if $platform === ANDROID}
32 |
33 | {:else}
34 |
35 | {/if}
36 | {#if $platform === ANDROID}
37 |
38 | {:else}
39 |
40 | {/if}
41 |
42 |
43 |
62 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/MiniInfoCell/README.md:
--------------------------------------------------------------------------------
1 | # MiniInfoCell
2 |
3 | ## Пример
4 |
5 | ```svelte scroll
6 |
16 |
17 |
18 |
19 |
20 | ВКонтакте начинался как сайт для выпускников вузов, а сейчас это огромная экосистема с
21 | безграничными возможностями и миллионами пользователей.
22 |
23 |
24 |
25 |
26 |
30 | 514,7K подписчиков · 77 друзей
31 |
32 |
33 |
34 |
35 | vk.com/team
36 |
37 |
38 |
39 |
40 |
45 | Место работы: Команда ВКонтакте
46 |
47 |
48 | console.log('Указать место учёбы')}>
49 |
50 | Укажите место учёбы
51 |
52 |
53 | console.log('Подробная информация')}>
54 |
55 | Подробная информация
56 |
57 |
58 | ```
59 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Separator/Separator.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
19 |
20 |
29 |
30 |
80 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/Tabbar/Tabbar.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
28 |
29 |
84 |
--------------------------------------------------------------------------------
/src/site/lib/Sidebar/Group.svelte:
--------------------------------------------------------------------------------
1 |
40 |
41 | {#if child.length > 0 || !(expand || search !== '')}
42 | (expand = !expand)}>
43 | {group.header}
44 |
45 | {#if expand || search !== ''}
46 |
47 | {:else}
48 |
49 | {/if}
50 |
51 |
52 |
53 | {#each child as el}
54 |
59 |
60 | {#if el.tokenized}
61 |
62 | {/if}
63 |
64 | {el.name}
65 |
66 | {/each}
67 |
68 | {/if}
69 |
70 |
75 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/AppRoot/ScrollContext.svelte:
--------------------------------------------------------------------------------
1 |
48 |
49 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Removable/RemovableIos.svelte:
--------------------------------------------------------------------------------
1 |
40 |
41 |
46 | 0}
53 | >
54 |
55 |
56 |
57 |
58 |
59 |
60 |
69 |
70 | {removePlaceholder}
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/CellButton/CellButton.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
29 |
30 | {#if before}{before}{/if}
31 |
32 |
33 |
34 |
35 |
83 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/FormItem/README.md:
--------------------------------------------------------------------------------
1 | # FormItem
2 |
3 | Базовый компонент формы. В него нужно оборачивать все поля, из которых конструируется форма. Исключения составляют поля-ячейки (`Radio`, `Checkbox`, etc.), если в дизайне для них не предусмотрены `top` и `bottom`. Такие поля можно располагать в форме без оборачивания в `FormItem`.
4 |
5 | ```svelte scroll
6 |
22 |
23 |
24 | {
26 | e.preventDefault();
27 | }}
28 | >
29 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | {#if showPatronymic}
55 | (showPatronymic = false)}
58 | top="Отчество"
59 | bottom="Если у вас нет отчества — удалите этот пункт."
60 | >
61 |
62 |
63 | {:else}
64 | (showPatronymic = true)}>Указать отчество
65 | {/if}
66 |
67 | Согласен со всем этим
68 |
69 |
70 | Зарегистрироваться
71 |
72 |
73 |
74 | ```
75 |
--------------------------------------------------------------------------------
/src/lib/components/Blocks/Spacing/Spacing.svelte:
--------------------------------------------------------------------------------
1 |
22 |
23 |
34 |
35 |
83 |
--------------------------------------------------------------------------------
/src/lib/components/Layout/SplitLayout/SplitLayout.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
26 |
27 |
28 |
29 |
81 |
--------------------------------------------------------------------------------
/src/lib/components/Forms/FormStatus/FormStatus.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
19 |
20 |
24 | {#if $$slots.header || header}
25 |
26 | {/if}
27 | {#if $$slots.default}
28 |
29 | {/if}
30 |
31 |
32 |
68 |
--------------------------------------------------------------------------------